Image de l'article Un code de sécurité PHP pour vos formulaires, partie 3

Un code de sécurité PHP pour vos formulaires, partie 3

Si vous prenez cet article en cours, voici les liens vers les 3 parties. Je vous conseille de commencer la lecture par la première partie puisque c'est progressif.

  1. Création d'un code de sécurité
  2. Amélioration du code de sécurité
  3. Vérification

Afficher les données de l'image

Tout d'abord, nous allons faire un ajustement dans la fonction qui génère le code. Nous n'allons plus enregistrer l'image sur le serveur, mais depuis un cache temporel avec ob_start(); et ob_get_clean().

Il faut remplacer les deux dernières lignes de la fonction CaptchaImage() par le code suivant :


// démarre le cache
ob_start();
// affiche l'image dans le cache
imagepng($img);
// enregistre les données du cache dans une variable et efface le cache
$imgData = ob_get_clean();
// détruit l'image
imagedestroy($img);
// renvoi les données de l'image
return $imgData;

Puisque la fonction renvoie les données brutes au lieu de créer un fichier, on ne peut plus afficher l'image en pointant vers ce fichier. Heureusement il est possible d'afficher des données en HTML en précisant le type. Ici image/png :


<img src="data:image/png;base64,'.base64_encode(CaptchaImage($txt, 'test.png', 200, 50, 20)).'" width="200" height="50" />

Pour info vous pouvez utiliser la même technique en CSS :


.maClasse{
	background-image: url(data:image/png;base64, [ici votre image codé en base 64] );
}

Internet Explorer ne supporte pas l'affichage des images avant la version 8.

Les variables de session en PHP avec $_SESSION

Les variables de session sont des variables temporaires affectés à l'utilisateur par le serveur. En PHP elles se manipulent de la même manière que des variables $_POST ou $_GET.

La portée est la même que les variables de cookies, vous pouvez y accéder dans tous les fichiers de votre application, mais elles sont temporaires et ne sont pas enregistrées sur le disque de l'utilisateur.

La durée de ces variables est définie par session_cache_expire(), il faut démarrer ou restaurer une session avec la fonction session_start();.

Par exemple créons un fichier a.php


session_start();
$_SESSION['ma_variable'] = 'Je mange des bretzels au petit déjeuner !';

Vous pouvez créer un fichier b.php et accéder à la variable initialisée dans a.php


session_start();
echo $_SESSION['ma_variable'];
// Je mange des bretzels au petit déjeuner !

Voilà pour les variables de session.

Vérification du code de sécurité

Maintenant que nous avons toutes les cartes en mains pour utiliser un code de sécurité, il est temps de finaliser la vérification.

On vérifie si la variable postée par l'utilisateur n'est pas vide avec empty(). Je préfère empty à isset parce que cette dernière se contente de vérifier l'existence de la variable. Empty vérifie en plus qu'elle n'est pas null ou vide.

On compare ensuite la valeur donnée par l'utilisateur à la valeur enregistrée en session.


session_start();
if($_GET['do']=='register'){
	if(!empty($_POST['codeSecure']) && $_POST['codeSecure']==$_SESSION['codeSecure']){
		// Tout est bon !
		$_SESSION['codeSecure'] = '';
	}
}

Mise en pratique et test de la session

Voici le fichier complet d'exemple, du PHP un soupçon de CSS un peu d'HTML.


<?php
function RandomWordFromArray($aWordLst, $WordNb=1){
	if(!is_array($aWordLst)) $aWordLst = explode(' ', $aWordLst);
	$str = '';
	$max = count($aWordLst)-1;
	for($i=0; $i<$WordNb; $i++){
		if($WordNb>1 && $i>0) $str .= ' ';
		$str .= $aWordLst[rand(0, $max)];
	}
	return $str;
}
// créer une image avec la bibliothèque GD
function CaptchaImage($aText='', $aWidth=200, $aHeight=50, $aNbLine=0, $aFontSize=20, $aLetterMaxAngle=5){
	if(empty($aText)) return 0;
	putenv('GDFONTPATH=' .dirname(__FILE__));
	$font = 'ArialRoundedBold';
	// calcul les coordonnées X et Y pour centrer le texte
	$box = imagettfbbox($aFontSize, 0, $font, $aText);
	$strX = ($aWidth-abs($box[4]))/2;
	$strY = ($aHeight-(abs($box[1])-abs($box[7])))/2;
	// créer l'image
	$img = imagecreatetruecolor($aWidth, $aHeight);
	// ajoute un fond clair
	imagefill($img, 0, 0, imagecolorallocate($img, 250, 250, 250));
	// active l'anti-aliasing
	imageantialias($img, true);
	// dessine quelques traits
	for($i=0; $i<$aNbLine; $i++){
		$r = rand(150, 255);
		$v = rand(150, 255);
		$b = rand(150, 255);
		$color = imagecolorallocate($img, $r, $v, $b);
		imageline($img, 0, rand(-50, $aHeight+50), $aWidth, rand(-50, $aHeight+50), $color);
	}
	// affiche le texte, lettre par lettre
	$strLen = strlen($aText);
	for($i=0; $i<$strLen; $i++){
		// change la couleur du caractère
		$r = rand(0, 150);
		$v = rand(0, 150);
		$b = rand(0, 150);
		$color = imagecolorallocate($img, $r, $v, $b);
		// change l'angle
		$angle = rand(-$aLetterMaxAngle, $aLetterMaxAngle);
		imagettftext($img, $aFontSize, $angle, $strX, $strY, $color, $font, substr($aText, $i, 1));
		$box = imagettfbbox($aFontSize, 0, $font, substr($aText, $i, 1));
		$strX += $box[4]+$aFontSize/8;
	}
	// démarre le cache
	ob_start();
	// afiche l'image dans le cache
	imagepng($img);
	// enregistre les données du cache dans une variable
	$imgData = ob_get_clean();
	// détruit l'image
	imagedestroy($img);
	// renvoi la variable
	return $imgData;
}
// démarre la session
session_start();
// variable pour savoir si le formulaire a été envoyé
$codeSend = 0;
// variable pour savoir si le code est correct
$codeOk = 0;
if($_GET['do']=='register'){
	// l'utilisateur a posté le formulaire
	// on initialise la variable $codeSend
	$codeSend = 1;
	// On vérifie si la variable 'codeSecure' n'est pas vide
	// ET si elle correspond avec la valeur enregistré en session
	if(!empty($_POST['codeSecure']) && $_POST['codeSecure']==$_SESSION['codeSecure']){
		// le code est bon, on peut traiter le formulaire normalement
		$codeOk = 1;
		// réinitialise la variable en session par sécurité
		$_SESSION['codeSecure'] = '';
	}
}

if($codeOk){
	// le code est correct
	$h = '<div class="codeOk"><h1>Code correct !</h1><p><a href="code-securite-php-final.php">Recommencer</a></p></div>';

}else{
	// affiche le formulaire
	if($codeSend){
		// l'utilisateur a envoyé le formulaire, mais le code est incorrect
		$h = '<div class="codeErreur"><h1>Code incorrect !</h1><p>Le code ne correspond pas</p></div>';
	}
	$dico = 'balle base biche boire boule buche canard cercle chou cours courir croire dire dormir entier facile genou hibou image impair lire liste manger marcher montage monter mousse pierre pion poule pull quart scie signe temps valoir voir wagon';
	$txt = RandomWordFromArray($dico, 2);
	// enregistre le code dans une variable de session
	$_SESSION["codeSecure"] = $txt;
	// formulaire
	$h .= '
<div id="main">
<h1>Test de code de sécurité en PHP</h1>
<form method="post" action="code-securite-php-final.php?do=register">
<p>Placez les champs de votre formulaire ici...</p>
<h2>Code de sécurité</h2>
<p>On ajoute le code de sécurité à la fin</p>
<p><span class="formMarge"> </span><img src="data:image/png;base64,'.base64_encode(CaptchaImage($txt, 200, 50, 20)).'" width="200" height="50" alt="" /></p>
<p><label class="formMarge">Code : </label><input type="text" value="" name="codeSecure" id="champ_codeSecure" size="30" maxlength="50"></p>
<p><span class="formMarge"> </span><input type="submit" name="Submit" value="Tester le code"></p>
</form>
</div>';
}
?>
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<title>Code de sécurité</title>
	<style type="text/css">
body{
	margin: 0;
	padding: 0;
	background-color: #f8f4ee;
	text-align: center;
	font-family: Helvetica, serif;
	font-size: 14px;
}
#main{
	margin: 0 20%;
	text-align: left;
}
h1{
	margin: 0;
	padding: 1em 0 0.5em 0;
	font-size: 2em;
}
.codeOk, .codeErreur{
	padding: 5% 10%;
	margin: 5% 10%;
	border: 0.5em dashed #f8f4ee;
	text-align: center;
}
.codeOk{
	background-color: #ccff66;
}
.codeOk a{
	color: #000;
	text-decoration: none;
	border-bottom: 1px dotted #000;
}
.codeErreur{
	background-color: #ff8485;
}
	</style>
</head>
<body>
<?php
echo $h;
?>
</body>
</html>

Démonstration

Liens vers les autres parties de cet article

  1. Création d'un code de sécurité
  2. Amélioration du code de sécurité
  3. Vérification

Article précédent : Ressource interprétée comme Image mais transférée avec un type MIME text/html

Article suivant : Éliminer les codes JavaScript et CSS qui bloquent l'affichage au dessus de la ligne de flottaison

 

Image Viewer