[李景山php]每天TP5-20170128|thinkphp5-Validate.php-1
<?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 <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace think;
use thinkFile;
use thinkRequest;
use thinkSession;
// 使用类
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);
}
}
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: 内存释放出错delete 失败 one tip
- 下一篇: delete常见错误总结