解决Yii框架验证码生成后的不刷新问题

2018-09-17 10:46:40 PHP 阅读 (5493) 评论(12)

     Yii2.0是一个高效,安全,快速的PHP开发框架,内置了很多开发时常用的功能。Yii也内置了验证码功能,让我们在开发时可以直接使用,不过框架自带的验证码在生成后,无论是点击验证码还是重新请求生成验证码的URL,生成的验证码内容是没有变化的,



    这样当然是不行的啊!有问题就要解决,往下看...


1.如何生成验证码


yii框架生成验证码,只需在控制器里的actions方法里,添加一些配置就行了

public function actions()
{
    return [
        'captcha' => [
            'class' => 'yii\captcha\CaptchaAction',
            //'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
            'backColor' => 0x000000,//背景颜色
            'maxLength' => 4, //最大显示个数
            'minLength' => 4,//最少显示个数
            'padding' => 7,//间距
            'height' => 40,//高度
            'width' => 130,  //宽度
            'foreColor' => 0xffffff,     //字体颜色
            'offset' => 4,        //设置字符偏移量 有效果
        ],
    ];
}

然后再模板文件里放验证码的位置,加上


这样,在模板页面里就会生成验证码图片了

image.png

 而且呢,这个验证码的验证,也是很简单,只需要在指定的模型类中的rules中指定验证类型为验证码,接收到输入数据后,validate()就可以了

public function rules()
{
    return [        
        ['verifyCode', 'captcha','captchaAction'=>'/public/captcha', 'message'=>'验证码输入错误'],
    ];
}

    

2.问题所在:点击验证码后,验证码图片及内容刷新是常规需求,但是yii内置验证码并没有实现此功能,需要我们手动去解决

  一般的验证码刷新,都是在生成验证码的url后,拼接一些随机数字,日期什么的,如:/public/captcha?Math.random()  .再次点击时,会重新请求这个url,验证码会随之刷新。但是这样处理后,Yii框架验证码并没有刷新,这是为什么呢?

    

   看下源码就能知道问题在哪儿了:

    yii框架验证码相关的文件在 vendor/yiisoft/yii2/captcha/CaptchaAction.php,里面有一个 run 方法负责返回生成的验证码图片

    我们来分析这个方法,我直接写在注释里了

/**
 * The name of the GET parameter indicating whether the CAPTCHA image should be regenerated.
 */
const REFRESH_GET_VAR = 'refresh';

/**
 * Runs the action.
 */
public function run()
{
    //第一步先检测,请求参数里有没有self::REFRESH_GET_VAR,而这个self::REFRESH_GET_VAR是在类里定义的一个常量,值为‘refresh’
    if (Yii::$app->request->getQueryParam(self::REFRESH_GET_VAR) !== null) {
        // AJAX request for regenerating code
        //如果有这个refresh请求参数,getVerifyCode方法就生成一个验证码,记住此时这个方法的一个参数true
        $code = $this->getVerifyCode(true);
        //声明返回格式为json
        Yii::$app->response->format = Response::FORMAT_JSON;
        //返回数据
        return [
            'hash1' => $this->generateValidationHash($code),
            'hash2' => $this->generateValidationHash(strtolower($code)),
            // we add a random 'v' parameter so that FireFox can refresh the image
            // when src attribute of image tag is changed
            'url' => Url::to([$this->id, 'v' => uniqid('', true)]),//这个URL是拼接好的访问验证码图片的链接
        ];
    }
    //第二步,如果没有refresh请求参数
    $this->setHttpHeaders();
    Yii::$app->response->format = Response::FORMAT_RAW;
    //返回验证码图片,此时的getVerifyCode方法没有任何参数
    return $this->renderImage($this->getVerifyCode());
}

    我们再来看下getVerifyCode()方法的源码,同样分析写在注释里

/**
 * Gets the verification code.
 * @param bool $regenerate whether the verification code should be regenerated.
 * @return string the verification code.
 */
public function getVerifyCode($regenerate = false)
{
    //上面再配置验证码时,有一个fixedVerifyCode参数,如果有给这个参数赋值了,
    //相当于给验证码设置了一个固定的值
    //这里就直接返回配置时的固定值
    if ($this->fixedVerifyCode !== null) {
        return $this->fixedVerifyCode;
    }
    //如果没有设定固定值
    //验证码是保存到session中的
    $session = Yii::$app->getSession();
    $session->open();
    //验证码保存到session中key值,这个key是按照访问的‘控制器名’和‘方法名’进行拼接的
    $name = $this->getSessionKey();
    //判断session中是不是已经有这个key值
    //$regenerate,是否重新生成验证码,这个参数默认是false
    //就是说,当session中不存在这个key值或$regenerate为true时,就会重新生成验证码
    if ($session[$name] === null || $regenerate) {
        //generateVerifyCode()是按照配置的规则,拼接出一个验证码字符串,并存到session里
        $session[$name] = $this->generateVerifyCode();
        $session[$name . 'count'] = 1;
    }
    //返回保存在session里的验证码
    return $session[$name];
}

由上面的分析源码,可知,在没有refreshgetVerifyCode()没有传参数,也就是说程序检测到如果已经在session中已经存在验证码的key,就没有重新生成验证码,而是直接返回了,这里我打印下$_SESSION,看下保存在session中验证的验证码:

image.png

而当有refresh参数时,getVerifyCode(true)有参数true,即为重新生成一个验证码的!!!

    Are you clear? 这就是yii框架验证码不刷新的问题所在了,那怎么解决呢?


3.上面说到要有refresh参数时,验证码才会重新生成,所以就需要构造一个ajax请求,携带这个参数请求生成验证码的url(/public/captcha?refresh),然后把返回的新验证码URL给模板上验证码图片的src更换下。

//刷新验证码
        $("#verifyCode").click(function get_code(obj){
            $.ajax({
                //使用ajax请求site/captcha方法,加上refresh参数,接口返回json数据
                url: '/public/captcha?refresh',
                dataType: 'json',
                cache: false,
                success: function (data) {
                    //将验证码图片中的图片地址更换
                    $("#verifyCode").attr('src', data['url']);
                }
            });
        });


    OK。

    这样就可以点击切换验证码了。

    


评论

zpw 19-10-17 16:22:02 用TP5写的个人博客,怎么安装,数据库也没有,想参考下博主的评论代码和界面
是我 18-09-19 13:13:09 https://gitee.com/shiyilin/myblog 这里不是提供了源码吗。没提供数据库,或者安装方法 没法用

用户头像
zpw 2019-10-17 15:33:03 有视频没
用户头像
宋永胜 2018-09-19 18:15:47 这个宋永胜和shiyilin,都是我本人
用户头像
宋永胜 2018-09-19 18:14:39 我这是tp5.0写的博客啊,不是yii写的,就你说一对多的表关系,如果你对模型关联不熟悉,可以用querybuilder联表查的,效果都一样的,技术没高低之分,就看你怎么使用而已
用户头像
是我 2018-09-19 17:20:07 特别是yii的博客实战项目的视频,都没见有,
用户头像
是我 2018-09-19 17:18:13 我就想看看这评论功能,各位大佬们都怎么写的, 我这一对多不会写,脑袋疼,没想法,一片空白
用户头像
shiyilin 2018-09-19 13:42:25 首先呢,你用词“提供了源码”我这里看着有点不太对劲。我把代码托管到gitee上,是为了我开发方便版本控制,初衷并不是直接给人"提供源码"。但是如果你真的觉得我这个博客不错,想拿来研究学习什么的,可以加我qq(990375387),我把sql文件给你。
是我 18-09-18 08:43:55 用TP5写的个人博客,怎么安装,数据库也没有,想参考下博主的评论代码和界面

用户头像
shiyilin 2018-09-19 09:53:06 你想直接用我这个博客吗?
用户头像
是我 2018-09-19 07:37:23 https://sysheng.cn/category/item.html是博主你写的这个,你提供down的这个
用户头像
宋永胜 2018-09-18 09:55:51 你自己写的?还是网上down的