ThinkPHP自動驗證分析

今天一起來學習下TP的自動驗證具體是怎麼實現的,首先驗證規則的定義格式如下:

// 驗證因子定義格式

array(field,rule,message,condition,type,when,params)

field:驗證字段的名稱

rule:驗證表達式

message:錯誤信息

condition:驗證條件,0存在就驗證 1 必須驗證 2值不爲空時驗證

type:驗證方式

when:什麼時候驗證 1插入時 2 更新時 3兩種情況都驗證

params:額外參數,當驗證規則類型爲function,callback等時用到


1.TP裏定義的驗證方式有哪些呢?

function,callback函數或回掉方法驗證

confirm驗證兩個字段的值是否相同

unique唯一性驗證

in, not in指定範圍驗證,逗號分隔字符串後數組

between, not between指定範圍驗證

equal, notequal值等於或不等於驗證

length長度驗證

expire有效期驗證

ip_allow,ip_deny IP驗證

regex:正則驗證

2.正則驗證TP裏定義的有哪些?

 'require'   =>  '/\S+/', //是否爲空
 'email'     =>  '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/' , //email驗證規則
 'url'       =>  '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(:\d+)?(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/' , //url規則
 'currency'  =>  '/^\d+(\.\d+)?$/' , //貨幣規則
 'number'    =>  '/^\d+$/' , //數字驗證規則
 'zip'       =>  '/^\d{6}$/', //
 'integer'   =>  '/^[-\+]?\d+$/' , //整形驗證規則
 'double'    =>  '/^[-\+]?\d+(\.\d+)?$/' , //double類型規則
 'english'   =>  '/^[A-Za-z]+$/' , //英文字母驗證

3.源碼分析

①自動錶單驗證方法 autoValidation

TP裏當調用create方法時會自動調用該方法進行自動驗證,首先看該方法的這一段:

 if( empty ($val[5]) || ( $val[5]== self:: MODEL_BOTH && $type < 3 ) || $val[5]== $type ) {
     ......
     }

這裏判斷是否需要執行驗證,如果驗證時間爲空,或者驗證時間爲3(插入和更新時都驗證)或者驗證時間等於給定的參數$type(1,2)則驗證,舉個例子

protected $_validate = array(
     array('title','require','title can not be blank'); //$val[5]爲空
     array('title','','title should be uqiue',1,'unique',1);

);

例如:if($model->create($data,1)){ .... },那麼此時表示插入時驗證,傳入2表示更新時驗證,那麼$_validate裏有對應的$val[5]值得規則就會被驗證

再來看下驗證條件

// 判斷驗證條件

 switch ($val[3]) {
    case self ::MUST_VALIDATE :   // 必須驗證 不管表單是否有設置該字段
     if (false === $this->_validationField($data,$val))
          return false ;
   break ;
   case self ::VALUE_VALIDATE :    // 值不爲空的時候才驗證
       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 ;
     }

這裏Model.class.php類裏定義了6個常量,分別是:

const MODEL_INSERT          =   1;      //  插入模型數據
const MODEL_UPDATE          =   2;      //  更新模型數據
const MODEL_BOTH            =   3;      //  包含上面兩種方式
const MUST_VALIDATE         =   1;      // 必須驗證
const EXISTS_VALIDATE       =   0;      // 表單存在字段則驗證
const VALUE_VALIDATE        =   2;      // 表單值不爲空則驗證

上面的代碼表示$val[3]如果爲1時,必須驗證 爲2時,表單字段的值不爲空時才驗證,默認是存在該字段就驗證。

②好,那麼下面來分析下具體是怎麼驗證的?

_validationField方法傳入了兩個參數,一是表單提交的數組$data,二是驗證規則數組

仔細分析下該方法裏的這段代碼:

 if( false === $this->_validationFieldItem($data,$val)){
     if ($this->patchValidate ) {//批量驗證
          $this-> error[$val[0]]   =   $val[2];
      } else {//單個驗證
          $this-> error    =   $val[2];
             return false ;
      }
  }

這裏$this->patchValidate表示是否批量處理驗證,如果爲true,則驗證不通過時返回的錯誤信息爲一數組,否則就行單個驗證,返回的錯誤信息爲字符串。

③驗證方式

_validationFieldItem方法裏定義了常見的驗證方式,像function,callback,unique,confirm等這些驗證,否則檢查附加規則

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);
       }
                 ......
     default :  // 檢查附加規則
       return $this->check($data[$val[0]],$val[1],$val[4]);
   }

     附加規則方法check裏定義裏常見的像in,not in,between,not between,equal等驗證方式,如果不符合這些驗證方式的話,默認爲regex正則驗證

④正則驗證

TP裏把驗證規則分別定義到了三個方法裏,_validationFieldItem裏定義了像function,unique這些驗證規則,check裏定義了in,not in等常見的附加規則,這些都不滿足的話則調用regex方法進行正則驗證

$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;


從源碼裏可以看出TP自己定義了一些正則驗證的規則,如果不滿足這些,那麼就要傳入自定義的正則表達式,最後執行preg_match($rule,$value)===1


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章