Bajo este título extraño y críptico para no iniciados, se esconde un problema al que me he tenido que enfrentar estos días y para el que me ha costado mucho encontrar información.

Cuando estamos programando un formulario, nos encontramos con la necesidad de incorporar un sistema para evitar que pueda ser rellenado por ordenadores,y saturarnos así la base de datos, o el correo electrónico. Esas imágenes normalmente son letras y números que un sistema OCR no los podrá reconocer porque están deformados, o con elementos extraños que dificultan su lectura, y que muchas veces nosotros tampoco…

La cuestión es la siguiente.Para añadir una imágen de éste estilo a un formulario Yii hay multitud de ejemplos en internet, a continuación te sugiero una forma. Para gestionar un formulario que va a tener campos que se guardarán en la base de datos, y otros que nó ( por ejemplo el captcha, no se guarda en la BBDD) , podemos crear una clase nueva que extienda la clase del modelo correspondiente. En el ejemplo, haremos un registro de usuarios, por lo que extenderé la clase CUsuario, que en su momento cree con gii

class RegistrationForm extends CUsuario {

	public $password2="";
	public $verifyCode="";

y le añadirémos las reglas con las qe vamos a trabajar, definiéndolas todas, o llamando a la clase padre para reutilizar las definidas; en nuestro caso, indico las nuevas reglas que necesitamos

 array('verifyCode', 'captcha', 'allowEmpty'=>!CCaptcha::checkRequirements(),'on'=>'insert'),

Se trata de indicar que el campo verifyCode es un captcha, que solo se tendrá que filtrar cuando pueda existir (los requerimientos…) y que solo se filtra en el escenario ‘insert’. Esto último es opcional y lo comentaré más adelante. Solucionamos también el tema de las etiquetas del formulario con

	public function attributeLabels()
	{
		return array(
			'verifyCode'=>'Código comprobación',
			...,
		);
	}

Una vez finalizado nuestro modelo, podemos ir al controlador en donde añadiremos un action para reconocer el captcha:

public function actions()
    {
        return array(
            'captcha'=>array(
                            'class'=>'CCaptchaAction',
               //             'backColor'=>0x000000,
            ),
        );
    }

Aquí podéis indicar el color de fondo, el número de reintentos,… Como nuestro formulario llamará a este controlador para conseguir las imagenes, deberémos autorizarlo:

	public function accessRules()
	{
		return array(
/*			...
			array('allow',
				'actions'=>array('RegistroUsuario','captcha'),
				'expression'=>'Yii::app()->user->isGuest();'
				),
			...
			array('deny',  // deny all users
				'users'=>array('*'),
			),
		);
        }

Y todo está a punto para crear nuestro formulario. En este punto vamos a suponer, que querémos hacer la validación con AJAX a medida que nuestro visitante va rellenando los campos (exactamente, en cuanto los abandona), el motivo es que es un método muy elegante, ademas de que es el valor añadido de este artículo. para hacerlo, crearemos nuestro formulario asi:

<?php 
beginWidget('bootstrap.widgets.TbActiveForm', array(
    'id'=>'RegistroCusuario',
    'type'=>'horizontal',
    'enableAjaxValidation'=>true, <----activo la validacion ajax
)); 

textFieldRow($model, 'nombre',array('class'=>'span8')); 
textFieldRow($model, 'usuario',array('hint'=>'...'));  
textFieldRow($model, 'pass',array('class'=>'span6','hint'=>'La longitud mínima de la contraseña es de 6 caracteres')); 
... 
//-----------------inclusion de la imagen CAPTCHA
if(extension_loaded('gd')){ 
         $form->enableAjaxValidation=false;<--- DESACTIVO validacion ajax a partir de aqui
         error($model,'verifyCode'); 
         labelEx($model, 'verifyCode'); 
         widget('CCaptcha'); 
         textField($model, 'verifyCode'); 
}

Lo que debemos destacar es que activamos la validación AJAX para todo el formulario, menos para el campo CAPTCHA, ello es debido a que cada vez que se verifica el campo, se cuenta un intento, si , como es habitual, nosotros solo deseamos que se pueda hacer un intento, representará que con cada campo que validémos, nos cambiará la imágen, cosa bastante fea, por lo que optamos porque este código solo se compruebe cuando se envíe el formulario. Si tenemos un formulario con validación por AJAX, en el controlador, en el «action» que lo controla, deberemos añadir:


public function actionRegistroUsuario()
{
	$model=new RegistrationForm('insert'); 
//-------------para la validacion AJAX---------------------
	if(isset($_POST['ajax']) && $_POST['ajax']==='RegistroCusuario') <----
        {
            $model->setScenario('ajax');
            echo CActiveForm::validate(array($model));
	    Yii::app()->end();
	}
//--------------a partir de aqui, el estandar
	if(isset($_POST['RegistrationForm']))
	{
		$model->attributes=$_POST['RegistrationForm'];
		$model->setScenario('insert');
		if ($model->validate()){
		    if($model->save(false)) //el registro ya esta validado..... evita el contador captcha		
			$this->redirect(Yii::app()->getHomeUrl());
		}
	}
	$this->render('register',array(
		'model'=>$model,
	));
}

Toda la gracia del montaje, y que evita los problemas que tiene el CAPTCHA en entornos con validación AJAX, es la utilización de escenarios, si os fijáis, cuando validamos via AJAX, definimos un escenario llamado ‘ajax’;  si comprobáis las reglas de validación que le dimos al modelo, dejamos establecido que todas las validaciones se hacían en cualquier escenario, excepto la del código de verificación, que solo se hacia en el escenario ‘insert’. Eso significa que este código de verificación se ignora en las llamadas ajax, pero antes de hacer la validación de post, cambiamos el escenario, y pasamos a llamarlo ‘insert’, por lo que en la siguiente validación, si que comprobaremos la imágen. Eso es todo, puede que haya quedado un poco liado, pero quería dejarlo escrito antes de que se me olvidara, porque ya os digo que me ha costado mucho encontrarlo, y al final lo descubrí en un pequeño comentario de una pagina rusa, no me pregunteis como me aclare, pero….

2 comentarios sobre “Yii. Formulario con CAPTCHA y verificacion AJAX”

  1. deberias poner algun enlace para descargarlo y probarlo ya que no todos somos programadores, algunos solo saben lo basico y desean implementar esto en formularios de contacto.

    1. Creo que para no programadores, el intentar hacer una aplicación con Yii es un poco difícil. En este caso, tal y como describo en el articulo, se han de tocar mas de una pagina….

      Tengo otros trabajos en donde doy toda la aplicación hecha, y en un plazo corto os ofreceré un blog funcionando…

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.