短信验证码在目前大多数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快捷实现短信验证的目的。