Blog de Portekoi : Programmation et Astuces

Programmation Cobol, Php, Asp, Java et DotNet…

Captcha simple mais efficace en PHP

Le pourquoi du comment :

Sur certains de mes sites, j’utilisais un captcha sous cette forme :

Combien font 1 + 3?

Mais les robots trouvaient parfois la bonne réponse sachant que cela n’était que des chiffres entre 1 et 18 maximum.

J’ai donc recréé un autre système plus performant composé de deux parties : La lettre dans un mot choisit de manière aléatoire et la présence d’un champ hidden « piégé »(1).
Pour la première solution, on le voit assez souvent sur le web et je trouve cela assez efficace mais j’ai préféré doubler la sécurité avec un champ caché.

Cela nous donnera donc ceci :

Quelle est la 2ième lettre du mot : Ordinateur

Pour pouvoir valider le formulaire, il faudra bien évidemment répondre « r ».

Comment cela fonctionne-t-il?

Tout d’abord, dans votre formulaire, placez un champ piégé (comme ci-dessous) bien nommé comme « email » ou « login » par exemple. Les robots raffolent de ce genre de données.
Ensuite, dans le script qui contrôlera les données, il suffira de vérifier que le champ « email » (ou « login ») soit bien vide.
S’il devait être saisi, c’est qu’un robot sera à l’origine de la requête.

<input type="hidden" name="email" value="" />

Ensuite, pour le contrôle via une lettre, j’ai d’abord recherché un site me permettant d’obtenir une liste de mots conséquente. J’ai trouvé celui-ci :
http://www.liste-de-mots.com/

J’ai ensuite récupéré ma liste de mots et tout placé dans un fichier texte avec un encodage en UTF-8. Ce point est très important.

Voici le code php pour récupérer le mot et déterminer une lettre de manière aléatoire :

<?php
//si le fichier existe
if(file_exists("fichier.txt")){
    //On lit le fichier
    $f_contents = file("fichier.txt");
    //On en extrait un ligne et donc un mot en remplaçant les sauts de ligne
    $word = str_replace("%0D%0A", "", trim($f_contents[array_rand($f_contents)]));
    //Longueur du mot?
    $len = strlen( utf8_decode( $word ) );
    //Nombre aléatoire entre 1 et longueur du mot.
    $nb = rand(1, $len);
    //On récupère la lettre pour la réponse
    //(-1 car la fonction substr commence à l'indice 0)
    $reply = substr($word, $nb-1, 1);  
    //On place la réponse dans une session :
    $_SESSION["securite"] = $reply;
   
    /*
    Ainsi, dans la page qui fera le contrôle, il suffira de faire entre autres contrôles :
    if($_SESSION["securite"] == $_POST["securite"] && $_POST["email"] == ""){
        //On envoi le message  
    }
    */

}
?>

Le code HTML (via Bootstrap 3) :

<form role="form">
<div class="row">
<div class="form-group col-lg-4"><label for="email">Email</label>
<input class="form-control" id="adreml" type="email" name="adreml" placeholder="Saisissez votre Email" /></div>
</div>
<div class="row">
<div class="form-group col-lg-4"><label for="prenom">Prénom</label>
<input class="form-control" id="prenom" type="text" name="prenom" placeholder="Votre Prénom" /></div>
</div>
<div class="row">
<div class="form-group col-lg-4"><label for="message">Message</label>
<textarea class="form-control" id="message" name="message" placeholder="Votre Message" rows="6"></textarea></div>
</div>
<div class="row">
<div class="form-group col-lg-4"><label for="securite">Quelle est la <?php echo $nb;?>ième lettre du mot : <?php echo $word;?></label>
<!-- Je n'ai pas trouvé comment faire pour mettre un type "small" comme dans BootStrap 2.3.2 -->
<span class="col-lg-4">
<input class="form-control" id="securite" type="text" name="securite" />
</span></div>
</div>
<input type="hidden" name="email" value="" />
<button class="btn btn-default" type="submit">Envoyer</button>

</form>

La source complète est ici : http://blog.portekoi.com/exemple/captcha/

Le fichier contenant les mots :
http://blog.portekoi.com/exemple/captcha/fichier.txt

(1)Champ caché détaillé ici : http://www.fredboucher.com/posts/view/un-captcha-infaillible-

, ,

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *