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.

PHP 8 PDO MySQL HTML / CSS JavaScript CSRF BCRYPT

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

Accueil vendeur Liste produits Liste vendeurs (gestionnaire) Liste préventes Filtres préventes Gestion des litiges

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.