Show image verify code more humane by CModel::scenario attribute.

Note: these code is for the Yii-1.1.x, if you are using Yii-1.0.x, you should modify the part 4, pass into the secnario parameter.

This implementation seems clumsy, if you have a better way, tell me please, thanks you!


  1. Specify the scenario name in the action of controller.

function actionLogin()

   {

     ...

     $model = new User;

     $model->setScenario('login');

     ...

   }

  1. Add the validate rule for Model class

public function rules()

   {

      return array(

        array('verifyCode', 'safe'),

        array('verifyCode', 'captcha', 'allowEmpty'=>false, 'captchaAction'=>'site/captcha', 'on'=>'login2'),

      ...

   }

  1. Add a public method to check whether the image verify code is required or not.

public function isReqCaptcha()

   {

     if ($this->getSecnario() == 'login' || $this->getSecnario() == 'login2')

     {

       $logCaptchaed = Yii::app()->user->getState('logCaptchaed');

         if ($logCaptchaed > 2) // failed 3 times

           return true;

     }

     return false;

   }

  1. Overwrite the validate() and afterValidate() of the Model:

public function validate($attributes = NULL)

   {

     $scenario = $oldscenario = $this->getScenario();

  

     // change the scenario to force check verify code...

     if ($scenario == 'login' && $this->isReqCaptcha())

	$scenario .= '2';

     $this->setScenario($scenario);

     $ret = parent::validate($attributes);


     // resotre the scnario value

     $this->setScenario($oldscenario);

     return $ret;

   }


   protected function afterValidate()

   {

     if ($this->getScenario() == 'login' || $this->getSecnario() == 'login2')

     {			

       if ($this->isReqCaptcha())

       {

         if (!$this->hasErrors('verifyCode'))    // correct verify code, reset!

           Yii::app()->user->setState('logCaptchaed', 0);

       }

       else

       {

         $logCaptchaed = Yii::app()->user->getState('logCaptchaed');

         Yii::app()->user->setState('logCaptchaed', $this->hasErrors() ? ($logCaptchaed + 1) : 0);

       }

     }

     parent::afterValidate();

   }

  1. Add the condition code to show verify code in View file of login action:



<?php if ($model->isReqCaptcha()) { ?>

<div class="simple">

	<?php echo CHtml::activeLabel($model, 'verifyCode'); ?>

	<div>

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

		<?php echo CHtml::activeTextField($model, 'verifyCode'); ?>

	</div>

</div>

<?php } ?>