Yii2发送短信验证码完全解决方案

技巧库 · ruzuojun · 于 2年前 发布 · 5933 次阅读

概述

在做项目的时候,需要用到短信发送验证码功能。不能不说Yii2的牛逼,很容易就搞定了。下面我整理一下具体功能和流程,分享给大家。

主要功能

  • 通过Yii2 rules验证手机号
  • 通过js验证是否为手机号
  • 通过Ajax验证手机是否在数据库存在
  • 通过ajax发送短信验证码
  • Js倒计时功能(cookie保存信息,防刷新)
  • 通过Yii2 rules 验证手机短信码是否合法。

实现详细步骤和代码

前端表单设计,这里主要定义了手机号码filed和和发送短信的按钮 'id' =>'second'

<?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'loginMode')->hiddenInput(['value' => 'login_sms_code'])->label(false); ?>
    <div class="form-group has-feedback login-mobile f-left">
        <?= $form->field($model, 'mobile')->textInput(['placeholder' => $model->getAttributeLabel('mobile')])->label(false) ?>
        <span class="glyphicon glyphicon-phone form-control-feedback"></span>
    </div>
    <?= Html::buttonInput(Yii::t('app', 'Get SMS Code'), ['class' => 'btn bg-yellow ', 'name' => 'signup-button', 'id' => 'second']) ?>
    <div class="clear"></div>
    <div class="form-group has-feedback">
        <?= $form->field($model, 'smsCode')->textInput(['placeholder' => $model->getAttributeLabel('smsCode')])->label(false) ?>
        <span class="glyphicon glyphicon-mobile form-control-feedback"></span>
    </div>
    <div class="footer bg-gray">
        <?= Html::submitButton(Yii::t('app', 'Login'), ['class' => 'btn bg-blue btn-block']) ?>
    </div>
<?php ActiveForm::end(); ?>

当发送短信的按钮 'id'=>'second' 被点击后,会通过js验证手机的合法性,然后发送短信,并进行倒计时。具体js部分代码如下

//发送验证码时添加cookie
function addCookie(name,value,expiresHours){
    var cookieString=name+"="+escape(value);
    //判断是否设置过期时间,0代表关闭浏览器时失效
    if(expiresHours>0){
        var date=new Date();
        date.setTime(date.getTime()+expiresHours*1000);
        cookieString=cookieString+";expires=" + date.toUTCString();
    }
    document.cookie=cookieString;
}
//修改cookie的值
function editCookie(name,value,expiresHours){
    var cookieString=name+"="+escape(value);
    if(expiresHours>0){
        var date=new Date();
        date.setTime(date.getTime()+expiresHours*1000); //单位是毫秒
        cookieString=cookieString+";expires=" + date.toGMTString();
    }
    document.cookie=cookieString;
}
//根据名字获取cookie的值
function getCookieValue(name){
    var strCookie=document.cookie;
    var arrCookie=strCookie.split("; ");
    for(var i=0;i<arrCookie.length;i++){
        var arr=arrCookie[i].split("=");
        if(arr[0]==name){
            return unescape(arr[1]);
            break;
        }
    }

}

$(function(){
    $("#second").click(function (){
        sendCode($("#second"));
    });
    v = getCookieValue("secondsremained_login") ? getCookieValue("secondsremained_login") : 0;//获取cookie值
    if(v>0){
        settime($("#second"));//开始倒计时
    }
})
//发送验证码
function sendCode(obj){
    var site = 'http://yun.ucrm.com.cn/';
    var mobile = $("#loginform-mobile").val();
    //检查手机是否合法
    var result = isPhoneNum();
    if(result){
        //检查手机号码是否存在
        var exists_result = dbCheckMobileExists(site+'site/check-mobile-exists',{"mobile":mobile});
        if(exists_result){
            doPostBack(site+'sms/send-login-code',{"mobile":mobile});
            addCookie("secondsremained_login",60,60);//添加cookie记录,有效时间60s
            settime(obj);//开始倒计时
        }
    }
}

//检查手机号码是否存在
function dbCheckMobileExists(url,queryParam){
    $.ajax({
        async : false,
        cache : false,
        type : 'POST',
        url : url,// 请求的action路径
        data:queryParam,
        error : function() {// 请求失败处理函数
        },
        success:function(result){
            if(result=='Success'){
                return true;
            }
            else{
                alert('该手机号码不存在!');
                return false;
            }
        }
    });
}
//将手机利用ajax提交到后台的发短信接口
function doPostBack(url,queryParam) {
    $.ajax({
        async : false,
        cache : false,
        type : 'POST',
        url : url,// 请求的action路径
        data:queryParam,
        error : function() {// 请求失败处理函数
        },
        success:function(result){
            if(result=='Success'){
                alert('短信发送成功,验证码10分钟内有效,请注意查看手机短信。如果未收到短信,请在60秒后重试!');
            }
            else{
                alert('短信发送失败,请和网站客服联系!');
                return false;
            }
        }
    });
}

//开始倒计时
var countdown;
function settime(obj) {
    countdown=getCookieValue("secondsremained_login") ? getCookieValue("secondsremained_login") : 0;
    if (countdown ==0) {
        obj.removeAttr("disabled");
        obj.val("获取验证码");
        return;
    } else {
        obj.attr("disabled", true);
        obj.val(countdown + "秒后重发");
        countdown--;
        editCookie("secondsremained_login",countdown,countdown+1);
    }
    setTimeout(function() { settime(obj) },1000) //每1000毫秒执行一次
}
//校验手机号是否合法
function isPhoneNum(){
    var phonenum = $("#loginform-mobile").val();
    var myreg = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1}))+\d{8})$/;
    if(!myreg.test(phonenum)){
        alert('请输入有效的手机号码!');
        $("#loginform-mobile").focus();
        return false;
    }else{
        return true;
    }
}

上述代码中有两个方法是通过Ajax交互的,一个为验证手机是否合法的方法dbCheckMobileExists(),另一个是通过ajax发送短信码的方法doPostBack(). 具体每个方法的代码大家上面看就可以了。 dbCheckMobileExists()会提交到CheckMobileExists方法检查手机是否存在:

public function actionCheckMobileExists()
{
    $mobile = Yii::$app->request->post('mobile');
    if(User::findByMobile($mobile)){
        echo 'Success';
    }else{
        echo  'Failed';
    }
}

doPostBack()会提交到SendLoginCode方法发送登录验证码:

 public function actionSendLoginCode()
 {
    $mobile = Yii::$app->request->post('mobile');
    $code = $this->createCode();
    $content = "本次验证码为".$code.",您正在登录纽仁云客管理系统,打死也不告诉别人哦";
    if($this->send($mobile,$content)===true){
        //检查session是否打开
        if(!Yii::$app->session->isActive){
            Yii::$app->session->open();
        }
        //验证码和短信发送时间存储session
        Yii::$app->session->set('login_sms_code',$code);
        Yii::$app->session->set('login_sms_time',time());
        echo 'Success';
    }else{
        echo  'Failed';
    }
}

在上述发送代码的时候,当发送成功时,会保存两个session,login_sms_code和login_sms_time,分别记录了验证码内容和生成时间。

当发送成功后,用户会收到验证码,然后输入后进行提交,此时我们会进行验证码的校验,这里我们是采用yii2 rules来完成此项任务。

在 LoginForm 表的里面的 rules 里面添加下面校验规则,大家可以看到这里写了关于手机和验证码的诸多验证规则,其实最后一个验证规则即为 验证短信码是否正确,这里我们通过requiredValue验证用户输入的值是否等于 getSmsCode 的值即可。

['mobile', 'required','on' => ['default','login_sms_code']],
['mobile', 'integer','on' => ['login_sms_code']],
['mobile','match','pattern'=>'/^1[0-9]{10}$/','on' => ['default','login_sms_code'],'message'=>'{attribute}必须为1开头的11位纯数字'],
['mobile', 'string', 'min'=>11,'max' => 11,'on' => ['default','login_sms_code']],

['smsCode', 'required','on' => ['default','login_sms_code']],
['smsCode', 'integer','on' => ['default','login_sms_code']],
['smsCode', 'string', 'min'=>6,'max' => 6,'on' => ['default','login_sms_code']],
['smsCode', 'required','requiredValue'=>$this->getSmsCode(),'on' => ['default','login_sms_code'],'message'=>'手机验证码输入错误'],

上面的getSmsCode()代码如下,这里通过session获取了验证码和生成时间,如果在10分钟内,则返回验证码session的值。

public function getSmsCode()
{
    //检查session是否打开

    if(!Yii::$app->session->isActive){
        Yii::$app->session->open();
    }
    //取得验证码和短信发送时间session
    $signup_sms_code = intval(Yii::$app->session->get('login_sms_code'));
    $signup_sms_time = Yii::$app->session->get('login_sms_time');
    if(time()-$signup_sms_time < 600){
        return $signup_sms_code;
    }else{
        return 888888;
    }
}

上面为全部代码,大家可以直接使用。大家有什么问题或更好的建议可以直接在后面回帖。后续我会为大家分享更多的代码。


如果这篇文章对您有帮助,不妨微信小额赞助我一下,让我有动力继续写出高质量的教程。

本帖已被设为精华帖!
共收到 3 条回复 Yii2 短信发送 手机登录
ruzuojun#12年前 0 个赞

发短信模块使用的是 daixianceng/yii2-smser ,大家在gitbub上搜下安装即可。

forecho#22年前 0 个赞

代码还有改进的空间,判断手机号是否存在 和 是否合理 应该可以直接在 LoginForm 文件里面添加 rules 规则,然后 form 开启 Ajax 验证。就不需要自己手写 js 了。

demo#329天前 0 个赞

在actionSendLoginCode()中设置的session,然后在$this->getSmsCode()中获取的$signup_sms_code和$signup_sms_time为空值,一直想不明白,还请多多指点指点

添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册