[SOLVED] Trying to write a CReCaptcha widget + CReCaptchaValidator

Hi, I want to use reCAPTCHA as my CAPTCHA. I already have ported a Prado 2 component to a Yii widget for the thing which renders the code (attached, BTW does magic setters and getters work with widgets?), which is the very basic renderer (I don't use the API for customization). This widget (reCAPTCHA, actually) generates the next HTML code:

<script type="text/javascript" src="http://api.recaptcha.net/challenge?k=[publickey]"></script>


	<noscript>


  		<iframe src="http://api.recaptcha.net/noscript?k=[publickey]" height="300" width="500" frameborder="0"></iframe><br/>


  		<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>


  		<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>


	</noscript>

Then, the reCAPTCHA validation API requires you to do this:

protected function revalidate($key,$client,$challenge,$response)


{


   $resp = recaptcha_check_answer($key,$client,$challenge,$response);


   return $resp->is_valid;


}

and then Yii's validators work with this (copied from CCaptchaValidator):

protected function validateAttribute($object,$attribute)


{


   $value=$object->$attribute;


   if($this->allowEmpty && ($value===null || $value===''))


      return;


   if(!$this->revalidate($this->privateKey,


                                $_SERVER['REMOTE_ADDR'],


                                $_POST['recaptcha_challenge_field'],


                                $_POST['recaptcha_response_field'])) {


      $message=$this->message!==null?$this->message:Yii::t('yii','The verification code is incorrect.');


      $this->addError($object,$attribute,$message);


   }


}

and this is where the wall appears: how would I trigger this validator, if it’s not linked to anything in the model…  :-\  ???

The standard way of performing validation is to define a form model and declare validations in it.

If you do not want to do this, you will need to manually call the validation method when the form is posted.

Ok, solved the problem with an activeHiddenField. Attached is the new CReCaptcha and the CReCaptchaValidator. Usage:

In the model

   public function rules()


   {


      return array(


         array('validacion','system.validators.CReCaptchaValidator','privateKey'=>'<privatekey>'),


      );


   }

In the view:



<? echo CHtml::activeLabel($user, Yii::t('demo', 'validacion')); ?>


<? $this->widget('system.web.widgets.CReCaptcha', array('model'=>$user, 'attribute'=>'validacion', 'theme'=>'blackglass', 'publicKey'=>'<publickey>')) ?>

My question is just this next: will be possible to use magic setters and getters in widgets? ::) It seems that they’re not working (or am I doing something wrong ??? )

Looks good.

Yes, you can use magic getter/setter anywhere. What problem did you encounter?

One suggestion: Please use a different prefix other than 'C'. Otherwise, you may encounter naming conflict if in future Yii includes the same class in the core release. You should also not use the alias 'system.validators.CReCaptchaValidator'.

Using 'application.extensions.recaptcha.ReCaptchaValidator' is more appropriate, assuming you are releasing it as an extension.

Quote

Looks good.

Thanks.

Quote

Yes, you can use magic getter/setter anywhere. What problem did you encounter?

Well, in [tt]CReCaptcha[/tt] I have a [tt]public $language[/tt] property, and this method:

	public function setLanguage($value)


	{


	   $suffix = empty($value) ? 'en' : (($p=strpos($value,'_'))!==false) ? strtolower(substr($value,0,$p)) : strtolower($value);


      if (in_array($suffix, $this->validLanguages)) $this->language = $suffix;


	}

which is never executed. I assume then that I'm doing something wrong… but can't find out what…

Quote

One suggestion: Please use a different prefix other than 'C'. Otherwise, you may encounter naming conflict if in future Yii includes the same class in the core release. You should also not use the alias 'system.validators.CReCaptchaValidator'.

Using 'application.extensions.recaptcha.ReCaptchaValidator' is more appropriate, assuming you are releasing it as an extension.

Well, it depends: if you decide to include it in the core, go ahead. If you prefer to accept it as an extension, I can do the changes and resubmit it ;)

You should not define a public member variable while defining a getter/setter for it because the getter/setter won't get chance to be invoked. In your case, define language as a private member, and define a getter function for it.

Yes, please rename the classes. We can always rename them back to "C" when we decide to include them into core release.

Quote

You should not define a public member variable while defining a getter/setter for it because the getter/setter won't get chance to be invoked. In your case, define language as a private member, and define a getter function for it.

I was missing that. Thanks.

Quote

Yes, please rename the classes. We can always rename them back to "C" when we decide to include them into core release.

Done. Posted in Extensions.