Groupy —
Plateforme de prévente groupée
Application web PHP/MySQL multi-rôles permettant à des vendeurs de proposer des produits en prévente, à des clients d'y participer, et à un gestionnaire de modérer la plateforme.
4
Rôles utilisateurs
~30
Pages PHP
4 mois
Sept – Déc 2025
4 rôles, 4 espaces dédiés
Client
Inscription, parcours d'achat, participation aux préventes, signalements, messagerie, factures PDF.
Vendeur
Catalogue produits (CRUD), création de préventes (date limite, nombre minimum), gestion litiges et messagerie clients.
Gestionnaire
Modération de la plateforme, gestion des catégories produits, blocage/déblocage de vendeurs en cas d'abus.
Admin
Accès super-utilisateur — défini par défaut si l'utilisateur n'est rattaché à aucun autre rôle métier.
Connexion BDD via PDO + protection CSRF
Toutes les requêtes passent par PDO avec prepared statements activés —
aucune concaténation SQL, donc pas de surface d'attaque pour l'injection. Les formulaires
sont protégés par un jeton CSRF généré par random_bytes(32).
includes/config.php// --- CONNEXION SÉCURISÉE À LA BDD --- function connectDB() { $dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4"; try { $pdo = new PDO($dsn, DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // les erreurs lèvent une exception PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // résultats en tableau associatif PDO::ATTR_EMULATE_PREPARES => false, // vraies prepared statements (anti-injection SQL) ]); return $pdo; } catch (PDOException $e) { error_log("[DB] ERREUR : " . $e->getMessage()); return null; } } // --- PROTECTION CSRF --- function generateCSRF() { if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // jeton aléatoire 64 caractères } return $_SESSION['csrf_token']; } function verifyCSRF($token) { return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token); // comparaison résistante aux timing attacks }
Authentification avec BCRYPT & gestion des rôles
Aucun mot de passe n'est stocké en clair : à l'inscription, on hashe avec
password_hash()
+ algorithme BCRYPT. À la connexion, on vérifie avec
password_verify(),
puis on détermine le rôle et on stocke l'utilisateur en session sans le mot de passe.
includes/functions.phpfunction connectUser($email, $motdepasse) { $pdo = connectDB(); if (!$pdo) return false; // Requête préparée → impossible d'injecter du SQL via l'email $stmt = $pdo->prepare("SELECT * FROM Utilisateur WHERE email = ?"); $stmt->execute([$email]); $user = $stmt->fetch(); // Vérification du hash BCRYPT (le hash est dans la BDD, pas le mot de passe) if (!$user || !password_verify($motdepasse, $user['motdepasse'])) { return false; } // Détermination dynamique du rôle selon les tables d'appartenance $role = 'admin'; if ($pdo->prepare("SELECT 1 FROM Vendeur WHERE id_user = ?") ->execute([$user['id_user']]) && /* ... */ ) $role = 'vendeur'; // idem pour Client et Gestionnaire // On retire le hash avant de stocker en session — par sécurité unset($user['motdepasse']); $_SESSION['user'] = $user; $_SESSION['role'] = $role; return $role; } // --- INSCRIPTION : hashage du mot de passe en BCRYPT avant insertion --- $mdp = password_hash($_POST['motdepasse'], PASSWORD_BCRYPT); $stmt = $pdo->prepare( "INSERT INTO Utilisateur (nom, prenom, email, motdepasse) VALUES (?, ?, ?, ?)" ); $stmt->execute([$nom, $prenom, $email, $mdp]);
Contrôle d'accès par rôle
Chaque page sensible vérifie le rôle de l'utilisateur connecté. Une tentative d'accès directe à une URL d'un autre rôle redirige vers la page de connexion.
includes/config.php + functions.phpfunction requireLogin() { if (!isLoggedIn()) { header('Location: /Utilisateur/connexion.php'); exit; } } function isVendeur() { return getUserRole() === 'vendeur'; } function isClient() { return getUserRole() === 'client'; } function isGestionnaire() { return getUserRole() === 'gestionnaire'; } // Exemple d'utilisation en haut d'une page Vendeur requireLogin(); if (!isVendeur()) { header('Location: /index.php'); exit; }
L'application en images
Ce que ce projet m'a apporté
🏗️ Architecture multi-rôles
Conception d'un modèle relationnel avec un utilisateur central et 3 tables de spécialisation (Client / Vendeur / Gestionnaire), pattern réutilisable.
🔐 Sécurité OWASP de base
Mise en pratique des contre-mesures contre injection SQL (PDO), CSRF (jetons), brute-force (BCRYPT) et fixation de session.
🔄 Cycle complet d'application
De l'analyse du besoin à l'hébergement web, en passant par le MCD, le développement, les tests et le déploiement.
👥 Travail en mode projet
Découpage en lots fonctionnels (auth, catalogue, préventes, messagerie, signalements) et suivi de l'avancement sur plusieurs mois.