Imágenes de validación de formularios en PHP (captcha).Este sistema de seguiridad comenzó a hacerse popular cuando los proveedores de cuentas gratuitas de correo vieron que los spammers creaban grandes cantidades de cuentas mediante bots que rellenaban los formularios de manera automatizada. Por ese motivo se hizo necesario crear un sistema que compruebe que quien realiza el registro de la cuenta es una persona y no un programa. Para ello se añadieron imágenes conteniendo un texto aleatorio difícil de leer para una máquina obligando al usuario a introducir ese texto para poder validarse.
Voy a exponer un código sencillo en PHP para generar estas imágenes y validarlas en tres capas.
Se requiren conocimientos básicos de manejo de sesiones en php y de la librería gráfica GD.
1 – El script Captcha.php. Una clase que genera la imagen captcha:
<?php define ("WIDTH", 120); define ("HEIGHT", 30); define ("CELL", 20); define ("FOLDER", "tmp/"); define ("FONTNAME", "AcidDreamer.ttf"); define ("FONTSIZE", 18); define ("MAXFILES", 5); class Captcha { function createImage($randString, $name) { $img = imagecreate(WIDTH, HEIGHT) or die("Can not create image");; imagecolorallocate($img, 200, 200, 200); //colors $black = imagecolorallocate($img, 0, 0, 0); imagerectangle($img, 0, 0, WIDTH-1, HEIGHT-1, $black); //print letters of rand string for ($i=0; $i < strlen($randString); $i++) { imagettftext($img, FONTSIZE, 10, $i*CELL + 2, 26, $black, FONTNAME, $randString[$i]); } $imagePath = FOLDER.$name.".png"; imagepng($img, $imagePath); imagedestroy($img); return $imagePath; } function createRandString($numChars) { $letters = "0123456789"; $numLetters = strlen($letters); $randString = ""; for ($c=0; $c < $numChars; $c++) { $num = rand(0, $numLetters-1); $randString .= $letters[$num]; } return $randString; } function deleteOldImages() { $DIR = opendir(FOLDER); $images = array(); while (($name = readdir($DIR))) { if ($name != "." && $name != "..") { $images[] = $name; } } closedir($DIR); if (count($images) == 0) return; rsort($images); while (count($images) > MAXFILES) { $last = array_pop($images); unlink(FOLDER.$last); } } } ?>
Se crea una cadena aleatoria para el nombre de la imagen y otra cadena aleatoria para el texto que se mostrará que no coincidirán.
Ambas cadenas se guardan como variables de sesión. Las variables de sesión y su contenido es invisible para el cliente.
2 – El formulario que llama al script anterior ‘formulario.php’:
<?php session_start(); //iniciamos la sesión require_once('Captcha.php'); $captcha = new Captcha(); $filename = time()."_".$captcha->createRandString(20); $_SESSION['image_code'] = $captcha->createRandString(6); $captcha->deleteOldImages(); ?> <html> <head></head> <body> <form action="validacion.php" method="post"> <?php $_SESSION['image_name'] = $captcha->createImage($_SESSION['image_code'], $filename); ?> <img src="<?php echo $_SESSION['image_name'] ?>"> <input type="text" name="imageText" /> <input type="submit" name="action" value="Submit" /> </form> </body> </html>
3 – La página de validación final ‘validacion.php’:
<?php session_start(); //iniciamos la sesión ?> <html> <body> <?php if ($_SESSION['image_code'] == $_POST['imageText']) { //validacion correcta echo "Bien"; session_unregister($_SESSION['image_code']); session_unregister($_SESSION['image_name']); } else { //ERROR echo "error"; } ?> </body> </html>
Finalmente, se compara la entrada del usuario con la información guardada en la variable de sesión. Si coincide, se borra la variable de sesión y la imagen y se continúa con la ejecución del script. En caso contrario, se muestra el error y se pide al usuario que vuelva a revisar el formulario.
Unas recomendaciones:
- El color de fondo y el de la fuente deben ser ligenramente parecidos (negro sobre gris por ejemplo).
- Usar fuentes poco comunes que estén ligeramente deformadas pero no difíciles de leer.