jueves, 21 de mayo de 2015

Creando un catpcha usando PHP GD

Actualmente hay un monton de librerias de captchas en la web, como anteriormente mostre una de google captcha: http://arthusu.blogspot.mx/2014/09/resumen-recaptcha.html

Un desarrollador debe conocer como un captcha es generado. En este tutorial iremos paso a paso como crear un captcha usando PHP GD. El captcha es una cadena generada aleatoria generada automaticamente por numeros/letras, la cadena generada es guardada en algo (como sesiones o base de datos), cuando el usuario envia el formulario, este verifica si el texto introducido por el usuario es igual a la cadena generada y almacenada en la sesion por ejemplo, si coinciden asume que el que ingreso la cadena es un humano y no un bot y el proceso seguiria. En estos dias hay capchas de matematicas tales como 5x_ = 20 y si llenaras el espacio vacio con 4 que seria 5x4 = 20 el formulario es validado. En este tutorial solo nos concentraremos en una imagen de captcha. Para generar un captcha lo que necesitamos nosotros es una cadena aleatoria, para ello utilizaremos la libreria PHP GD, en la mayoria de los casos esta libreria viene instalada por defecto en los servidores. Asi que no discutiremos como instalarla. PHP GD tienen varias funciones para generar imagenes en varios formatos, nosotros comenzaremos con imagecreatetruecolor:

$im = imagecreatetruecolor('150','50');

Lo anterior crea una imagen de 150px de ancho y 50px de alto. Note que $im contiene el recurso de la imagen y no la imagen actual. Nosotros agregaremos componentes a la imagen tal como fondos, cadenas de texto. En este caso requerimos tres colores: primero para el fondo, segundo para la cadena y tercero para hacer unos pixeles de ruido, para que el captcha sea dificultoso para que los bots lo lean. Antes de aplicar estos colores a nuestro recurso de imagen $im primero tenemos que crear los tres colores:

$bg = imagecolorallocate($im, 230, 80, 0); // fondo naranja
$fg = imagecolorallocate($im, 255, 255, 255); // texto blanco
$ns = imagecolorallocate($im, 200, 200, 200); // ruido color gris

Los ultimos tres parametros para imagecolorallocate son el rgb para color. Y el primer parametro es el recurso de la imagen. Entonces ahora tenemos los colores listos, ahora necesitamos llenar la imagen con estos colores, primero agregemos el color de fondo:

imagefill($im, 0, 0, $bg); // el segundo y tercer parametro son las coordenadas x e y para comenzar el llenado de color

Ahora agregamos algunos caracteres a la imagen. Por ahora nosotros agregaremos la palabra 'captcha' pero esta debe ser generada automaticamente en el codigo final.

imagestring($im, 5, 10, 8, 'captcha', $fg);

imagestring dibuja la cadena 'captcha' como quinto parametro. El segundo parametro 5 es el tamaño de la fuente. 10 y 8 son de la esquina arriba a la izquierda las coordenadas x e y para comenzar la cadena desde ese punto. El primer parametro es el recurso de imagen y el ultimo es el color de la cadena. Nosotros agregamos un color de fondo, y una cadena de texto. Esta oficialmente hecho. Pero algunos bots son capaces de leer imagenes. Entonces para defendernos nosotros agregaremos un poco de ruido a la imagen para que solo la puedan leer los humanos y los bots no. 

imagesetpixel($im, 2, 4, $ns);

El codigo de arriba agrega un pixel en la coordenada (2,4) medido desde la esquina arriba izquierda. Obviamente necesitas varios de estos para que la imagen sea mas dificultosa de leer. Ahora es cuando generamos nuestra imagen utilizando imagepng creamos una imagen fuera del recurso $im. Y podemos crear nuestra imagen. 

imagepng($im);

Una buena practica que debemos de tener es destruir la imagen creada, despues de que es mostrada por el navegador ya no la requerimos mas.

imagedestroy($im);

Para que la imagen sea mostrada por el navegador necesitamos enviar algunas cabeceras del tipo de contenido de imagen, en este caso png. El codigo de abajo es llamado antes de que la imagen sea enviada al navegador. Esto es antes de imagepng($im).

header('Cache-Control: no-cache, must-revalidate');
header('Content-type: image/png');

El codigo de abajo es el codigo total. Nota que agregamos todas las funciones y sus parametros discutidos anteriormente. El proposito es agregar nuestro codigo dinamico. Tambien el fondo de ruido con la funcion imagesetpixel es agregado dentro de un loop para ser llamado varias veces. y por ultimo los caracteres del captcha son agregados aleatoriamente. El captcha aleatorio es almacenado en $_SESSION['captcha_code'].

 


 <?php
 
//ancho y alto de la imagen a crear
$width = 90;
$height = 30;
 
//Cantidad de fondo para agregar el ruido a la imagen
$noise_level = 15;
 
//generamos codigo aleatorio en caso de que queramos usar numeros:
//$code=rand(1000,9999);
 
// generamos codigo aleatorio en caso de que queramos usar letras y numeros:
$chars = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
// el tamano del captcha en caracteres ?lenght=5...
$length = (isset($_GET['lenght']) && is_numeric($_GET['lenght'])) ? (int)$_GET['lenght'] : 8;

// Es agregado el captcha aleatorio en la variable $code
$code = "";
for ($i = 1; $i <= $length; $i++)
{
 $code .= $chars[mt_rand(0, strlen($chars)-1)];
}


// guardamos la sesion para la validacion del formulario
session_start();
$_SESSION["captcha_code"]=$code;
 
//creamos el recurso de imagen
$im = imagecreatetruecolor($width, $height);
$bg = imagecolorallocate($im, 230, 80, 0); //color de fondo
$fg = imagecolorallocate($im, 255, 255, 255);//color de texto
$ns = imagecolorallocate($im, 200, 200, 200);//color de ruido
 
//llenamos la imagen del color fondo
imagefill($im, 0, 0, $bg);
 
//Agregamos la cadena aleatoria a la imagen
imagestring($im, 5, 10, 8,  $code, $fg);
 
//Agregamos ruido a la imagen
for ($i = 0; $i < $noise_level; $i++) {
    for($j = 0; $j < $noise_level; $j++) {
        imagesetpixel(
            $im,
            rand(0, $width), 
            rand(0, $height),// nos aseguramos que los pixeles no se salgan de la imagen agregando sus respectivos ancho y alto
            $ns
        );
    }
}
 
//le decimos al navegador el tipo de aimgen
header("Cache-Control: no-cache, must-revalidate");
header('Content-type: image/png');
 
//generamos la imagen
imagepng($im);
 
//destruimos la imagen
imagedestroy($im);
?>


Guardamos el codigo en un archivo php como captcha.php, ahora podemos usar el archivo como recurso de imagen, us uso es simple:

<form method="post" action="">
    <img src="captcha.php">
    <input type="text" name="captcha_code">
    <input type="submit" name="enviar">
</form>



En caso de que queramos agregar menos caracteres (aunque en realidad esta funcion es irrelevante y podria causar problemas futuros), es una buena demostracion:

<form method="post" action="">
    <img src="captcha.php?lenght=4">
    <input type="text" name="captcha_code">
    <input type="submit" name="enviar">
</form>


Ahora para validar el formulario con el captcha por el lado del servidor es como lo siguiente:

    session_start();
    if (isset($_POST['enviar'])) {
        if($_POST["captcha_code"] == $_SESSION["captcha_code"] ){
            //El captcha es correcto, entonces el formulario es procesado.
            echo "Correcto!";
        }
        else{
            //Los caracteres del captcha no coinciden.
            echo "Codigo captcha incorrecto.";
        }
    }



El capcha tambien nos ayuda contra ataques de fuerza bruta como comentamos en el tutorial de seguridad de php numero 7.


Espero que este post les haya sido de utilidad.

Publicacion original: http://perials.com/tutorial-creating-image-captcha-php-using-gd-library/

No hay comentarios:

Publicar un comentario en la entrada