7.PHP pour le web

7.4.Captcha (anti robot) pour formulaire

7.4.5.Intégration du captcha dans un formulaire (suite)

7.4.5.1.Validation

Le code du formulaire précédent doit être enrichi pour intégrer la validation (i.e. récupérer le mot du captcha en session et le comparer avec le mot saisi). Ce qui donne en première approximation
<?php
// Utilisation des sessions
session_start();

// Tableau des erreurs de validation
$errs = array();

if (strlen($_POST["submit"]) >0) {
    // On a clique sur le bouton "Sauver"
    if ($_POST["captcha"] != $_SESSION["sess_captcha"]) {
        $errs["captcha"][] = "Le mot saisi ne correspond pas a l'image";
    }
    // Poursuivre avec la validation des autres champs du formulaire
    
    if (count($errs) == 0) {
        // Les donnees du formulaires ont ete validee (pas d'erreur trouvee)
        // faire ce qui doit etre fait (envoi de mail, enregistrement en base)
        // et rediriger vers la page suivante
        // header("Location: pagesuivante.php");
        die("Formulaire valide!");
    }
}


// Eventuellement integrer ici l'habillage "superieur" (entete) du site

// Si des erreurs ont été trouvées, les afficher sous forme de liste
if (count($errs) > 0) {
    echo "<ul>";
    foreach ($errs as $champEnErreur => $erreursDuChamp) {
        foreach ($erreursDuChamp as $erreur) {
            echo "<li>".$erreur."</li>";
        }
    }
    echo "</ul>";
}
?>
<form method="post">
   <!-- Inserer les vrais champs du formulaire (nom, prenom, id, etc.) -->
   <img src="captcha.php" alt="captcha" />
   Copier le mot ici: <input type="text" name="captcha" />
   <input type="submit" name="submit" value="Sauver"/>
</form>
<?php
// Eventuellement integrer ici l'habillage "inferieur" (pied de page) du site
?>
que vous pouvez tester Comme vous pouvez le constater, nous vérifions bien que le mot saisi correspond à celui qui est affiché.
Mais il y a des failles dans cette solution. Si monsieur "pasgentil" se crée son propre formulaire (ce qui est tout à fait possible) pointant sur le même script de validation mais sans intégrer le captcha (donc sans générer un nouveau mot à chaque tentative) alors il pourra au choix:
  • Ne jamais avoir affiché le captcha du site visité et donc pouvoir valider son formulaire en laissant le champ "captcha" vide. Pour lutter contre cela, il faut s'assurer que le captcha a bien été créé (et donc que l'on a bien en session un mot non vide).
  • Avoir déjà affiché au moins une fois le captcha du site visité (mais plus par la suite) et donc pouvoir valider son formulaire autant de fois qu'il le veut en saisissant toujours le même mot. Pour lutter contre cela, il faut réinitialiser le captcha après chaque validation (fructueuse ou infructueuse).
Le code complet est donc le suivant
<?php
// Utilisation des sessions
session_start();

// Tableau des erreurs de validation
$errs = array();

if (strlen($_POST["submit"]) >0) {
    // On a clique sur le bouton "Sauver"
    if (strlen($_SESSION["sess_captcha"]) == 0) {
        $errs["captcha"][] = "Captcha invalide";
    }
    if ($_POST["captcha"] != $_SESSION["sess_captcha"]) {
        $errs["captcha"][] = "Le mot saisi ne correspond pas a l'image";
    }
    
    // on en a fini avec le captcha... on re-initialise
    unset($_SESSION["sess_captcha"]);
    
    // Poursuivre avec la validation des autres champs du formulaire
    
    if (count($errs) == 0) {
        // Les donnees du formulaires ont ete validee (pas d'erreur trouvee)
        // faire ce qui doit etre fait (envoi de mail, enregistrement en base)
        // et rediriger vers la page suivante
        // header("Location: pagesuivante.php");
        die("Formulaire valide!");
    }
}


// Eventuellement integrer ici l'habillage "superieur" (entete) du site

// Si des erreurs ont été trouvées, les afficher sous forme de liste
if (count($errs) > 0) {
    echo "<ul>";
    foreach ($errs as $champEnErreur => $erreursDuChamp) {
        foreach ($erreursDuChamp as $erreur) {
            echo "<li>".$erreur."</li>";
        }
    }
    echo "</ul>";
}
?>
<form method="post">
   <!-- Inserer les vrais champs du formulaire (nom, prenom, id, etc.) -->
   <img src="captcha.php" alt="captcha" />
   Copier le mot ici: <input type="text" name="captcha" />
   <input type="submit" name="submit" value="Sauver"/>
</form>
<?php
// Eventuellement integrer ici l'habillage "inferieur" (pied de page) du site
?>