El helper para crear nuestros captchas en CodeIgniter 3

- Andrés Cruz

El helper para crear nuestros captchas en CodeIgniter 3

CodeIgniter cuenta con una gran cantidad de helpers y librerías tantos de terceros como propias que nos permiten emplear una gran cantidad de funcionalidades prácticamente sin hacer nada salvo crear las configuraciones necesarias para emplear dichas herramientas; una de estas herramientas que son bastante imprescindibles hoy en día son los captchas que son soportados de manera nativa (incorporado en el mismo framework) mediante la siguiente importación del helper que veremos en la siguiente sección; si no sabes que es un helper en CodeIgniter, para definir nuestras funciones o usar las de la API, revisa en enlace anterior.

Carga del helper captcha en CodeIgniter

Como siempre en CodeIgniter, para realizar una carga, hacemos lo siguiente:

$this->load->helper('captcha');

Dicha línea la podemos colocar en una clase, que heredará nuestro controlador, en cada acción o directamente en la acción de nuestro controlador; una vez realizado esto podemos crear el array de configuraciones para crear nuestro helper:

$vals = array(
	'word' => 'Random word',
	'img_path' => './assets/captcha/',
	'img_url' => base_url() . 'assets/captcha',
	'font_path' =>  './system/fonts/font.ttf',
	'img_width' => '300',
	'img_height' => 80,
	'expiration' => 7200,
	'word_length' => 15,
	'font_size' => 48,
	'img_id' => 'Imageid',
	'pool' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
	// White background and border, black text and red grid
	'colors' => array(
		'background' => array(255, 255, 255),
		'border' => array(0, 255, 255),
		'text' => array(0, 0, 0),
		'grid' => array(255, 40, 40)
	)
);
  • El parámetro word permite especificar una palabra para el captcha, en caso de no se provea CodeIgniter emplea un texto aleatorio.
  • El parámetro img_url permite especificar la carpeta para almacenar la imagen que representa al captcha.
  • El parámetro font_path nos permite personalizar el captcha con una fuente en específico mediante una ruta a la misma, como puedes ver en este ejemplo almacenamos la fuente en la carpeta system de nuestro proyecto pero puedes referenciar en otra carpeta que dispongas, por ejemplo la public, assets o cualquier en la que definas el CSS, JS, etc.
  • Con los parámetros img_width y img_height definimos el ancho y alto de la imagen en pixeles.
  • También podemos especificar un tiempo de duración de la imagen del captcha en la carpeta especificada con expiration; en caso de no ser definida la duración sería de dos horas
  • El parámetro word_length permite definir la cantidad de letras del captcha, esto solo aplica en caso de que no definieramos el parámetro word.
  • El parámetro font_size permite definir el tamaño de letra.
  • El parámetro img_id establece un identificador al tag HTML de la imagen.
  • El parámetro pool especifica el pool de las palabras, signos, etc que se emplearían para generar la palabra aleatoria del captcha.
  • El parámetro colors establecemos los colores del fondo, texto, rallado y borde de la imagen.

Finalmente, para crear y posteriormente mostrar nuestro capcha, empleamos la función create_captcha() de la siguiente manera:

 $cap = create_captcha($vals);

Lo que generará nuestro captcha y procedemos a pintarlo o establecerlo en una estructura para pasarlo a la vista, etc, en este caso solo lo mostramos por pantalla:

echo $cap['image'];

Finalmente todo el código que debemos copiar en nuestro controlador/controller:

public function captcha() {
	$this->load->helper('captcha');

	$vals = array(
		'word' => 'Random word',
		'img_path' => './assets/captcha/',
		'img_url' => base_url() . 'assets/captcha',
		'font_path' =>  './system/fonts/font.ttf',
		'img_width' => '300',
		'img_height' => 80,
		'expiration' => 7200,
		'word_length' => 15,
		'font_size' => 48,
		'img_id' => 'Imageid',
		'pool' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
		// White background and border, black text and red grid
		'colors' => array(
			'background' => array(255, 255, 255),
			'border' => array(0, 255, 255),
			'text' => array(0, 0, 0),
			'grid' => array(255, 40, 40)
		)
	);

	$cap = create_captcha($vals);
	echo $cap['image'];
}

Que mostraría una imagen como la promocional al inicio de esta entrada.

En caso de que no especifiquemos la palabra que compone al captcha, para obtener las palabras en texto plano para poder validarlos con la respuesta del usuario empleamos la siguiente asignación:

echo $cap['word'];

La función create_captcha() devuelve un array con los siguientes elementos:

array(
        'image' => IMAGE TAG
        'time'  => TIMESTAMP (in microtime)
        'word'  => CAPTCHA WORD
)

Configurando el helper del captcha con la base de datos

El propósito de los captchas no solo es generar la ya conocida imagen con los textos distorsionados, sino también de validar la respuesta de un usuario con las palabras escritas en el captcha y de esta forma "garantizar" que el internauta sea un usuario y no un robot, para eso lógicamente tenemos que comparar el texto empleado para generar el captcha con la respuesta del usuario.

Para el texto, podríamos inventarnos varias formas de tener guardado el texto empleado para generar el captcha para posteriormente compararlo con el texto suministrado por el usuario, una forma sería guárdalo en una variable en sesión; algo como lo siguiente:

$this->session->set_userdata(array(
	'captcha_texto' => $cap['word']
));

Dos formas de guardando la respuesta del captcha en base de datos

Y posteriormente consultamos dicha variable en sesión con la respuesta del usuario cuando este envía la petición del formulario.

Otra forma algo más profesional, limpia y por lo tanto más recomendada, es emplear el esquema que proponen en la documentación oficial, que es guardar dicho texto en un registro junto con el nombre de la imagen; para ello empleamos una tabla como la siguiente:

CREATE TABLE captcha (
        captcha_id bigint(13) unsigned NOT NULL auto_increment,
        captcha_time int(10) unsigned NOT NULL,
        ip_address varchar(45) NOT NULL,
        word varchar(20) NOT NULL,
        PRIMARY KEY `captcha_id` (`captcha_id`),
        KEY `word` (`word`)
);

En general, el esquema que plantean es bastante simple y muy funcional, como podemos ver en el método que genera y pinta el capcha registran la IP del usuario que consulta la web junto con el nombre de la imagen del captcha y la frase empleada para generar el mismo:

    public function captcha1() {

        $this->load->helper('captcha');

        $vals = array(
//            'word' => 'Random word',
            'img_path' => './assets/captcha/',
            'img_url' => base_url() . 'assets/captcha',
            'font_path' => './system/fonts/font.ttf',
            'img_width' => '300',
            'img_height' => 80,
            'expiration' => 7200,
            'word_length' => 15,
            'font_size' => 48,
            'img_id' => 'Imageid',
            'pool' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
            // White background and border, black text and red grid
            'colors' => array(
                'background' => array(255, 255, 255),
                'border' => array(0, 255, 255),
                'text' => array(0, 0, 0),
                'grid' => array(255, 40, 40)
            )
        );

        $cap = create_captcha($vals);

        $data = array(
            'captcha_time' => $cap['time'],
            'ip_address' => $this->input->ip_address(),
            'word' => $cap['word']
        );

        $query = $this->db->insert_string('captcha', $data);
        $this->db->query($query);

        echo 'Submit the word you see below:';
        echo $cap['image'];
        echo '/<input type="text" name="captcha" value="" />';
    }

Validando la respuesta del usuario

El siguiente método se encarga de recibir y validar los datos del usuario y de la respuesta introducida por el usuario al descifrar las letras que están en el capcha, además de realizar otras tareas:

  • El método del captcha encarga de hacer una limpieza cuya duración exceda del tiempo de vida de la imagen de los captchas que para este ejemplo es de dos horas.
  • La función se encarga de buscar coincidencias entre la frase introducida por el usuario (IP), con la del captcha, como podemos ver.

Consideraciones en el uso del captcha

El helper de captcha en CodeIgniter no buscará necesariamente por un registro del captcha para ese usuario (IP) si no, SOLO las que tengan una duración de a lo sumo dos horas (7200 segundos).

Si el usuario solicita múltiples veces el capcha (digamos tres) antes del tiempo estipulado para realizar la limpieza en la base de datos (para este ejemplo es de dos horas -7200 segundos-) dicha comprobación en base de datos se realizará con todos los registros de captchas que solicitara el usuario y generará la aplicación.

    public function captcha2() {

// First, delete old captchas
        $expiration = time() - 7200; // Two hour limit
        $this->db->where('captcha_time < ', $expiration)
                ->delete('captcha');

// Then see if a captcha exists:
        $sql = 'SELECT COUNT(*) AS count FROM captcha WHERE word = ? AND ip_address = ? AND captcha_time > ?';
        $binds = array($_POST['captcha'], $this->input->ip_address(), $expiration);
        $query = $this->db->query($sql, $binds);
        $row = $query->row();

        if ($row->count == 0) {
            echo 'You must submit the word that appears in the image.';
        }
    }

Remover antiguos capcha en cada solicitud

Si deseas que el método SOLO compare con un registro y que este sea del captcha actual, simplemente hay que eliminar todos los captchas solicitados por el usuario (IP) al momento de generar el captcha:

    public function captcha1() {

        $this->load->helper('captcha');

        $vals = array(
//            'word' => 'Random word',
            'img_path' => './assets/captcha/',
            'img_url' => base_url() . 'assets/captcha',
            'font_path' => './system/fonts/font.ttf',
            'img_width' => '300',
            'img_height' => 80,
            'expiration' => 7200,
            'word_length' => 15,
            'font_size' => 48,
            'img_id' => 'Imageid',
            'pool' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
            // White background and border, black text and red grid
            'colors' => array(
                'background' => array(255, 255, 255),
                'border' => array(0, 255, 255),
                'text' => array(0, 0, 0),
                'grid' => array(255, 40, 40)
            )
        );

        $cap = create_captcha($vals);

        $data = array(
            'captcha_time' => $cap['time'],
            'ip_address' => $this->input->ip_address(),
            'word' => $cap['word']
        );

        $this->db->where('ip_address = ', $this->input->ip_address())
                ->delete('captcha');

        $query = $this->db->insert_string('captcha', $data);
        $this->db->query($query);

        echo 'Submit the word you see below:';
        echo $cap['image'];
        echo '/>input type="text" name="captcha" value="" />';
    }

Obviamente debemos colocar las consultas en los modelos, crear las vistas para mostrar el captcha y la respuesta del mismo; pero la idea del código anterior es mostrar la idea en general sin que se complique con otros detalles de menor importancia.

Puedes consultar la documentación oficial en el siguiente enlace: CAPTCHA Helper CodeIgniter.

La tabla de los captchas es la siguiente:

CREATE TABLE captcha (
        captcha_id bigint(13) unsigned NOT NULL auto_increment,
        captcha_time int(10) unsigned NOT NULL,
        ip_address varchar(45) NOT NULL,
        word varchar(20) NOT NULL,
        PRIMARY KEY `captcha_id` (`captcha_id`),
        KEY `word` (`word`)
);
Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy

Acepto recibir anuncios de interes sobre este Blog.