<?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- // | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <[email protected]> // +---------------------------------------------------------------------- namespace think; use think\File; use think\Request; use think\Session; // 使用類 class Validate { // 實例 protected static $instance;// 驗證實例 // 自定義的驗證類型 protected static $type = [];// 驗證類型 // 驗證類型別名 protected $alias = [ '>' => 'gt', '>=' => 'egt', '<' => 'lt', '<=' => 'elt', '=' => 'eq', 'same' => 'eq', ];// 別名 方式 // 當前驗證的規則 protected $rule = [];// 當前規則 // 驗證提示信息 protected $message = [];// 提示信息 // 驗證規則默認提示信息 protected static $typeMsg = [// 提示信息 'require' => ':attribute不能爲空', 'number' => ':attribute必須是數字', 'float' => ':attribute必須是浮點數', 'boolean' => ':attribute必須是布爾值', 'email' => ':attribute格式不符', 'array' => ':attribute必須是數組', 'accepted' => ':attribute必須是yes、on或者1', 'date' => ':attribute格式不符合', 'file' => ':attribute不是有效的上傳文件', 'image' => ':attribute不是有效的圖像文件', 'alpha' => ':attribute只能是字母', 'alphaNum' => ':attribute只能是字母和數字', 'alphaDash' => ':attribute只能是字母、數字和下劃線_及破折號-', 'activeUrl' => ':attribute不是有效的域名或者IP', 'chs' => ':attribute只能是漢字', 'chsAlpha' => ':attribute只能是漢字、字母', 'chsAlphaNum' => ':attribute只能是漢字、字母和數字', 'chsDash' => ':attribute只能是漢字、字母、數字和下劃線_及破折號-', 'url' => ':attribute不是有效的URL地址', 'ip' => ':attribute不是有效的IP地址', 'dateFormat' => ':attribute必須使用日期格式 :rule', 'in' => ':attribute必須在 :rule 範圍內', 'notIn' => ':attribute不能在 :rule 範圍內', 'between' => ':attribute只能在 :1 - :2 之間', 'notBetween' => ':attribute不能在 :1 - :2 之間', 'length' => ':attribute長度不符合要求 :rule', 'max' => ':attribute長度不能超過 :rule', 'min' => ':attribute長度不能小於 :rule', 'after' => ':attribute日期不能小於 :rule', 'before' => ':attribute日期不能超過 :rule', 'expire' => '不在有效期內 :rule', 'allowIp' => '不允許的IP訪問', 'denyIp' => '禁止的IP訪問', 'confirm' => ':attribute和字段 :rule 不一致', 'different' => ':attribute和字段 :rule 不能相同', 'egt' => ':attribute必須大於等於 :rule', 'gt' => ':attribute必須大於 :rule', 'elt' => ':attribute必須小於等於 :rule', 'lt' => ':attribute必須小於 :rule', 'eq' => ':attribute必須等於 :rule', 'unique' => ':attribute已存在', 'regex' => ':attribute不符合指定規則', 'method' => '無效的請求類型', 'token' => '令牌數據無效', 'fileSize' => '上傳文件大小不符', 'fileExt' => '上傳文件後綴不符', 'fileMime' => '上傳文件類型不符', ]; // 當前驗證場景 protected $currentScene = null;// 當前的驗證場景 // 正則表達式 regex = ['zip'=>'\d{6}',...] protected $regex = [];// 正則表達式規則 // 驗證場景 scene = ['edit'=>'name1,name2,...'] protected $scene = [];// 驗證場景 // 驗證失敗錯誤信息 protected $error = [];// 驗證失敗 // 批量驗證 protected $batch = false;// 批量驗證 /** * 架構函數 * @access public * @param array $rules 驗證規則 * @param array $message 驗證提示信息 */ public function __construct(array $rules = [], $message = []) { $this->rule = array_merge($this->rule, $rules);// 合併規則 $this->message = array_merge($this->message, $message);// 合併信息 }// 架構函數 進行架構規則驗證 /** * 實例化驗證 * @access public * @param array $rules 驗證規則 * @param array $message 驗證提示信息 * @return Validate */ public static function make($rules = [], $message = []) {// 實例化驗證 if (is_null(self::$instance)) {// 如果爲空 self::$instance = new self($rules, $message); } return self::$instance;// 返回 實例化 }// make 有點初始化的意味 /** * 添加字段驗證規則 * @access protected * @param string|array $name 字段名稱或者規則數組 * @param mixed $rule 驗證規則 * @return Validate */ public function rule($name, $rule = '') {// 單獨的規則添加 if (is_array($name)) {// 如果是數組 $this->rule = array_merge($this->rule, $name);// 規則 } else { $this->rule[$name] = $rule; } return $this; }// 命令鏈設置 /** * 註冊驗證(類型)規則 * @access public * @param string $type 驗證規則類型 * @param mixed $callback callback方法(或閉包) * @return void */ public static function extend($type, $callback = null) { if (is_array($type)) { self::$type = array_merge(self::$type, $type); } else { self::$type[$type] = $callback; } }// 驗證類型規則,回調函數 /** * 獲取驗證規則的默認提示信息 * @access protected * @param string|array $type 驗證規則類型名稱或者數組 * @param string $msg 驗證提示信息 * @return void */ public static function setTypeMsg($type, $msg = null) { if (is_array($type)) { self::$typeMsg = array_merge(self::$typeMsg, $type); } else { self::$typeMsg[$type] = $msg; } }// 獲取驗證規則的默認提示信息 應該是設置了, 這個團隊,太惱火了 /** * 設置提示信息 * @access public * @param string|array $name 字段名稱 * @param string $message 提示信息 * @return Validate */ public function message($name, $message = '') {// 設置提示信息 if (is_array($name)) { $this->message = array_merge($this->message, $name); } else { $this->message[$name] = $message; } return $this; }// 合併信息設置 /** * 設置驗證場景 * @access public * @param string|array $name 場景名或者場景設置數組 * @param mixed $fields 要驗證的字段 * @return Validate */ public function scene($name, $fields = null) { if (is_array($name)) { $this->scene = array_merge($this->scene, $name); }if (is_null($fields)) { // 設置當前場景 $this->currentScene = $name; } else { // 設置驗證場景 $this->scene[$name] = $fields; } return $this; }// 關於驗證場景的設置 /** * 設置批量驗證 * @access public * @param bool $batch 是否批量驗證 * @return Validate */ public function batch($batch = true) { $this->batch = $batch; return $this; }// 設置批量驗證 /** * 數據自動驗證 * @access public * @param array $data 數據 * @param mixed $rules 驗證規則 * @param string $scene 驗證場景 * @return bool */ public function check($data, $rules = [], $scene = '') {// 數據自動驗證 完成 $this->error = [];// 準備好錯誤驗證的倉庫 if (empty($rules)) {// 如果沒有單獨設置規則 // 讀取驗證規則 $rules = $this->rule;// 使用當前的規則 } // 分析驗證規則 $scene = $this->getScene($scene);// 分析驗證場景,也就是分析驗證規則 if (is_array($scene)) {// 如果是多處 場景 // 處理場景驗證字段 $change = [];// 處理分開的倉庫 $array = [];// 倉庫2 foreach ($scene as $k => $val) {// 循環場景 if (is_numeric($k)) {// 如果是數字 $array[] = $val;// 就沒有了 change } else { $array[] = $k; $change[$k] = $val;// 有這個 } } } foreach ($rules as $key => $item) {// 對全部的規則進行剖析 // field => rule1|rule2... field=>['rule1','rule2',...] if (is_numeric($key)) {// 如果 字段 是數字 // [field,rule1|rule2,msg1|msg2] $key = $item[0];// 第一個 $rule = $item[1];// 第二個 if (isset($item[2])) {// 如果還有第三個 $msg = is_string($item[2]) ? explode('|', $item[2]) : $item[2];// 對提示字符串進行處理 } else { $msg = [];// 否則信息 爲哦 } } else {// 否則這樣 $rule = $item; $msg = []; } if (strpos($key, '|')) {// 形式 // 字段|描述 用於指定屬性名稱 list($key, $title) = explode('|', $key); } else { $title = $key;// 重新處理 } // 場景檢測 if (!empty($scene)) {// 如果有場景檢測 if ($scene instanceof \Closure && !call_user_func_array($scene, [$key, $data])) { continue; } elseif (is_array($scene)) { if (!in_array($key, $array)) { continue; } elseif (isset($change[$key])) {// 重新裝載驗證規則 // 重載某個驗證規則 $rule = $change[$key]; } } } // 獲取數據 支持二維數組 $value = $this->getDataValue($data, $key);// 獲取數據 // 字段驗證 $result = $this->checkItem($key, $value, $rule, $data, $title, $msg);// 單獨的去驗證字段 if (true !== $result) {// 對驗證信息進行處理 // 沒有返回true 則表示驗證失敗 if (!empty($this->batch)) { // 批量驗證 if (is_array($result)) { $this->error = array_merge($this->error, $result); } else { $this->error[$key] = $result; } } else { $this->error = $result; return false; } } } return !empty($this->error) ? false : true; }// 這個到應該是正則應用的很好的一個案例 /** * 驗證單個字段規則 * @access protected * @param string $field 字段名 * @param mixed $value 字段值 * @param mixed $rules 驗證規則 * @param array $data 數據 * @param string $title 字段描述 * @param array $msg 提示信息 * @return mixed */ protected function checkItem($field, $value, $rules, $data, $title = '', $msg = []) { if ($rules instanceof \Closure) {// 如果規則是個 閉包函數的規則 // 匿名函數驗證 支持傳入當前字段和所有字段兩個數據 $result = call_user_func_array($rules, [$value, $data]);// 結果 直接就是 閉包返回的數據 } else { // 支持多規則驗證 require|in:a,b,c|... 或者 ['require','in'=>'a,b,c',...] if (is_string($rules)) {// 如果是個字符串 $rules = explode('|', $rules); }// 規則變成數組, $i = 0;// 標誌位 foreach ($rules as $key => $rule) {// 遍歷全部規則 if ($rule instanceof \Closure) { $result = call_user_func_array($rule, [$value, $data]);// 支持 閉包 } else { // 判斷驗證類型 if (is_numeric($key) && strpos($rule, ':')) {// 如果 是數字,也就是,沒有特殊的用法 list($type, $rule) = explode(':', $rule, 2);// 指定類型 及規則 if (isset($this->alias[$type])) {// 如果是規則的別名 // 判斷別名 $type = $this->alias[$type]; } $info = $type;// 將類型賦值給 info } elseif (is_numeric($key)) {// 如果僅僅數數字 $type = 'is'; $info = $rule; } else { $info = $type = $key; }// 否則全部相同 // 如果不是require 有數據纔會行驗證 if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) { // 驗證類型 如果是 數據 $callback = isset(self::$type[$type]) ? self::$type[$type] : [$this, $type]; // 驗證數據 $result = call_user_func_array($callback, [$value, $rule, $data, $field]);// 調用當前的驗證函數 } else { $result = true; } } if (false === $result) {// 如果結果有問題 // 驗證失敗 返回錯誤信息 if (isset($msg[$i])) { $message = $msg[$i]; } else { $message = $this->getRuleMsg($field, $title, $info, $rule); } return $message; } elseif (true !== $result) { // 返回自定義錯誤信息 return $result; } $i++; } } return true !== $result ? $result : true; }// 看來是繼續外包 /** * 驗證是否和某個字段的值一致 * @access protected * @param mixed $value 字段值 * @param mixed $rule 驗證規則 * @param array $data 數據 * @return bool */ protected function confirm($value, $rule, $data) { return $this->getDataValue($data, $rule) == $value; } /** * 驗證是否和某個字段的值是否不同 * @access protected * @param mixed $value 字段值 * @param mixed $rule 驗證規則 * @param array $data 數據 * @return bool */ protected function different($value, $rule, $data) { return $this->getDataValue($data, $rule) != $value; } /** * 驗證是否大於等於某個值 * @access protected * @param mixed $value 字段值 * @param mixed $rule 驗證規則 * @return bool */ protected function egt($value, $rule) { return $value >= $rule; } /** * 驗證是否大於某個值 * @access protected * @param mixed $value 字段值 * @param mixed $rule 驗證規則 * @return bool */ protected function gt($value, $rule) { return $value > $rule; } /** * 驗證是否小於等於某個值 * @access protected * @param mixed $value 字段值 * @param mixed $rule 驗證規則 * @return bool */ protected function elt($value, $rule) { return $value <= $rule; } /** * 驗證是否小於某個值 * @access protected * @param mixed $value 字段值 * @param mixed $rule 驗證規則 * @return bool */ protected function lt($value, $rule) { return $value < $rule; } /** * 驗證是否等於某個值 * @access protected * @param mixed $value 字段值 * @param mixed $rule 驗證規則 * @return bool */ protected function eq($value, $rule) { return $value == $rule; } /** * 驗證字段值是否爲有效格式 * @access protected * @param mixed $value 字段值 * @param string $rule 驗證規則 * @param array $data 驗證數據 * @return bool */ protected function is($value, $rule, $data = []) { switch ($rule) { case 'require': // 必須 $result = !empty($value) || '0' == $value; break; case 'accepted': // 接受 $result = in_array($value, ['1', 'on', 'yes']); break; case 'date': // 是否是一個有效日期 $result = false !== strtotime($value); break; case 'alpha': // 只允許字母 $result = $this->regex($value, '/^[A-Za-z]+$/'); break; case 'alphaNum': // 只允許字母和數字 $result = $this->regex($value, '/^[A-Za-z0-9]+$/'); break; case 'alphaDash': // 只允許字母、數字和下劃線 破折號 $result = $this->regex($value, '/^[A-Za-z0-9\-\_]+$/'); break; case 'chs': // 只允許漢字 $result = $this->regex($value, '/^[\x{4e00}-\x{9fa5}]+$/u'); break; case 'chsAlpha': // 只允許漢字、字母 $result = $this->regex($value, '/^[\x{4e00}-\x{9fa5}a-zA-Z]+$/u'); break; case 'chsAlphaNum': // 只允許漢字、字母和數字 $result = $this->regex($value, '/^[\x{4e00}-\x{9fa5}a-zA-Z0-9]+$/u'); break; case 'chsDash': // 只允許漢字、字母、數字和下劃線_及破折號- $result = $this->regex($value, '/^[\x{4e00}-\x{9fa5}a-zA-Z0-9\_\-]+$/u'); break; case 'activeUrl': // 是否爲有效的網址 $result = checkdnsrr($value); break; case 'ip': // 是否爲IP地址 $result = $this->filter($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6); break; case 'url': // 是否爲一個URL地址 $result = $this->filter($value, FILTER_VALIDATE_URL); break; case 'float': // 是否爲float $result = $this->filter($value, FILTER_VALIDATE_FLOAT); break; case 'number': $result = is_numeric($value); break; case 'integer': // 是否爲整型 $result = $this->filter($value, FILTER_VALIDATE_INT); break; case 'email': // 是否爲郵箱地址 $result = $this->filter($value, FILTER_VALIDATE_EMAIL); break; case 'boolean': // 是否爲布爾值 $result = in_array($value, [0, 1, true, false]); break; case 'array': // 是否爲數組 $result = is_array($value); break; case 'file': $result = $value instanceof File; break; case 'image': $result = $value instanceof File && in_array($this->getImageType($value->getRealPath()), [1, 2, 3, 6]); break; case 'token': $result = $this->token($value, '__token__', $data); break; default: if (isset(self::$type[$rule])) { // 註冊的驗證規則 $result = call_user_func_array(self::$type[$rule], [$value]); } else { // 正則驗證 $result = $this->regex($value, $rule); } } return $result; } // 判斷圖像類型 protected function getImageType($image) { if (function_exists('exif_imagetype')) { return exif_imagetype($image); } else { $info = getimagesize($image); return $info[2]; } } /** * 驗證是否爲合格的域名或者IP 支持A,MX,NS,SOA,PTR,CNAME,AAAA,A6, SRV,NAPTR,TXT 或者 ANY類型 * @access protected * @param mixed $value 字段值 * @param mixed $rule 驗證規則 * @return bool */ protected function activeUrl($value, $rule) { return checkdnsrr($value, $rule); } /** * 驗證是否有效IP * @access protected * @param mixed $value 字段值 * @param mixed $rule 驗證規則 ipv4 ipv6 * @return bool */ protected function ip($value, $rule) { if (!in_array($rule, ['ipv4', 'ipv6'])) { $rule = 'ipv4'; } return $this->filter($value, FILTER_VALIDATE_IP, 'ipv6' == $rule ? FILTER_FLAG_IPV6 : FILTER_FLAG_IPV4); } /** * 驗證上傳文件後綴 * @access protected * @param mixed $file 上傳文件 * @param mixed $rule 驗證規則 * @return bool */ protected function fileExt($file, $rule) { if (!($file instanceof File)) { return false; } if (is_string($rule)) { $rule = explode(',', $rule); } if (is_array($file)) { foreach ($file as $item) { if (!$item->checkExt($rule)) { return false; } } return true; } else { return $file->checkExt($rule); } } /** * 驗證上傳文件類型 * @access protected * @param mixed $file 上傳文件 * @param mixed $rule 驗證規則 * @return bool */ protected function fileMime($file, $rule) { if (!($file instanceof File)) { return false; } if (is_string($rule)) { $rule = explode(',', $rule); } if (is_array($file)) { foreach ($file as $item) { if (!$item->checkMime($rule)) { return false; } } return true; } else { return $file->checkMime($rule); } } /** * 驗證上傳文件大小 * @access protected * @param mixed $file 上傳文件 * @param mixed $rule 驗證規則 * @return bool */ protected function fileSize($file, $rule) { if (!($file instanceof File)) { return false; } if (is_array($file)) { foreach ($file as $item) { if (!$item->checkSize($rule)) { return false; } } return true; } else { return $file->checkSize($rule); } }
[李景山php]每天TP5-20170128|thinkphp5-Validate.php-1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.