CCaptchaAction,Yii中的驗證碼工具bug修復方案


前段時間作登錄功能,涉及到了一個驗證碼的插件。想到Yii框架自帶的一個CCaptcha的擴展,輕鬆許多。 php

一、先用CActiveForm作了個登錄的表單, web

二、而後往裏面添加一個CCaptcha的widget ajax

<dl class="intxt yz">
    <dt>驗證碼:</dt>
    <dd>
        <?php
        $this->widget('CCaptcha', array(
            'imageOptions' => array('style' => 'cursor:pointer;width:70px;height:30px;display:inline-block;','id' => 'veryCode'),
            'clickableImage' => true,
            'buttonLabel' => '換一張',
        ));
        ?>
        <?php echo $form->textField($model,'verifyCode'); ?>
        <span class="msg"><i></i><?php echo $form->error($model, 'verifyCode', array('class'=>'tso'),false,false); ?></span>
    </dd>
</dl>

表單組合出來後的效果圖: session

登錄表單


看似不錯,可是測試後發現驗證碼怎麼輸入都提示錯誤。想不明白,我是徹底按照手冊API上的步驟作的,不可能會有錯誤啊。 app

百度/谷歌無果後,決定仔細看一下這個CCaptcha內部的結構。 框架

既然驗證碼只是起到一個驗證的功能,那就先看看它的驗證過程。 yii

找到 CCaptchaAction::validate()這個方法,發現有這麼一行代碼: 測試


$session[$name] = $session[$name] + 1;
if($session[$name] > $this->testLimit && $this->testLimit > 0)
        $this->getVerifyCode(true);
其中$session[$name]記錄了驗證碼的使用次數。


發現問題了,我設置了testLimit這個參數等於1。並且,登錄表單還打開了ajax驗證以及提交前驗證功能。 this

知道問題在哪了吧,testLimit表示這個驗證碼只能用一次,而表單的Ajax過程當中驗證了不少次了,致使系統中的驗證碼早就更換了,而頁面中展現的仍是第一次生成的驗證碼圖片。 spa

解決這個問題的辦法就是讓驗證碼在ajax提交的時候不執行$session[$name] = $session[$name] + 1;這一行。  


根本緣由找到後就開始解決這個問題。代碼以下:

<?php
/**
 * @author xiaobo
 * 繼承自yii自帶的CCaptchaAction
 * 若是是ajax提交則不記錄提交次數
 * example code:
class SiteController extends QController
{
    public function actions()
    {
        return array(
            // 驗證碼
            'captcha' => array(
                'class' => 'webroot.protected.extensions.captcha.glcaptchaAction',
            ),
            );
    }
}
 */
class glcaptchaAction extends CCaptchaAction
{
    public function validate($input,$caseSensitive)
    {
        $code = $this->getVerifyCode();
        $valid = $caseSensitive ? ($input === $code) : !strcasecmp($input,$code);
        $session = Yii::app()->session;
        $session->open();
        $name = $this->getSessionKey() . 'count';
        if(!Yii::app()->request->isAjaxRequest){
            $session[$name] = $session[$name] + 1;
        }
        if($session[$name] > $this->testLimit && $this->testLimit > 0){
            $this->getVerifyCode(true);
        }
        return $valid;
    }
}

?>

至此,驗證碼再也不‘飄忽不定’。一切都這麼美好!!!

相關文章
相關標籤/搜索