第三方框架或程序引入ThinkPHP自动验证功能

ThinkPHP的自动验证功能很好用,可以让我们少写不少代码,但是除了ThinkPHP外,其他的框架可能没有这样的功能,那么可以通过如下的办法来引入。

1.在你的基础模型里添加如下代码:

  protected $options          =   array();
  protected $_validate        =   array();  // 自动验证定义
  protected $_auto            =   array();  // 自动完成定义
  // 最近错误信息
  protected $error            =   '';
  // 是否批处理验证
  protected $patchValidate    =   false;
  // 主键名称
  protected $pk               =   'id';
  // 验证操作状态
  const MODEL_INSERT          =   1;      //  插入模型数据
  const MODEL_UPDATE          =   2;      //  更新模型数据
  const MODEL_BOTH            =   3;      //  包含上面两种方式
  const MUST_VALIDATE         =   1;      // 必须验证
  const EXISTS_VALIDATE       =   0;      // 表单存在字段则验证
  const VALUE_VALIDATE        =   2;      // 表单值不为空则验证

  /**
   * 验证数据
   * @access public
   * @param array $data 要验证数据
   * @param array $rule 验证规则 array(验证字段,验证规则,错误提示,[验证条件,附加规则,验证时间])
   * @return mixed
   */
  public function validate($data='',$rule='',$patchValidate=false) {

      // 如果没有传值默认取POST数据
      if(empty($data)) {
          $data   =   $_POST;
      }elseif(is_object($data)){
          $data   =   get_object_vars($data);
      }
      // 验证数据
      if(empty($data) || !is_array($data)) {
          $this->error = '数据类型不合法';
          return false;
      }
      if($patchValidate===true){
          //是否批处理验证
          $this->patchValidate = true;
      }
      // 数据自动验证
      if(!self::autoValidate($data,$rule)){
          return false;
      }

      // 表单令牌验证
      // 验证完成生成数据对象
      // 创建完成对数据进行自动处理
      // 赋值当前数据对象
      // 返回创建的数据以供其他调用

      return true;
  }


  /**
   * 自动表单验证
   * @access private
   * @param array $data 创建数据
   * @param array $rule 验证规则
   * @return boolean
   */
  public function autoValidate($data,$rule='') {


      // 属性验证
      if(!empty($rule)) { // 如果设置了规则则进行数据验证
          $this->error = array(); // 保存验证错误信息

          foreach($rule as $key=>$val) {
              // 验证因子定义格式
              // array(field,rule,message,condition,type,when,params)
              // 判断是否需要执行验证
              $type = self::MODEL_UPDATE;
              if(empty($val[5]) || ( $val[5]== self::MODEL_BOTH && $type < 3 ) || $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[4]  =  isset($val[4])?$val[4]:'regex';
                  // 判断验证条件
                  switch($val[3]) {
                      case self::MUST_VALIDATE:   // 必须验证 不管表单是否有设置该字段
                          if(false === self::_validationField($data,$val))
                              return false;
                          break;
                      case self::VALUE_VALIDATE:    // 值不为空的时候才验证
                          if('' != trim($data[$val[0]]))
                              if(false === self::_validationField($data,$val))
                                  return false;
                          break;
                      default:    // 默认表单存在该字段就验证
                          if(isset($data[$val[0]]))
                              if(false === self::_validationField($data,$val))
                                  return false;
                  }
              }
          }
          // 批量验证的时候最后返回错误
          if(!empty($this->error)) return false;
      }
      return true;
  }

  /**
   * 验证表单字段 支持批量验证
   * 如果批量验证返回错误的数组信息
   * @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 === self::_validationFieldItem($data,$val)){
          if($this->patchValidate) {
              $this->error[$val[0]]   =   $val[2];
          }else{
              $this->error            =   $val[2];
              return false;
          }
      }
      return ;
  }

  /**
   * 根据验证因子验证字段
   * @access protected
   * @param array $data 创建数据
   * @param array $val 验证因子
   * @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]];
              }
              $pk =   $this->getPk();
              if(!empty($data[$pk]) && is_string($pk)) { // 完善编辑的时候验证唯一
                  $map[$pk] = array('neq',$data[$pk]);
              }
              if($this->where($map)->find())   return false;
              return true;
          default:  // 检查附加规则
              return self::check($data[$val[0]],$val[1],$val[4]);
      }
  }

  /**
   * 获取主键名称
   * @access public
   * @return string
   */
  public function getPk() {
      return $this->pk;
  }

  /**
   * 验证数据 支持 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 $_SERVER['REQUEST_TIME'] >= $start && $_SERVER['REQUEST_TIME'] <= $end;
          case 'regex':
          default:    // 默认使用正则验证 可以使用验证类中定义的验证名称
              // 检查附加规则
              return self::regex($value,$rule);
      }
  }

  /**
   * 使用正则验证数据
   * @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}(:\d+)?(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\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;
  }

  /**
   * 返回模型的错误信息
   * @access public
   * @return string
   */
  public function getError(){
      return $this->error;
  }

2.在你要验证的模型里继承该基础模型

以下是测试代码:

    $data['age'] = 10;
    $data['user_name'] = 'test001';
    $data['tel'] = '15212345678';
    $data['password'] = '123456';
    $data['repassword'] = '1234561';
    $data['email'] = '884358qq.com';

    $rules = array(
        array('user_name','','帐号名称已经存在!',0,'unique'), // 在新增的时候验证name字段是否唯一
        array('verify','require','验证码必须!'), //默认情况下用正则进行验证
        array('value',array(1,2,3),'值的范围不正确!',2,'in'), // 当值不为空的时候判断是否在一个范围内
        array('repassword','password','确认密码不正确',0,'confirm'), // 验证确认密码是否和密码一致
        array('password','checkPwd','密码格式不正确',0,'function'), // 自定义函数验证密码格式
        array('email','email','email格式不正确',0,''), // 自定义函数验证密码格式
    );

    $model = new Tests();
    $dd = $model->validate($data,$rules,true);
    var_dump($model->getError());

发表评论

邮箱地址不会被公开。 必填项已用*标注