资讯专栏INFORMATION COLUMN

WebGeeker-Validation: 一个强大的 PHP 参数验证器

zzzmh / 2713人阅读

摘要:用于对接口的请求参数进行合法性检查。唯一不符合这一规则的是字符串型验证器,它们一部分以开头的,但也有一部分不以开头,比如等。验证型参数型验证器只有两个合法的取值为字符串忽略大小写。合法的取值为字符串忽略大小写例完整的型验证器的列表参考附录。

用于对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, ""0false的问题

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表单)中的参数,展示了最基本的用法

 "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",
    "age" => "10",
];
Validation::validate($userInfo, $validations); // 创建用户时的验证

unset($userInfo["age"]); // 删除age字段
Validation::validate($userInfo, $validations, true); // 更新用户信息时的验证

注意上面代码的最后一行:validate()函数的第三个参数为true表示忽略所有的 Required 验证器。

这样我们就只需要写一份验证规则,就可以同时用于创建用户和更新用户信息这两个接口。

4.9 嵌套参数的验证

下面这个例子展示了包含数组和对象的嵌套的参数的验证:

$params = [
    "comments" => [
        [
            "title" => "title 1",
            "content" => "content 1",
        ],
        [
            "title" => "title 1",
            "content" => "content 1",
        ],
        [
            "title" => "title 1",
            "content" => "content 1",
        ],
    ]
];

$validations = [
    "comments[*].title" => "Required|StrLenGeLe:2,50",
    "comments[*].content" => "Required|StrLenGeLe:2,500",
];

Validation::validate($params, $validations);
4.10 条件判断型验证器

条件判断型验证器都以"If"开头。

比如你想招聘一批模特,男的要求180以上,女的要求170以上,验证可以这样写:

$validations = [
    "sex" => "StrIn:male,female",
    "height" => [
        "IfStrEq:sex,male|IntGe:180",
        "IfStrEq:sex,female|IntGe:170",
    ],
];

参数"sex"的值不同,参数"height"的验证规则也不一样。

完整的条件判断型验证器的列表参考附录 A.9 。

4.11 验证规则并联(或)

多条验证规则可以并联,它们之间是“或”的关系,如

"type" => [
    "StrIn:small,middle,large",
    "IntIn:1,2,3",
]

上面这条验证要求参数"type"既可以是字符串"small", "middle"或"large",也可以整型的1, 2或3

验证规则并联不是简单的“或”的关系,具体验证流程如下:

按顺序验证这些规则,如果有一条验证规则通过, 则该参数验证通过。

如果全部验证规则都被忽略(If验证器条件不满足,或者没有Required验证器并且该参数不存在,或者有0条验证规则),也算参数验证通过。

上面两条都不满足, 则该参数验证失败。

这些规则如果要完全理清并不是一件容易的事,所以不建议使用验证规则并联,也尽量不要设计需要这种验证方式的参数。

4.12 关于特殊值null, ""0false的问题

这些特殊的值是不等价的,它们是不同的数据类型(需要用不同的验证器去验证):

""是字符串。

0是整型。

false是bool型。

null是PHP的空。在本工具中它有特殊的含义。

如果某个参数的值为null,则本工具会视为该参数不存在。

比如下面两个array对于本工具来说是等价的.

$params = [
    "name" => "hello",
];

$params = [
    "name" => "hello",
    "comment" => null,
];

是等价的。

4.13 关于基本数据类型与字符串的关系

对于以下url地址

http://abc.com/index.php?p1=&&p2=hello&&p3=123

我们将得到的参数数组:

$params = [
    "p1" => "",
    "p2" => "hello",
    "p3" => "123",
];

注意

参数"p1"的值为空字符串"",而不是null

参数"p3"的值为字符串"123",而不是整型123

GET方式的HTTP请求是传递不了null值的。

本工具的所有验证器都是强类型的,"Int"验证的是整型,"Float"验证的是浮点型,"Str*"验证的是字符串型,数据类型不匹配,验证是通不过的。但是字符串类型是个例外。

因为常规的HTTP请求,所有的基本数据类型最终都会转换成字符串,所以:

整型123和字符串"123"均可以通过验证器"Int"的验证;

浮点型123.0和字符串"123.0"均可以通过验证器"Float"的验证;

bool型true和字符串"true"均可以通过验证器"Bool"的验证;

但是null值和字符串"null"永远不等价,字符串"null"就只是普通的字符串。

4.14 自定义错误信息输出文本

如果参数验证不通过,Validation::validate()方法会抛出异常,这个异常会包含验证不通过的错误信息描述的文本。

但是这个描述文本对用户来说可能不那么友好,我们可以通过两个伪验证器来自定义这些文本:

Alias 用于自定义参数名称(这个名称会与内部的错误信息模版相结合,生成最终的错误信息描述文本)

>>> 用于自定义错误描述文本(这个文本会完全取代模版生成的错误描述文本)。

看下面的例子:

$params = [
    "title" => "a",
];

Validation::validate($params, [
    "title" => "Required|StrLenGeLe:2,50",
]); // 抛出异常的错误描述为:“title”长度必须在 2 - 50 之间

Validation::validate($params, [
    "title" => "Required|StrLenGeLe:2,50|Alias:标题", // 自定义参数名称
]); // 抛出异常的错误描述为:“标题”长度必须在 2 - 50 之间

Validation::validate($params, [
    "title" => "Required|StrLenGeLe:2,50|>>>:标题长度应在2~50之间", // 自定义错误信息描述文本
]); // 抛出异常的错误描述为:标题长度应在2~50之间

参考附录A.10获取更详细的信息

4.15 国际化

从0.4版开始:

使用新的静态成员变量 $langCode2ErrorTemplates 来进行“错误提示信息模版”的翻译,主要目的是简化格式(感谢 @gitHusband 的建议)。

旧的翻译表 $langCodeToErrorTemplates 仍然有效,已有代码无需修改(参考下一节)。如果新旧翻译表同时提供,优先新的,新表中查不到再使用旧的。

要支持国际化,需要自定义一个类,继承WebGeekerValidationValidation,重载两个静态成员变量:

$langCode2ErrorTemplates用于提供“错误提示信息模版”的翻译对照表。完整的错误提示信息模版列表可以在WebGeekerValidationValidation::$errorTemplates成员变量中找到

$langCodeToTranslations用于提供“自定义参数名称”(由Alias指定)和“自定义错误描述文本”(由>>>指定)的翻译对照表。

下面提供一个示例类:

class MyValidation extends Validation
{
    // “错误提示信息模版”翻译对照表
    protected static $langCodeToErrorTemplates = [
        "zh-tw" => [
            "Int" => "“{{param}}”必須是整數", //            
               
                                           
                       
                 

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/31022.html

相关文章

  • PHP 开发者应了解 24 个库

    摘要:下面是一个例子这个库要求你至少安装了和其中的一个,这可能意味着,在大多数主机提供商提供的主机上它可能用不了。借助它,你可以忘记如何书写乏味的有一个姊妹库叫,是一个基于的实现。 showImg(http://segmentfault.com/img/bVbJml); 作为一个PHP开发者,现在是一个令人激动的时刻。每天有许许多多有用的库分发出来,在 Github 上很容易发现和使用这些库...

    0x584a 评论0 收藏0
  • jQuery Validate 表单验证强大插件

    摘要:返回为真,表示需要验证。注意在文件中添加只能包括中文字英文字母数字和下划线。中文名称返回类型描述验证所选的。检查是否验证通过。提交表单后,未通过验证的表单第一个或提交之前获得焦点的未通过验证的表单会获得焦点。 jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求。该插件捆绑了一套有用的验证方法,包括 ...

    zorpan 评论0 收藏0
  • 利用vmware搭建php开发环境

    摘要:打算探索方式,利用搭建开发环境利用搭建开发环境。第二种,基于文件共享服务安装并配置软件仓库来安装服务程序服务程序中的参数以及作用全局参数。是否所有人可见,等同于参数。 由于买不起MAC PRO,所以想研究下在windows下进行php开发的最佳方式。打算探索方式, 利用vmware搭建php开发环境; 利用docker搭建php开发环境。 在网上看到vagrant问题颇多,所以不打...

    wuyangnju 评论0 收藏0
  • 你不可不知道20个优秀PHP框架

    摘要:每一个开发者都知道,拥有一个强大的框架可以让开发工作变得更加快捷安全和有效。官方网站是一款老牌的框架,现在稳定版本已经是了。官方网站是由最大的社区之一的管理开发的,也是一个开源的框架。 对于Web开发者来说,PHP是一款非常强大而又受欢迎的编程语言。世界上很多顶级的网站都是基于PHP开发的。 每一个开发者都知道,拥有一个强大的框架可以让开发工作变得更加快捷、安全和有效。在开发项目之前选...

    zombieda 评论0 收藏0
  • Swoft 框架 1.0 正式来袭,首个基于 Swoole 原生协程 PHP 框架

    摘要:历时年多紧锣密鼓的开发,以及愉快而忙碌的春节假期,期间数从到快破,码云首页推荐,作者和社区的大力支持,正式版终于要和大家见面。此次更新新增了大量特性在易用性代码复用性能方面都有所提升。可以用于构建高性能的系统中间件基础服务等等。 历时 1 年多紧锣密鼓的开发,以及愉快而忙碌的春节假期,期间 github star 数从 500 到快破 1k,码云首页推荐,Swoole作者 Rango ...

    weij 评论0 收藏0

发表评论

0条评论

zzzmh

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<