max_wen 2016-11-11 10:19:03 9801次浏览 7条评论 27 9 0

短信验证码在目前大多数web应用中都会有,本文介绍一个基于Yii2 Validator方式的验证码验证方式。
在其他文章中看到的方式大多比较难做到一次封装,多次重用。
使用此方式的好处自然不用多说,Validator支持在Model和Form中使用,使用的时候只需要在rules中添加一条验证规则即可。

第一步: 准备数据表,用来存储短信验证码

CREATE TABLE `tbl_sms_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `to` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号',
  `usage` varchar(20) NOT NULL DEFAULT '' COMMENT '用途',
  `code` varchar(6) DEFAULT NULL COMMENT '验证码',
  `result` varchar(80) DEFAULT '' COMMENT '发送结果',
  `error_code` varchar(255) DEFAULT '' COMMENT '错误码',
  `error_msg` varchar(255) DEFAULT '' COMMENT '错误信息',
  `used` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用',
  `use_time` int(11) DEFAULT '0' COMMENT '使用时间',
  `create_time` int(11) DEFAULT '0' COMMENT '发送时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8;

表结构可根据项目实际场景进行细节调整。
创建好数据表之后, 再使用Gii生成对应的Model类app\models\SmsLog

第二步: 创建短信验证码验证器, app\validators\SmscodeValidator


namespace app\validators;


use app\models\SmsLog;
use yii\validators\Validator;

/**
 * 短信验证码验证器
 * Class SmscodeValidator
 */
class SmscodeValidator extends Validator
{
	/**
         * 对应Smslog表中的usage字段,用来匹配不同用途的验证码
	 * @var string sms code type
	 */
	public $usage;
	/**
	 * Model或者form中提交的手机号字段名称
	 * @var string
	 */
	public $phoneAttribute = 'cellphone';
	/**
	 * 验证码过期时间
	 * @var int
	 */
	public $expireTime = 10800;

        /**
	 * @param \yii\base\Model $model
	 * @param string $attribute
	 */
	public function validateAttribute($model, $attribute)
	{
		$fieldName = $this->phoneAttribute;
		$cellPhone = $model->$fieldName;

		$smsLog = SmsLog::find()->where([
			'to' => $cellPhone,
			'usage' => $this->usage
		])->orderBy('create_time DESC')->one();

		/** @var $smsLog SmsLog */
		$time = time();
		if(
			is_null($smsLog) ||
			($smsLog->code != $model->$attribute) ||
			($smsLog->create_time > $time || $time > ($smsLog->create_time + $this->expireTime) )
		) {
			$this->addError($model, $attribute,'验证码有误');
		}else{
			$smsLog->used = 1;
			$smsLog->use_time = $time;
			$smsLog->save();
		}
	}


}

第三步: 使用方法, 在Model或者Form中添加Rules

例如, 在用户注册使用,前端通过ajax请求后台向指定手机号,发送了验证码
在验证的时候只需要添加一条rule:
['verifyCode', '\app\validators\SmscodeValidator', 'usage' => 'userRegister' ],

完整的rule,可以覆盖SmscodeValidator中的三个属性的值
['verifyCode', '\app\validators\SmscodeValidator', 'usage' => 'userRegister', 'phoneAttribute' => '手机号字段名称', 'expireTime' => '短信验证码有效时间' ],

RegisterForm.php

namespace mobile\models;


use yii;


class RegisterForm extends AjaxForm
{
	const  VERCODE_USAGE = 'userRegister';
	public $cellphone;
	public $verifyCode;
	public $password;

	public function rules()
	{
		return [
			[['cellphone', 'verifyCode', 'password'], 'required'],
			['verifyCode', '\common\validators\SmscodeValidator', 'usage' => self::VERCODE_USAGE ],
			['password' , 'string', 'min' => 6, 'max' => 32],

			['cellphone', 'filter', 'filter' => 'trim'],
			['cellphone', 'match', 'pattern'=>'/^1[34578][0-9]{9}$/','message'=>'请输入正确的手机号'],
			['cellphone', 'unique', 'targetClass' => '\mobile\models\User', 'message' => '此手机号已经被注册'],
		];
	}

	/**
	 * 用户注册
	 * @return User|null
	 */
	public function register()
	{
		if($this->validate()) {
			$user = new User();
			$user->cellphone = $this->cellphone;
			$user->username  = $this->cellphone;
			$user->setPassword($this->password);
			$user->cellphone_verified = 1;
			$user->create_from = Yii::$app->id;
			$user->create_ip   = Yii::$app->request->getUserIP();
			$user->create_time = time();
			if($user->save()) {
				return $user;
			}
		}
		return null;
	}

	public function attributeLabels()
	{
		return [
			'truename'  => '真实姓名',
			'cellphone' => '手机号码',
			'verifyCode' => '验证码',
			'password'  => '密码',
			'repassword' => '确认密码'
		];
	}
}

当然, 首先你得利用自己的方式(比如,前端点击form中按钮,利用Ajax请求后台发送验证码)发送验证码。
本文的主要目的是能让大家能够通过一条rule快捷实现短信验证的目的。

D02F92F8-4CF5-41FE-9F3B-EE9FC29C82B3.jpg

觉得很赞
您需要登录后才可以评论。登录 | 立即注册