Question

I have 3 controllers named Site, Ads and Message. All controllers have captcha action class definition and they are allowed in accessrules of each controller.

The captcha works well in the site controller but in other controllers its validation wont work. It shows captcha image and recaptcha works too but just validation doesn't work, any idea to debug?

UPDATE :

I've probed into Yii and found something. CCaptcha widget uses controller name as a part of session key to store captcha verification code.

CCaptchaAction.php

protected function getSessionKey(){
    return self::SESSION_VAR_PREFIX . Yii::app()->getId() . '.' .   $this->getController()->getUniqueId() . '.' . $this->getId();
}

As you can see $this->getController()->getUniqueId() is a part of session key.

CCaptchaAction uses this function to generate and validate verification code.

The problem is that generation and verification occures in different controllers.

In a clear example assume we have Controllers A and B .

when captcha generation is ocuured in controller A , print_r($_SESSION) is something like :

Array ( [Yii.CCaptchaAction.12bd9136.A.captcha] => eyntri [Yii.CCaptchaAction.12bd9136.A.captchacount] => 1

and when captcha validation occures in controller B the validation method checks if

New Generated and showed code in controller B === $_SESSION[Yii.CCaptchaAction.12bd9136.A.captcha] is true or not.

And they are not equal always when generator and validator controllers are not same!!

Was it helpful?

Solution

  1. In the model validation rule specify captchaAction to point exactly to your controller captcha action:

    array('verifyCode', 'captcha', 'allowEmpty'=>!CCaptcha::checkRequirements(), 'captcaAction' => 'site/captcha'),

  2. In the view when capthca widget is used again point exactly to your controller captcha action via captchaAction:

    <?php $this->widget('CCaptcha', array('captchaAction' => 'site/captcha')); ?>

OTHER TIPS

I think my hole problem is that CCaptchaAction uses name of controller to name the session key to store verification key.

Finally As a not bad solution I overloaded CCaptchaAction by following class :

class CCaptchaActionExtension extends CCaptchaAction{
    protected function getSessionKey(){
           return self::SESSION_VAR_PREFIX . Yii::app()->getId() . '.' . $this->getId();
    }
}

And insead of CCaptchaAction I used CCaptchaActionExtention in all controllers :

    public function actions()
    {
        return array(
            'captcha'=>array(
                'class'=>'CCaptchaActionExtension',
                'backColor'=>0xFFFFFF,
            ),   
        );
    }

As you can see the new class overloads getSessionKey() method. Because name of controller had bothered me I removed it.

I don't accept my solution because I want to hear your comments about it or a new better solution ( if exists; :) )

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top