thinkphp有一个自动验证的方法
验证规则如下
array(
array(验证字段1,验证规则,错误提示,[验证条件,附加规则,验证时间]),
array(验证字段2,验证规则,错误提示,[验证条件,附加规则,验证时间]),
......
);
注:研究源码后发现其实还有第7个参数,是给函数或者回调方法传参数用的,参数1默认为该字段值,如:
array('mobile','is_phone','手机格式不正确',1,'function','参数2,参数3')
验证支付动态和静态
静态验证
在模型类里面预先定义好该模型的自动验证规则,在使用create方法后会自动去验证。
以下是官方的例子
1.首先在模型中定义好验证的规则
namespace Home\Model;
use Think\Model;
class UserModel extends Model{
protected $_validate = array(
array('verify','require','验证码必须!'), // 都有时间都验证
array('name','checkName','帐号错误!',1,'function',4), // 只在登录时候验证
array('password','checkPwd','密码错误!',1,'function',4), // 只在登录时候验证
);
}
2.在调用的时候用create方法会自动进行验证
$User = D("User"); // 实例化User对象
if (!$User->create($_POST,4)){ // 登录验证数据
// 验证没有通过 输出错误提示信息
exit($User->getError());
}else{
// 验证通过 执行登录操作
}
动态验证
以下是官方的例子
$rules = array(
array('verify','require','验证码必须!'), //默认情况下用正则进行验证
array('name','','帐号名称已经存在!',0,'unique',1), // 在新增的时候验证name字段是否唯一
array('value',array(1,2,3),'值的范围不正确!',2,'in'), // 当值不为空的时候判断是否在一个范围内
array('repassword','password','确认密码不正确',0,'confirm'), // 验证确认密码是否和密码一致
array('password','checkPwd','密码格式不正确',0,'function'), // 自定义函数验证密码格式
);
$User = M("User"); // 实例化User对象
if (!$User->validate($rules)->create()){
// 如果创建失败 表示验证没有通过 输出错误提示信息
exit($User->getError());
}else{
// 验证通过 可以进行其他数据操作
}
下面是核心的代码分析:
create方法调用后会调用autoValidation方法,方法如下
protected function autoValidation($data,$type) {
if(!empty($this->options['validate'])) {
$_validate = $this->options['validate'];
unset($this->options['validate']);
}elseif(!empty($this->_validate)){
$_validate = $this->_validate;
}
// 属性验证
if(isset($_validate)) { // 如果设置了数据自动验证则进行数据验证
if($this->patchValidate) { // 重置验证错误信息
$this->error = array();
}
foreach($_validate as $key=>$val) {
// 验证因子定义格式
// array(field,rule,message,condition,type,when,params)
// 判断是否需要执行验证
//cqh:$val[5]为验证时间,这里判断是设置了验证时间,默认为插入和更新都验证
if(empty($val[5]) || $val[5]== self::MODEL_BOTH || $val[5]== $type ) {
if(0==strpos($val[2],'{%') && strpos($val[2],'}'))
// 支持提示信息的多语言 使用 {%语言定义} 方式
$val[2] = L(substr($val[2],2,-1));
$val[3] = isset($val[3])?$val[3]:self::EXISTS_VALIDATE;//$val[3]为验证条件
$val[4] = isset($val[4])?$val[4]:'regex';//$val[4]为验证规则,默认为正则regex
// 判断验证条件(self::EXISTS_VALIDATE|0:存在字段就验证,self::MUST_VALIDATE|1:必须验证,self::VALUE_VALIDATE|2:值不为空的时候验证
switch($val[3]) {
case self::MUST_VALIDATE: // 值为1:必须验证 不管表单是否有设置该字段
if(false === $this->_validationField($data,$val))
return false;
break;
case self::VALUE_VALIDATE: // 值为2:值不为空的时候才验证
if('' != trim($data[$val[0]]))
if(false === $this->_validationField($data,$val))
return false;
break;
default: // ,默认表单存在该字段就验证
if(isset($data[$val[0]]))
if(false === $this->_validationField($data,$val))
return false;
}
}
}
// 批量验证的时候最后返回错误
if(!empty($this->error)) return false;
}
return true;
}
以下是$this->_validationField方法,验证表单字段,并收集错误信息到$this->error属性上
/**
* 验证表单字段 支持批量验证
* 如果批量验证返回错误的数组信息
* @access protected
* @param array $data 创建数据
* @param array $val 验证因子
* @return boolean
*/
protected function _validationField($data,$val) {
if($this->patchValidate && isset($this->error[$val[0]]))
return ; //当前字段已经有规则验证没有通过
if(false === $this->_validationFieldItem($data,$val)){
if($this->patchValidate) {
$this->error[$val[0]] = $val[2];
}else{
$this->error = $val[2];
return false;
}
}
return ;
}
以下是$this-> _validationFieldItem方法,返回验证结果
/**
* 根据验证因子验证字段
* @access protected
* @param array $data 创建数据
* @param array $val 验证因子,注意:$val[6]为验证参数
* @return boolean
*/
protected function _validationFieldItem($data,$val) {
switch(strtolower(trim($val[4]))) {
case 'function':// 使用函数进行验证
case 'callback':// 调用方法进行验证
$args = isset($val[6])?(array)$val[6]:array();
if(is_string($val[0]) && strpos($val[0], ','))
$val[0] = explode(',', $val[0]);
if(is_array($val[0])){
// 支持多个字段验证
foreach($val[0] as $field)
$_data[$field] = $data[$field];
array_unshift($args, $_data);
}else{
array_unshift($args, $data[$val[0]]);
}
if('function'==$val[4]) {
return call_user_func_array($val[1], $args);
}else{
return call_user_func_array(array(&$this, $val[1]), $args);
}
case 'confirm': // 验证两个字段是否相同
return $data[$val[0]] == $data[$val[1]];
case 'unique': // 验证某个值是否唯一
if(is_string($val[0]) && strpos($val[0],','))
$val[0] = explode(',',$val[0]);
$map = array();
if(is_array($val[0])) {
// 支持多个字段验证
foreach ($val[0] as $field)
$map[$field] = $data[$field];
}else{
$map[$val[0]] = $data[$val[0]];
}
if(!empty($data[$this->getPk()])) { // 完善编辑的时候验证唯一
$map[$this->getPk()] = array('neq',$data[$this->getPk()]);
}
if($this->where($map)->find()) return false;
return true;
default: // 检查附加规则
return $this->check($data[$val[0]],$val[1],$val[4]);
}
}
以下是附加规则的方法$this->check,验证thinkphp定义好的规则
/**
* 验证数据 支持 in between equal length regex expire ip_allow ip_deny
* @access public
* @param string $value 验证数据
* @param mixed $rule 验证表达式
* @param string $type 验证方式 默认为正则验证
* @return boolean
*/
public function check($value,$rule,$type='regex'){
$type = strtolower(trim($type));
switch($type) {
case 'in': // 验证是否在某个指定范围之内 逗号分隔字符串或者数组
case 'notin':
$range = is_array($rule)? $rule : explode(',',$rule);
return $type == 'in' ? in_array($value ,$range) : !in_array($value ,$range);
case 'between': // 验证是否在某个范围
case 'notbetween': // 验证是否不在某个范围
if (is_array($rule)){
$min = $rule[0];
$max = $rule[1];
}else{
list($min,$max) = explode(',',$rule);
}
return $type == 'between' ? $value>=$min && $value<=$max : $value<$min || $value>$max;
case 'equal': // 验证是否等于某个值
case 'notequal': // 验证是否等于某个值
return $type == 'equal' ? $value == $rule : $value != $rule;
case 'length': // 验证长度
$length = mb_strlen($value,'utf-8'); // 当前数据长度
if(strpos($rule,',')) { // 长度区间
list($min,$max) = explode(',',$rule);
return $length >= $min && $length <= $max;
}else{// 指定长度
return $length == $rule;
}
case 'expire':
list($start,$end) = explode(',',$rule);
if(!is_numeric($start)) $start = strtotime($start);
if(!is_numeric($end)) $end = strtotime($end);
return NOW_TIME >= $start && NOW_TIME <= $end;
case 'ip_allow': // IP 操作许可验证
return in_array(get_client_ip(),explode(',',$rule));
case 'ip_deny': // IP 操作禁止验证
return !in_array(get_client_ip(),explode(',',$rule));
case 'regex':
default: // 默认使用正则验证 可以使用验证类中定义的验证名称
// 检查附加规则
return $this->regex($value,$rule);
}
}
以下是正则验证的方法$this->regex,返回正则验证的结果
/**
* 使用正则验证数据
* @access public
* @param string $value 要验证的数据
* @param string $rule 验证规则
* @return boolean
*/
public function regex($value,$rule) {
$validate = array(
'require' => '/\S+/',
'email' => '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',
'url' => '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/',
'currency' => '/^\d+(\.\d+)?$/',
'number' => '/^\d+$/',
'zip' => '/^\d{6}$/',
'integer' => '/^[-\+]?\d+$/',
'double' => '/^[-\+]?\d+(\.\d+)?$/',
'english' => '/^[A-Za-z]+$/',
);
// 检查是否有内置的正则表达式
if(isset($validate[strtolower($rule)]))
$rule = $validate[strtolower($rule)];
return preg_match($rule,$value)===1;
}