Créa-blog

#100JoursPourCoder
Projet Créa-code

Ressources pour développeur web

Jour 17 : Système pour réinitialiser un mot de passe oublié

Temps de lecture : 21 minutes
Accueil Projets Jour 17 : Système pour réinitialiser un mot de passe oublié

Aujourd’hui, nous allons mettre en place un système complet de réinitialisation de mot de passe pour notre projet Créa-code. Ce système permettra à un utilisateur qui a oublié son mot de passe de recevoir un lien sécurisé par email. En cliquant sur ce lien, il pourra définir un nouveau mot de passe.

Ce processus, que nous voyons tous les jours sur les sites que nous utilisons, peut sembler complexe à première vue. Il implique la vérification d’une adresse email, la génération d’un lien unique, l’envoi d’un mail, la vérification d’un token, la sécurité de la base de données… Mais ne vous inquiétez pas, nous allons avancer pas à pas, en expliquant tout dans un langage simple et accessible. Et toujours en utilisant et en enrichissant notre architecture MVC en PHP.

Comprendre le fonctionnement général

Avant de commencer à coder, visualisons les grandes étapes :

  1. Un utilisateur clique sur “Mot de passe oublié ?” depuis la page de connexion.
  2. Il arrive sur un formulaire lui demandant son adresse email.
  3. Si cet email existe dans la base, un token sécurisé est généré et stocké temporairement dans la base.
  4. Un email contenant un lien unique est envoyé à l’utilisateur.
  5. Ce lien contient le token. Il redirige vers un formulaire où l’utilisateur peut saisir un nouveau mot de passe.
  6. Si le token est valide (et pas expiré), le mot de passe est mis à jour de façon sécurisée.
  7. Le token est ensuite supprimé ou invalidé.

Nous allons maintenant coder tout cela.

Préparer notre architecture MVC

Nous allons suivre l’architecture que nous avons déjà utilisée dans les précédents articles de #100JoursPourCoder. Pour rappel, nous avons un dossier app avec les sous-dossiers suivants :

  • controllers : pour les contrôleurs PHP.
  • models : pour les classes qui accèdent à la base de données.
  • views : pour les fichiers HTML/PHP affichés à l’utilisateur.
  • core : pour les classes de base comme Controller et Model.

Notre système de réinitialisation de mot de passe va se répartir sur plusieurs fichiers :

  • Une vue avec le formulaire de demande de réinitialisation (email).
  • Un contrôleur pour gérer l’envoi du mail et la vérification du lien.
  • Un modèle qui interagit avec la base de données pour stocker le token.
  • Et un second formulaire pour définir un nouveau mot de passe sécurisé.

Créer le formulaire de demande de réinitialisation

Nous commençons par créer une vue simple contenant un champ pour que l’utilisateur entre son email. Cette vue sera affichée à l’adresse suivante :
https://code.crea-troyes.fr/forgot

Création de la route

Nous ajoutons nos deux routes dans le fichier routes.php :

$router->get('/forgot', 'AuthController@forgotForm');
$router->post('/forgot', 'AuthController@handleForgot');

Nous avons donc deux routes :

  • une pour afficher le formulaire (GET),
  • une pour traiter le formulaire (POST).

La vue forgot.php

Créons le fichier views/auth/forgot.php :

<h1>Mot de passe oublié</h1>

<?php $message = $message ?? ""; ?>
<?php if (!empty($error)) echo "<p style='color:red;'>$error</p>"; ?>
<?php if (!empty($message)) echo "<p style='color:green;'>$message</p>"; ?>

<?php if ($message != "Un email de réinitialisation vous a été envoyé avec les instructions à suivre.") : ?>
    <form method="post" action="<?= BASE_URL ?>forgot" id="forgot_form">
        <label for="email">Votre adresse email :</label>
        <input type="email" name="email" id="email" required>
        <button type="submit" id="submit_forgot">Réinitialiser</button>
    </form>

    <script src="<?= BASE_URL ?>assets/js/forgot-password.js" defer></script>
<?php endif; ?>

Ce formulaire est très simple. Il contient un champ email et un bouton. Il affiche aussi un message d’erreur ou de confirmation si besoin.

Ajoutons un script JavaScript à placer dans public/assets/js/forgot-password.js pour améliorer l’expérience utilisateur de notre formulaire « Mot de passe oublié ». Ce script vérifie si l’email a un format valide et, si cet email n’est pas valide, affiche un message d’erreur en dessous du champ si besoin :

document.addEventListener("DOMContentLoaded", () => {
    const form = document.getElementById("forgot_form");
    const emailInput = document.getElementById("email");
    const submitButton = document.getElementById("submit_forgot");

    // Création du message d’erreur
    const errorMsg = document.createElement("p");
    errorMsg.style.color = "red";
    errorMsg.style.fontSize = "0.9em";
    errorMsg.style.marginTop = "5px";
    errorMsg.style.display = "none";
    emailInput.insertAdjacentElement("afterend", errorMsg);

    // Vérification simple de l'email
    const isValidEmail = (email) => {
        const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        return regex.test(email);
    };

    form.addEventListener("submit", (e) => {
        const email = emailInput.value.trim();

        if (!isValidEmail(email)) {
            e.preventDefault(); // Empêche l'envoi du formulaire
            errorMsg.textContent = "Veuillez entrer une adresse email valide.";
            errorMsg.style.display = "block";
        } else {
            errorMsg.style.display = "none"; // Tout va bien, on laisse envoyer
        }
    });
});

Le contrôleur pour afficher ce formulaire

Nous allons créer un contrôleur controllers/AuthController.php et ajouter cette méthode :

<?php
namespace App\Controllers;

use App\Core\Controller;
use App\Core\View;


class AuthController extends Controller
{
    public function forgotForm()
    {
        $title = "Créa-code - Mot de passe oublié ?";
        $desc = "Réinitialisez votre mot de passe en saisissant votre adresse email.";

        //$nombreInscrits = User::count();
        View::render('auth/forgot', compact('title', 'desc'));
    }

}

Elle se contente de charger la vue. Rien de plus. Et enfin, nous relions la page de connexion à la page de ce formulaire en ajoutant le lien suivant dans la vue app/Views/login.php :

<p>
    <a href="<?= BASE_URL ?>forgot">Mot de passe oublié ?</a>
</p>

Traitement du formulaire et génération du token

Quand l’utilisateur soumet le formulaire, nous devons vérifier que l’email existe, puis générer un token de réinitialisation, et le stocker dans la table users avec une date d’expiration.

Ajout dans la base de données

Nous avons déjà dans la table users deux champs utiles :

reset_token VARCHAR(255)
reset_token_expiry DATETIME

C’est parfait. Nous allons les utiliser.

Création du token

Dans le contrôleur AuthController, ajoutons la méthode handleForgot() :

public function handleForgot()
{
    $title = "Créa-code - Mot de passe oublié ?";
    
    $email = trim($_POST['email']);
    $email = strtolower($email);
    $email = filter_var($email, FILTER_VALIDATE_EMAIL) ? $email : '';

    if (empty($email)) {
        $error = "Veuillez entrer votre adresse email.";
        View::render('auth/forgot', compact('title', 'error'));
        return;
    }

    $db = Database::getInstance();

    // Vérifier si l'email existe
    $userModel = new User(Database::getInstance());
    $user = $userModel->findByEmail($email);

    if (!$user) {
        $message = "L'adresse mail est incorrecte.";
        View::render('auth/forgot', compact('title', 'message'));
        return;
    }

    // Générer un token sécurisé
    $token = bin2hex(random_bytes(32));

    // Le token est valide 15 minutes
    $expiry = date('Y-m-d H:i:s', time() + 900);

    // Stocker le token
    $user->setResetToken($email, $token, $expiry);

    // Envoyer le mail
    $this->sendResetEmail($email, $token);

    $message = "Un email de réinitialisation vous a été envoyé avec les instructions à suivre.";
    View::render('auth/forgot', compact('title', 'message'));
}

Explication ligne par ligne

  • On vérifie que l’email est sécurisé.
  • On cherche l’email dans la base.
  • Si l’email n’existe pas, on renvoie une erreur.
  • Si l’email existe, on génère un token avec random_bytes(32) qu’on transforme en chaîne hexadécimale.
  • On fixe une date d’expiration (15 minutes).
  • On met à jour l’utilisateur avec ce token.
  • On envoie un mail via une fonction sendResetEmail (que l’on va bientôt coder).

Mise à jour du modèle User.php

Nous allons mettre à jour le fichier app/Models/User.php en lui ajoutant la méthode setResetToken() :

public function setResetToken($email, $token, $expiry)
{
    $sql = "UPDATE users SET reset_token = :token, reset_token_expiry = :expiry WHERE email = :email";
    $stmt = $this->db->prepare($sql);
    $stmt->bindValue(':token', $token);
    $stmt->bindValue(':expiry', $expiry);
    $stmt->bindValue(':email', $email);
    $stmt->execute();
}

Cette méthode met à jour les colonnes reset_token et reset_token_expiry pour l’utilisateur correspondant à l’email fourni.

La fonction mail() de PHP ou une bibliothèque tierce ?

mail() en PHP : simple, mais limité

La fonction mail() est native en PHP. Elle permet d’envoyer un email rapidement, sans installer quoi que ce soit, donc aucune dépendance externe. Cette fonction est facile à utiliser pour un test en local ou un petit site personnel.

Mais en pratique… Elle contient de nombreux inconvénients majeurs :

  • Aucune authentification SMTP.
  • Pas de support intégré pour les en-têtes modernes (DKIM, SPF, etc.).
  • Les mails finissent souvent dans les spams.
  • Très peu de contrôle sur les erreurs (pas de retour clair si l’envoi échoue).
  • Pas de support HTML propre, ni de pièces jointes faciles à ajouter.

En résumémail() convient uniquement pour du test local, du développement ou des scripts très simples.

Une bibliothèque tierce comme PHPMailer

Cette bibliothèque permet d’envoyer des mails professionnellement, en utilisant un vrai serveur SMTP, avec authentification, en-têtes complets, support HTML, pièces jointes, et gestion des erreurs. C’est la référence dans le monde PHP.

Installation avec Composer. Avant de coder, nous devons installer PHPMailer avec Composer. Si Composer est bien installé sur votre machine (ou sur votre serveur), vous pouvez entrer cette commande dans votre terminal, à la racine de votre projet. Cela va ajouter PHPMailer à votre projet dans le dossier vendor/.

composer require phpmailer/phpmailer

On installe PHPMailer avec Composer à la racine du projet Créa-code, c’est-à-dire là où se trouvent les fichiers autoload.php et  config.php.

Pour un site comme Créa-code, qui vise la qualité, la fiabilité et le sérieux, il ne faut pas utiliser mail() en production. C’est trop risqué et peu professionnel.

Nous allons utiliser PHPMailer avec un vrai SMTP. C’est simple à mettre en place avec Composer et ça changera tout pour la fiabilité de notre système de réinitialisation de mot de passe… et pour tout autre envoi de mail futur (activation de compte, notifications, badges, etc).

SMTP = Simple Mail Transfer Protocol

C’est le protocole standard d’envoi de mails sur Internet. Quand on dit « envoyer un e-mail », on utilise toujours le protocole SMTP, que ce soit via Gmail, Outlook ou un site web.

Quand on parle d’un « vrai SMTP », on veut dire un serveur d’envoi d’emails configuré, sécurisé et fiable, généralement fourni par un hébergeur, un service email, ou un fournisseur spécialisé.

Quand on utilise la fonction mail() de PHP sans rien configurer, PHP essaie d’envoyer l’e-mail en se basant sur le serveur de l’hébergement, sans authentification, souvent avec des en-têtes basiques. Cela passe par ce qu’on appelle un sendmail local, qui est souvent mal configuré.

Formation web et informatique - Alban Guillier - Formateur

Des formations informatique pour tous !

Débutant ou curieux ? Apprenez le développement web, le référencement, le webmarketing, la bureautique, à maîtriser vos appareils Apple et bien plus encore…

Formateur indépendant, professionnel du web depuis 2006, je vous accompagne pas à pas et en cours particulier, que vous soyez débutant ou que vous souhaitiez progresser. En visio, à votre rythme, et toujours avec pédagogie.

Découvrez mes formations Qui suis-je ?

Résultat : L’e-mail est très souventconsidéré comme suspect, il finit généralement dans les spams ou est bloqué et nous n’avons aucun retour clair en cas d’erreur.

Un “vrai SMTP” est un serveur d’envoi d’e-mails fiable, sécurisé, souvent géré par OVH, Ionos, LWS, 02Switch… On peut y créer une adresse pro du style contact@crea-troyes.fr, et l’utiliser dans PHPMailer.

Avec un vrai SMTP, nous aurons : un identifiant (souvent l’adresse email), un mot de passe (ou une clé API), une adresse du serveur SMTP (ex : smtp.brevo.com) et un port (souvent 587 pour TLS)

C’est important car les “vrais” serveurs SMTP authentifient clairement l’émetteur (moins de spams), ajoutent automatiquement des en-têtes DKIM/SPF/DMARC, fournissent des logs en cas d’erreur et ont une réputation de domaine/IP surveillée

Pour faire simple, quand on dit « utiliser un vrai SMTP », on parle d’un serveur SMTP sécurisé, authentifié, avec une vraie réputation, et pas juste un appel à mail() qui passe par un serveur mal configuré ou anonyme.

Envoyer le mail de réinitialisation du mot de passe avec PHPMailer

Nous allons maintenant intégrer PHPMailer pour envoyer l’e-mail avec le lien de réinitialisation. Toujours dans app/controllers/Auth.php, ajoutons la méthode sendResetEmail() :

private function sendResetEmail($email, $token)
{
    require_once '../vendor/autoload.php';

    $mail = new \PHPMailer\PHPMailer\PHPMailer(true);

    try {
        $mail->CharSet = 'UTF-8';
        $mail->isSMTP();
        $mail->Host = 'smtp.example.com';
        $mail->SMTPAuth = true;
        $mail->Username = 'votre@email.fr';
        $mail->Password = 'votre_mot_de_passe';
        $mail->SMTPSecure = 'tls';
        $mail->Port = 587;

        $mail->setFrom('votre@email.fr', 'Code Créa-Troyes');
        $mail->addAddress($email);

        $mail->isHTML(true);
        $mail->Subject = 'Réinitialisation de votre mot de passe';
        $resetLink = 'https://code.crea-troyes.fr/auth/reset?token=' . urlencode($token);
        $mail->Body = "<p>Bonjour,</p><p>Pour réinitialiser votre mot de passe, cliquez sur ce lien : <a href=\"$resetLink\">Réinitialiser</a></p><p>Ce lien expirera dans 15 minutes.</p>";

        $mail->send();
        
    } catch (Exception $e) {
        echo "Erreur lors de l'envoi de l'e-mail : {$mail->ErrorInfo}";
    }
}

Pour utiliser PHPMailer avec une adresse Gmail, il faut ajuster la configuration SMTP à celle de Gmail, activer l’accès sécurisé via OAuth2 ou une « application spécifique », et respecter les paramètres exacts de Google.

Voici la configuration à adapter dans ce script :

$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = 'tonemail@gmail.com'; // ton adresse Gmail
$mail->Password = 'mot_de_passe_application'; // mot de passe d'application, PAS ton mot de passe Gmail
$mail->SMTPSecure = 'tls'; // ou 'ssl' avec port 465
$mail->Port = 587; // ou 465 si SMTPSecure = 'ssl'

⚠️ Attention : Gmail n’autorise plus les « applications moins sécurisées ».

Mot de passe d’application Gmail

  1. Activer la vérification en deux étapes sur votre compte Google :
    https://myaccount.google.com/security
  2. Une fois activée, créez un mot de passe d’application :
    https://myaccount.google.com/apppasswords
  3. Sélectionnez « Mail » puis « Autre (nom personnalisé) », et choisis par exemple PHPMailer
  4. Google génère un mot de passe unique à 16 caractères que tu colles dans :
$mail->Password = 'le_mot_de_passe_app';

Ne jamais utiliser ton mot de passe Gmail principal ici — seulement le mot de passe d’application.

Configuration finale recommandée avec Gmail :

$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = 'tonemail@gmail.com';
$mail->Password = 'ton_mot_de_passe_application';
$mail->SMTPSecure = 'tls'; // ou 'ssl' si tu préfères
$mail->Port = 587; // ou 465 si ssl
$mail->setFrom('tonemail@gmail.com', 'Code Créa-Troyes');

Créer la page de réinitialisation depuis le lien envoyé

Dans l’email que nous avons envoyé via PHPMailer, nous avions mis un lien de cette forme :

https://code.crea-troyes.fr/auth/reset?token=le_token_ici

Ce lien doit pointer vers une page qui affiche un formulaire permettant à l’utilisateur de saisir un nouveau mot de passe.

Côté routeur

Dans le fichier app/Route/Routes.php, on ajoute simplement cette ligne :

$router->get('/reset', 'AuthController@reset');

Côté contrôleur

Nous devons ensuite nous assurer que notre architecture MVC accepte l’URL /auth/reset. Ce sera donc une nouvelle méthode reset() dans le contrôleur AuthConrtoller que nous allons coder.

Dans app/controllers/AuthController.php :

public function reset()
{

    $title = "Créa-code - Mot de passe oublié ?";

    $token = $_GET['token'] ?? '';

    if (!$token) {
        $errors = ["Aucun token n'a été fourni."];
        View::render('login', compact('title', 'errors'));
        return;
    }

    if (!preg_match('/^[a-f0-9]{64}$/', $token)) {
        $errors = ["Le token n'est pas valide."];
        View::render('login', compact('title', 'errors'));
        return;
    }

    $userModel = $this->model('User');
    $user = $userModel->findByToken($token);

    if (!$user) {
        $errors = ["Ce lien n'est pas valide."];
        View::render('login', compact('title', 'errors'));
        return;
    }

    $expiry = strtotime($user['reset_token_expiry']);

    if ($expiry < time()) {
        $errors = ["Ce lien a expiré."];
        View::render('login', compact('title', 'errors'));
        return;
    }

    // On affiche la vue avec le formulaire
    View::render('auth/reset_form', compact('title', 'token'));
}

Avec cette méthode reset() :

  1. On récupère le token depuis l’URL.
  2. On vérifie le token transmis.
  3. On cherche l’utilisateur avec ce token.
  4. On vérifie que la date d’expiration n’est pas dépassée.
  5. Si tout est bon, nous affichons le formulaire de changement de mot de passe.

Rechercher un utilisateur par token

Dans app/models/User.php, on joute la méthode findByToken() :

public function findByToken($token)
{
    $sql = "SELECT * FROM users WHERE reset_token = :token";
    $stmt = $this->db->prepare($sql);
    $stmt->bindValue(':token', $token);
    $stmt->execute();
    return $stmt->fetch(PDO::FETCH_ASSOC);
}

Créer la vue avec le formulaire de nouveau mot de passe

Dans app/views/auth/reset_form.php, on ajoute le code suivant pour afficher le formulaire qui permettra d’entrer un nouveau mot de passe :

<h1>Nouveau mot de passe</h1>

<?php if (!empty($error)) : ?>
    <p><?= htmlspecialchars($error) ?></p>
<?php endif; ?>

<form method="post" action="<?= BASE_URL ?>updatePassword" id="reset_form">
    <input type="hidden" name="token" value="<?= htmlspecialchars($token) ?>">

    <label for="password">Nouveau mot de passe :</label>
    <input type="password" id="password" name="password" required>

    <label for="confirm">Confirmer le mot de passe :</label>
    <input type="password" id="confirm" name="confirm" required>

    <button type="submit">Changer le mot de passe</button>
</form>

<script src="<?= BASE_URL ?>assets/js/reset-password-validation.js"></script>

Ce formulaire envoie les données à la méthode updatePassword() du contrôleur AuthController.php.

Nous ajoutons également un script JavaScript externe qui empêche l’envoi du formulaire si les mots de passe ne correspondent pas ou si le mot de passe ne respecte pas ces règles :

  • Au moins 8 caractères
  • Au moins 1 majuscule
  • Au moins 1 chiffre

Le message d’erreur est affiché lors de la soumissionpas en temps réel. Voici le fichier public/assets/js/reset-password-validation.js :

document.addEventListener("DOMContentLoaded", function () {
    const form = document.getElementById("reset_form");
    const passwordInput = document.getElementById("password");
    const confirmInput = document.getElementById("confirm");

    // Création du conteneur d'erreur si besoin
    let errorContainer = document.createElement("div");
    errorContainer.id = "password-errors";
    errorContainer.style.color = "red";
    errorContainer.style.marginTop = "10px";
    form.appendChild(errorContainer);

    form.addEventListener("submit", function (e) {
        const password = passwordInput.value;
        const confirm = confirmInput.value;
        let errors = [];

        // Vérifications
        if (password !== confirm) {
            errors.push("Les mots de passe ne correspondent pas.");
        }

        if (password.length < 8) {
            errors.push("Le mot de passe doit contenir au moins 8 caractères.");
        }

        if (!/[A-Z]/.test(password)) {
            errors.push("Le mot de passe doit contenir au moins une lettre majuscule.");
        }

        if (!/[0-9]/.test(password)) {
            errors.push("Le mot de passe doit contenir au moins un chiffre.");
        }

        // Affichage et blocage du formulaire si erreurs
        if (errors.length > 0) {
            e.preventDefault();
            errorContainer.innerHTML = "";
            errors.forEach(function (err) {
                const p = document.createElement("p");
                p.textContent = err;
                errorContainer.appendChild(p);
            });
        }
    });
});

Le formulaire POST vers /updatePassword doit avoir une route déclarée dans Routes.php, sinon elle renverra une 404.

$router->post('/updatePassword', 'AuthController@updatePassword');

Vérifier et mettre à jour le mot de passe

On ajoute la méthode updatePassword() dans le contrôleur AuthController.php :

public function updatePassword()
{
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        
        $title = "Modifiez votre mot de passe - Créa-code";

        $token = $_POST['token'] ?? '';
        $password = $_POST['password'] ?? '';
        $confirm = $_POST['confirm'] ?? '';

        if (empty($token) || empty($password) || empty($confirm)) {
            $error = "Tous les champs sont obligatoires.";
            View::render('auth/reset_form', compact('title', 'token', 'error'));
            return;
        }

        if ($password !== $confirm) {
            $error = "Les mots de passe ne correspondent pas.";
            View::render('auth/reset_form', compact('title', 'token', 'error'));
            return;
        }

        // Vérifie longueur minimale
        if (strlen($password) < 8) {
            $error = "Le mot de passe doit contenir au moins 8 caractères.";
            View::render('auth/reset_form', compact('title', 'token', 'error'));
            return;
        }

        // Vérifie absence d'espaces
        if (preg_match('/\s/', $password)) {
            $error = "Le mot de passe ne doit pas contenir d'espaces.";
            View::render('auth/reset_form', compact('title', 'token', 'error'));
            return;
        }

        // Vérifie présence d'une majuscule
        if (!preg_match('/[A-Z]/', $password)) {
            $error = "Le mot de passe doit contenir au moins une lettre majuscule.";
            View::render('auth/reset_form', compact('title', 'token', 'error'));
            return;
        }

        // Vérifie présence d'un chiffre
        if (!preg_match('/[0-9]/', $password)) {
            $error = "Le mot de passe doit contenir au moins un chiffre.";
            View::render('auth/reset_form', compact('title', 'token', 'error'));
            return;
        }

        $userModel = new User(Database::getInstance());
        $user = $userModel->findByToken($token);

        if (!$user) {
            $error = "Lien de réinitialisation invalide.";
            View::render('auth/reset_form', compact('title', 'token', 'error'));
            return;
        }

        $expiry = strtotime($user['reset_token_expiry']);

        if ($expiry < time()) {
            $error = "Lien expiré.";
            View::render('auth/reset_form', compact('title', 'token', 'error'));
            return;
        }

        // Tout est OK, on hash le nouveau mot de passe
        $hash = password_hash($password, PASSWORD_DEFAULT);

        // Mise à jour
        $userModel->updatePassword($user['id'], $hash);

        $errors = ["Mot de passe mis à jour avec succès. Vous pouvez maintenant vous connecter."];
        View::render('login', compact('title', 'token', 'errors'));

    }
}

Mise à jour du mot de passe en base

Dans app/models/User.php, nous ajoutons la méthode updatePassword pour mettre à jour le mot de passe dans la table users.

public function updatePassword($id, $hash)
{
    $sql = "UPDATE users SET password = :hash, reset_token = NULL, reset_token_expiry = NULL WHERE id = :id";
    $stmt = $this->db->prepare($sql);
    $stmt->bindValue(':hash', $hash);
    $stmt->bindValue(':id', $id, PDO::PARAM_INT);
    $stmt->execute();
}

Nous mettons à jour le mot de passe, en supprimant le token et sa date d’expiration, pour que ce lien ne puisse plus jamais être réutilisé.

Pour rappel, nos modèles servent à interagir avec la base de données.


Nous avons mis en place un système complet et sécurisé de réinitialisation de mot de passe. En résumé, nous avons :

  • Créé un formulaire pour envoyer un lien de réinitialisation.
  • Généré un token unique avec une date d’expiration.
  • Utilisé PHPMailer pour envoyer un mail professionnel via un vrai serveur SMTP.
  • Vérifié le lien et affiché un formulaire pour saisir un nouveau mot de passe.
  • Sécurisé la mise à jour en base de données, et nettoyé le token.

C’est une fonctionnalité indispensable, et surtout une excellente occasion de progresser en PHP, en sécurité, et en MVC. Bravo si vous êtes arrivé jusqu’ici.

À demain pour la suite …

Live on Twitch