Tutorial - Comment faire une image de vérification pour protéger ses formulaires
Votre site comporte sûrement des
formulaires, que ce soit pour un formulaire de contact/d'inscription, un système de commentaire pour votre blog, un livre d'or, un forum...
Ces formulaires peuvent être la cible de
robots de spam, qui envoient de manière automatique des publicités ou des liens.
Des hackers peuvent aussi le faire
de manière massive pour crasher votre base de données voire votre serveur web.
Pour y remédier, il existe une
solution simple que vous avez sûrement déjà vu sur de nombreux sites: une
image de vérification aussi appelée captcha.
Cette image est cryptée et prouve que celui qui remplit le formulaire est bien humain.
Vous apprendrez avec ce tutorial Ã
créer cette image et Ã
effectuer la vérification de la valeur entrée.
Le code PHP est celui utilisé pour la vérification des ajouts de commentaires sur le blog Pixtiz.
Ce tutorial a été largement inspiré par un post du forum de notoon.fr.
Les éléments requis
Pour ce tutorial, vous aurez besoin de la
librairie GD. Vérifier qu'elle est
activée auprès de votre hébergeur ou avec un phpinfo().
La plupart des hébérgeurs payant ont cette librairie activée.
Pour pouvoir générer les caractères, vous devrez
placer un police de caractères sur votre serveur, dans le même dossier que celui où
vous placerez les fichiers PHP.
Choisissez une police lisible, le but ici n'est pas de gêner l'utilisateur avec des caractères incompréhensibles mais de brouiller les robots.
Vous pouvez
en uploader plusieurs pour plus de sécurité.
Pour Pixtiz, j'utilisé simplement la police arial.ttf. N'oubliez pas de renommer l'extension TTF en minuscule (ou modifiez le script PHP).
Placez aussi le fichier
bruit.png qui servira à brouiller le fond de l'image.
Le fichier image.php qui va créer l'image de vérification
<?php
// On démarre une session
session_start();
/*
Pour créer une image, on envoie un en-tête avec la fonction header()
pour dire au navigateur qu'on envoie une image
Lorsqu'on va appeler l'image avec <img src="..." /> on utlisera
bien image.php et non bruit.png
*/
header("Content-Type: image/png");
/**
mt_rand() génère un nombre aléatoire : cette fonction est
plus rapide que rand() de la bibliothèque standard
sha1() renvoie une chaine cryptée de son paramètre. Elle est similaire
à md5() mais renvoie une chaine plus longue, la probabilité de
collision est donc réduite
substr() retourne le segement d'une chaine. Dans notre cas on prend un segment
de 5 caractères en partant du caractère 0
On stocke alors la chaine obtenue dans $rand_str
*/
$rand_str = substr( sha1( mt_rand() ), 0, 5);
// On hash ensuite cette valeur avec md5() puis on stocke ce résultat
dans variable de session $_SESSION['valeur_image'] de la session en cours
$_SESSION['valeur_image'] = md5($rand_str);
// Afin de personnaliser chacun de nos caractères, on les stocke un
par un dans des variables
$char1=substr($rand_str,0,1);
$char2=substr($rand_str,1,1);
$char3=substr($rand_str,2,1);
$char4=substr($rand_str,3,1);
$char5=substr($rand_str,4,1);
/*
imagecreatefrompng() crée une nouvelle image PNG à partir d'un
fichier
On la stocke dans $image pour pouvoir y mettre ensuite nos caractères
*/
$image=imagecreatefrompng("bruit.png");
/*
putenv() fixe la valeur de la variable d'environnement pour GD. Cette valeur
n'existera que durant la vie du script courant, et l'environnement initial sera
restauré lorsque le script sera terminé
Cette ligne est utile si vous avez des problèmes lorsque la police de
caractère réside dans le même dossier que le script qui
l'utilise
Remarquez que lorsqu'on utilisera les polices, il faudra enlever l'extension
.tff
*/
putenv('GDFONTPATH=' . realpath('.'));
/*
glob() retourne un tableau contenant les fichiers trouvés dans le dossier
avec l'extension .ttf
Vous pouvez donc ajouter autant de police TTF que vous voulez
*/
$files = glob("*.ttf");
/*
Pour chaque nom de fichier trouvé, on retire l'extension .tff
Et on l'ajoute au tableau $font[]
*/
foreach ($files as $filename) {
$filename = substr($filename,0,-4); // retire l'extension .tff
$fonts[] = $filename; // ajoute les noms des polices sans leur extension dans
un tableau
}
/*
imagecolorallocate() retourne un identifiant de couleur
On définit les couleurs RVB qu'on va utiliser pour nos polices et on
les stocke dans le tableau $colors[]
Vous pouvez ajouter autant de couleurs que vous voulez
*/
$colors = array(imagecolorallocate($image, 255,0,0), // rouge
imagecolorallocate($image, 109,30,100), // violet
imagecolorallocate($image, 30,80,180), // bleu
imagecolorallocate($image, 40,100,20), // vert
imagecolorallocate($image, 255,90,0), // orange
imagecolorallocate($image, 130,130,130)); // gris
/*
On crée la fonction aleatoire() qui va retourner une valeur prise au hasard dans un tableau
Elle sera utilisée pour piocher une couleur et une police au hasard pour chaque caractère
*/
function aleatoire($tab){
$max = count($tab)-1;
$hasard = mt_rand(0,$max);
return ($tab[$hasard]);
}
/*
On met en forme nos caractères un par un pour les disposer sur notre
image d'origine bruit.png
imagettftext(image, taille_de_la_police, angle, coordonnée_X_à_partir_du_bord,
coordonnée_Y_à_partir_du_bord, couleur_RVB, police_de_caractères,
texte) dessine un texte avec une police TrueType
*/
imagettftext($image, 25, -10, 10, 35, aleatoire($colors), aleatoire($fonts), $char1);
imagettftext($image, 25, 20, 40, 35, aleatoire($colors), aleatoire($fonts), $char2);
imagettftext($image, 25, -35, 60, 35, aleatoire($colors), aleatoire($fonts), $char3);
imagettftext($image, 25, 25, 100, 35, aleatoire($colors), aleatoire($fonts), $char4);
imagettftext($image, 25, -15, 120, 35, aleatoire($colors), aleatoire($fonts), $char5);
// imagepng() crée une image PNG en utilisant l'image $image
imagepng($image);
//L'image a été créée, on appelle donc imagedestroy() qui libère toute la mémoire associée à l'image $image
imagedestroy($image);
?>
La page form.php avec le fomulaire et la vérification
<?php
/** On démarre une session pour pouvoir récupérer le code généré */
session_start();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
/>
<title>Formulaire avec captcha</title>
</head>
<body>
<?php
/** Si le formulaire a été soumis */
if(isset($_POST['submit'])) {
$nombre = $_POST['nombre']; // on stocke dans $nombre la valeur tapée
dans le formulaire
// si le code ne correspond pas à celui déjà stocké
dans la variable de session après l'avoir hashé avec md5() comme
l'autre
if(md5($nombre) != $_SESSION['valeur_image'])
// on affiche une erreur
echo '<h1>Le code ne correspond pas, réessayez !</h1>';
// sinon le code est exact
else echo '<h1>Le code est exact !</h1>';
}
?>
<!-- Formulaire $_SERVER['PHP_SELF'] signifie que le traitement du formulaire se fait sur la même page -->
<form name="verify_form" method="post" action="<?
$_SERVER['PHP_SELF'] ?>">
<!-- Affichage de l'image créée par image.php -->
<img src="image.php" alt="Captcha" id="captcha"
/>
<br /><br />
<label for="Verification">Recopiez le code ci-dessus</label>
<br />
<input name="nombre" type="text" id="nombre">
<br />
<input type="submit" name="submit" value="Envoyer"
/>
</form>
</body>
</html>
Pour tout problème avec votre
création d'images de vérification, vous pouvez laisser un commentaire sur cet article.
Faut il une image d'origine au format png?? comment doit on l'appeler??
merci :) ^^