WebGeeker-Validation: 一个强大的 PHP 参数验证器
项目地址: github 码云
用于对API接口的请求参数进行合法性检查。
在实现服务端的API接口时,对于每一个接口的每一个参数,都应该检测其取值是否合法,以免错误的数据输入到系统中。这个工作可以说是费时费力,但又不得不做。而且PHP本身是弱类型语言,不但要验证取值,还要验证数据的类型是否符合,这就更复杂了。
本工具就是针对这个工作而设计的,能够有效地减少编码量,代码可读性好。
看看下面这段代码,可以对用法有个大概印象,应该不难看懂:
$params = $request->query(); // 获取GET参数
// 验证(如果验证不通过,会抛出异常)
Validation::validate($params, [
"offset" => "IntGe:0",
"count" => "Required|IntGeLe:1,200",
]);
支持多种数据类型的校验:整型、浮点型、bool型、字符串、数组、对象、文件、日期时间,能够验证嵌套的数据结构中的参数,还支持带条件判断的验证。
- 目录
- 1 简介
- 1.1 为什么要写这样一个工具?
- 1.2 特点
- 1.3 一个简单示例
- 2 安装
- 3 快速上手
- 3.1 一个完整的示例(不使用任何框架)
- 3.2 验证不通过的错误处理
- 3.3 在第三方框架中的用法
- 4 详细使用方法
- 4.1 验证整型参数
- 4.2 验证浮点型参数
- 4.3 验证bool型参数
- 4.4 验证字符串型参数
- 4.5 验证数组型、对象型、文件型、日期时间型参数
- 4.6 验证器串联(与)
- 4.7 Required 验证器
- 4.8 忽略所有 Required 验证器
- 4.9 嵌套参数的验证
- 4.10 条件判断型验证器
- 4.11 验证规则并联(或)
- 4.12 关于特殊值null, "",0,false的问题
- 4.13 关于基本数据类型与字符串的关系
- 4.14 自定义错误信息输出文本
- 4.15 国际化
- 4.16 国际化(0.4版之前)
- A 附录 - 验证器列表
- A.1 整型
- A.2 浮点型
- A.3 bool型
- A.4 字符串型
- A.5 数组型
- A.6 对象型
- A.7 文件型
- A.8 日期和时间型
- A.9 条件判断型
- A.10 其它验证器
1 简介
1.1 为什么要写这样一个工具?
我在使用Laravel框架的时候,Laravel提供了一个参数验证工具,不过用起来不怎么顺畅: 每一个验证都写一个验证类(继承XXX),这样太麻烦,而且系统中会多出许多许多的类;如果这些类在多处被复用,或者为了“更加”复用(减少重复代码),再在这些类之间搞出很多的继承关系,那么这些类的维护本身就是一个大问题; 验证器有“一词多义”的问题。比如它有一个size
验证器,它同时支持验证字符串、整型、文件等多种类型的参数,针对不同数据类型size
的含义不一样。这就好比你去背英语单词,有那么一些英语单词,它有很多很多意思,不同的语境下有不同的含义。比如"present"这个单词,它既有“呈现”、“出席”的意思,也有“礼物”的意思。这种一词多义的单词最让人头疼了,搞不清它到底什么意思,而且记不住啊。
为了解决这些问题,所以才写了这么一个工具。
1.2 特点
- 每个功能特性都有单元测试(共有 41 tests, 369 assertions)
- 支持无限嵌套的数据结构的验证(参考 1.3 节的例子)
- 支持条件验证,根据参数取值不同,应用不同的验证规则(参考 1.3 节的例子)
- 支持正则表达式验证
- 简洁,验证逻辑一目了然(参考后面的例子)
- 轻量,不需要定义和维护各种验证classes
- 验证器语义明确,没有“一词多义”的问题
- 易学易记。比如整型验证器都是以"Int"开头,浮点型验证器都是以"Float"开头,等等。唯一不符合这一规则的是字符串型验证器,它们一部分以"Str"开头的,但也有一部分不以"Str"开头,比如
Regexp
,Ip
,Email
,Url
等。 - 不绑定任何一个框架,无任何依赖。你可以在任何一个框架中使用这个工具,就算你不使用框架,也可以使用本工具。
1.3 一个简单示例
下面这个示例展示了一个查询获取用户投诉列表的Request参数的验证(注意其中的条件验证和针对嵌套数据结构的验证):
//验证规则
$validations = [
"offset" => "IntGe:0", // 参数offset应该大于等于0
"count" => "Required|IntGeLe:1,200", // 参数count是必需的且大于等于1小于等于200
"type" => "IntIn:1,2", // 参数type可取值为: 1, 2
"state" => [
'IfIntEq:type,1|IntEq:0', // 如果type==1(批评建议),那么参数state只能是0
'IfIntEq:type,2|IntIn:0,1,2', // 如果type==2(用户投诉),那么参数state可取值为: 1, 2, 3
],
"search.keyword" => "StrLenGeLe:1,100", // search.keyword 应该是一个长度在[1, 100]之间的字符串
"search.start_time" => "Date", // search.start_time 应该是一个包含合法日期的字符串
"search.end_time" => "Date", // search.end_time 应该是一个包含合法日期的字符串
];
// 待验证参数
$params = [
"offset" => 0, // 从第0条记录开始
"count" => 10, // 最多返回10条记录
"type" => 2, // 1-批评建议, 2-用户投诉
"state" => 0, // 0-待处理, 1-处理中, 2-已处理
"search" => [ // 搜索条件
"keyword" => '硬件故障', // 关键字
"start_time" => "2018-01-01", // 起始日期
"end_time" => "2018-01-31", // 结束日期
],
];
// 验证(如果验证不通过,会抛出异常)
Validation::validate($params, $validations);
2 安装
通过Composer安装
composer require webgeeker/validation:^0.4
3 快速上手
3.1 一个完整的示例(不使用任何框架)
这个例子直接验证$_POST
(POST表单)中的参数,展示了最基本的用法
<?php
include "vendor/autoload.php";
use WebGeekerValidationValidation;
try {
Validation::validate($_POST, [
"offset" => "IntGe:0", // 参数offset应该大于等于0
"count" => "Required|IntGeLe:1,200", // 参数count是必需的且大于等于1小于等于200
]);
} catch (Exception $e) {
echo $e->getMessage();
}
注意:验证不通过会抛出异常,该异常中包含有错误描述信息
3.2 验证不通过的错误处理
如果验证不通过,Validation::validate(...)
方法会抛出异常,建议在框架层面统一捕获这些异常,提取错误描述信息并返回给客户端。
3.3 在第三方框架中的用法
第三方框架一般会提供Request对象,可以取到GET, POST参数(以Laravel为例)
//$params = $request->query(); // 获取GET参数
$params = $request->request->all(); // 获取POST参数
// 验证(如果验证不通过,会抛出异常)
Validation::validate($params, [
// 此处省略验证规则
]);
4 详细使用方法
4.1 验证整型参数
整型验证器全部以"Int"开头,用于验证整型数值(如123
)或整型字符串(如"123"
)。其它数据类型均不匹配。
"size" => "IntGeLe:1,100"
这条验证要求参数"size"是整数,并且大于等于1,小于等于100。
完整的整型验证器的列表参考附录 A.1 。
4.2 验证浮点型参数
浮点型验证器全部以"Float"开头,用于验证浮点型数值(如1.0
)、浮点型字符串(如"1.0"
)、整型数值(如123
)或整型字符串(如"123"
)。其它数据类型均不匹配。
"height" => "FloatGeLe:0.0,100.0"
这条验证要求参数"height"是浮点数,并且大于等于0,小于等于100.0。
完整的浮点型验证器的列表参考附录 A.2 。
4.3 验证bool型参数
bool型验证器只有两个: Bool: 合法的取值为: true
, false
, "true"
, "false"
(字符串忽略大小写)。 BoolSmart: 合法的取值为: true
, false
, "true"
, "false"
, 1
, 0
, "1"
, "0"
, "yes"
, "no"
, "y"
, "n"
(字符串忽略大小写)
例
"accept" => "BoolSmart"
完整的bool型验证器的列表参考附录 A.3 。
4.4 验证字符串型参数
字符串型验证器不全以"Str"开头。只接收字符串型数据,其它数据类型均不匹配。
例1:
"name" => "StrLenGeLe:2,20"
这条验证要求参数"name"是字符串,长度在2-20之间(字符串长度是用mb_strlen()
来计算的)。
例2:
"comment" => "ByteLenLe:1048576"
这条验证要求参数"comment"是字符串,字节长度不超过1048576(字节长度是用strlen()
来计算的)。
例3:
"email" => "Email"
这条验证要求参数"email"是必须是合法的电子邮件地址。
例4(正则表达式验证):
"phone" => "Regexp:/^1(3[0-9]|4[579]|5[0-35-9]|7[0135678]|8[0-9]|66|9[89])d{8}$/"
这条验证要求参数"phone"是合法的手机号。
关于正则表达式中的哪些特殊字符需要转义的问题,只需要用 preg_match()
函数验证好,如:
preg_match('/^string$/', $string);
然后把两个'/'
号及其中间的部分拷贝出来,放在Regexp:
后面即可,不需要再做额外的转义,即使正则中有'|'
这种特殊符号,也不需要再转义。
完整的字符串型验证器的列表参考附录 A.4 。
4.5 验证数组型、对象型、文件型、日期时间型参数
参考附录A.5-A.8
4.6 验证器串联(与)
一条规则中可以有多个验证器前后串联,它们之间是“AND”的关系,如:
"file" => "FileMaxSize:10m|FileImage"
这个验证要求参数"file"是一个图像文件,并且文件大小不超过10m
4.7 Required 验证器
- Required验证器要求参数必须存在,且其值不能为
null
(这个是PHP的null
值,而不是字符串"null")(参数值为null
等价于参数不存在)。 - 如果多个验证器串联,Required验证器必须在其它验证器前面。
- 如果还有条件验证器,Required必须串联在条件验证器后面。
- 如果验证规则中没有 Required,当参数存在时才进行验证,验证不通过会抛异常;如果参数不存在,那么就不验证(相当于验证通过)
例:
"size" => "Required|StrIn:small,middle,large"
该验证要求参数"size"必须是字符串的"small", "middle"或者"large"。
4.8 忽略所有 Required 验证器
比如当创建一个用户时,要求姓名、性别、年龄全部都要提供;但是当更新用户信息时,不需要提供全部信息,提供哪个信息就更新哪个信息。
$validations = [
"name" => "Required|StrLenGeLe:2,20",
"sex" => "Required|IntIn:0,1",
"age" => "Required|IntGeLe:1,200",
];
$userInfo = [
"name" => "tom",
"sex" => "0