Crear un generador de Captcha en PHP

Formulario de verificación de Captcha

Formulario de verificación de Captcha

Un Captcha es el acrónimo en ingles de Prueba de Turing pública y automática para diferenciar máquinas y humanos (Completely Automated Public Turing test to tell Computers and Humans Apart), como su nombre lo indica es una prueba lógica que un humano debe poder pasar sin esfuerzo, pero una máquina no sabe como interpretar tal prueba o no logra contestar correctamente.

 

El captcha es utilizado para evitar que robots o spambots puedan hacer uso de servicios de nuestro sitio web, por ejemplo crear infinidad de usuarios, contestar mas de una ves una encuesta, enviar mensajes con spam o cualquier otro servicio disponible.

Clase para generar captcha en PHP – Podemos crear el archivo llamado «clase_captcha.php»

<?php

/*
 * Clase para crear captcha dando la calve y tamaño deseado
 */

class Captcha
{
    // Tipos de fuentes para utilizar
    var $fuentes = array(
                        array("f" => "ididthis.ttf", "t" => "14"),
                        array("f" => "edosz.ttf", "t" => "18")
                    );

    // Se inicia el captcha
    function Captcha()
    {
        $this->fondo = array(255, 255, 255);
        $this->frente = array(0, 0, 128);
    }

    // Se genera la imagen del captcha
    function generar_captcha($clave, $tam_x = 120, $tam_y = 70)
    {
        // Se toma un tipo de fuente de forma aleatoria
        $rand_fuente = rand(0, count($this->fuentes) - 1);
        $fuente = $this->fuentes[$rand_fuente]["f"];
        $tam_fuente = $this->fuentes[$rand_fuente]["t"];

        // Envio del header de imagen en formato PNG
        header("Content-type: image/png");

        // Validar que se puede crear una imagen (requiere GD)
        if (function_exists("imagecreatetruecolor"))
        {
            $imagen = imagecreatetruecolor($tam_x, $tam_y);
        }
        else
        {
            $imagen = imagecreate($tam_x, $tam_y) or die ("No se puede iniciar GD para crear una imagen");
        }

        // Si existe el Anti-Alias se activa en la imagen
        if (function_exists("imageantialias"))
        {
            imageantialias($imagen, true);
        }

        // Se toman de forma aleatoria los colores de fondo (claro) y texto (oscuro)
        $this->fondo = imagecolorallocate($imagen, rand(224, 256), rand(224, 256), rand(224, 256));
        $this->frente = imagecolorallocate($imagen, rand(0, 4), rand(0, 4), rand(64, 128));

        // Se rellena la imagen con el color de fondo
        imagefill($imagen, 0, 0, $this->fondo);

        // Se genera un angulo aleatorio para girar el texto
        $maximo_angulo = 30;
        $angulo = rand(-100 * $maximo_angulo, 100 * $maximo_angulo) / 100.0;

        // Se coloca el texto en la imagen con su color, tipo de fuente y angulo
        if (function_exists("imagettftext") && $fuente != "")
        {
            $caja_texto = imagettfbbox($tam_fuente, $angulo, $fuente, $clave);
            $min_x = min($caja_texto[0], $caja_texto[2], $caja_texto[4], $caja_texto[6]);
            $max_x = max($caja_texto[0], $caja_texto[2], $caja_texto[4], $caja_texto[6]);
            $min_y = min($caja_texto[1], $caja_texto[3], $caja_texto[5], $caja_texto[7]);
            $max_y = max($caja_texto[1], $caja_texto[3], $caja_texto[5], $caja_texto[7]);
            $x = max(0, ($caja_texto[0] - $min_x) + rand(0, $tam_x - ($max_x - $min_x)));
            $y = max(0, ($caja_texto[1] - $min_y) + rand(0, $tam_y - ($max_y - $min_y)));
            imagettftext($imagen, $tam_fuente, $angulo, $x, $y, $this->frente, $fuente, $clave);
        }
        else
        {
            imagestring($imagen, 5, rand(0, $tam_x - 65), rand(0, $tam_y - 15), $clave, $this->frente);
            if (function_exists("imagerotate"))
            {
                $imagen = imagerotate($imagen, $angulo, $this->fondo);
            }
        }

        // Se agregan lineas para dificultar la lectura del texto (para evitar el uso de bots)
        $this->generar_ruido($imagen, (int)($tam_x / 15), 'x');
        $this->generar_ruido($imagen, (int)($tam_y / 15), 'y');

        // Se crea y muestra la imagen
        imagepng($imagen);
    }

    // Se generan lineas de ruido a una imagen, se puede especificar la cantidad y eje donde se colocaran
    function generar_ruido($imagen, $cantidad = 5, $rango = 'y')
    {
        // Se toma el tamaño de la imagen
        $x = imagesx($imagen);
        $y = imagesy($imagen);

        // Se crean las lineas de ruido deseadas
        for ($i = 0; $i < $cantidad; $i++)
        {
            // Se toma un color aleatorio (entre claro y oscuro)
            $color = imagecolorallocate($imagen, rand(64, 192), rand(64, 192), rand(64, 192));

            // Se colocan las lineas en un eje de forma aleatoria
            if ($rango == 'y')
            {
                $linea = rand(0, $x);
                imageline($imagen, $linea, 0, $linea + rand(-10, 10), $y, $color);
            }
            else
            {
                $linea = rand(0, $y);
                imageline($imagen, 0, $linea, $x, $linea + rand(-10, 10), $color);
            }
        }
    }
}

?>

Modo de uso de la clase – Podemos crear el archivo «captcha.php»

<?php

// Incluir la clase captcha para su utilización
include("clase_captcha.php");

// Clave a colocar en el captcha
$clave= "ELHAPPY";  // Se puede cambiar por una función para generar claves

// Crear un captcha de 120x70
$captcha = new Captcha();
$captcha->generar_captcha($clave, 120, 70);

?>

Lo que se debe de tener muy en cuenta al momento de crear captchas es que se generen de manera aleatoria y dinámica, para evitar tener siempre la misma como «ELHAPPY».

Función para generar claves aleatorias – Podemos colocarlo en el mismo archivo donde se manda llamar al captcha

/*
 * Genera una clave aleatoria de X a Y números de caracteres
 *
 * Ejemplo:  generar_clave(10, 12)
 */
function generar_clave($minimo = 6, $maximo = 8)
{
    $clave = "";
    $caracteres = "ABCDEFGHIJKLMNOPRSTUVWXYZ";

    for ($i = 0; $i < rand($minimo, $maximo); $i++)
    {
        $clave .= $caracteres[rand(0, strlen($caracteres) - 1)];
    }

    return $clave;
}

Seria mejor mandar por un GET la clave que se va a utilizar para que se pueda generar la imagen directamente desde el mismo archivo PHP.

Para facilitarles el entendimiento de como poder generarlos y verificar los captchas, pueden descargar los archivos donde ya les dejo un formulario de ejemplo de como pueden utilizarlo.

Espero que les sea de utilidad y si encuentran alguna mejora o algún problema, háganme lo saber.

Sitio | Prueba en linea

Descarga | Archivos de ejemplo (ZIP, 34.8 KB)

3 comentarios en “Crear un generador de Captcha en PHP

  1. He cogido tu ejemplo, todo parece funcionar pero las letras no se me muestran, en cambio la imagen sí. Espero una respuesta. Un saludo

  2. Que tal Dani, primero que nada te recomiendo activar en la configuración de PHP que se muestren los errores, para facilitar el debugeo al desarrollar.

    Con respecto al error, al parecer no se encuentra el archivo con la fuente para el texto, eso se soluciona colocando la ruta hacia el o los archivos, de todas formas actualice el ejemplo para que funcione correctamente.

    Gracias por el aviso del error, saludos.

Deja un comentario