在Web应用开发中,数据验证是确保数据合法性、完整性与安全性的关键环节。ThinkPHP 内置的验证器组件提供了一套声明式、高可读的验证机制,能够将繁琐的数据校验逻辑封装为简洁的规则定义,有效提升代码的健壮性与开发效率。本文将集中学习验证器的核心用法,涵盖验证规则的定义与组合、错误信息的定制与获取、验证场景的灵活切换、验证分组的精细管理、路由中便捷的验证调用、丰富内置规则的选用,以及防范重复提交的表单令牌机制。掌握这些内容,将帮助我们为应用构建起简洁而可靠的数据验证层。
[1、添加令牌 Token 验证](#1、添加令牌 Token 验证)
验证
think-validate 是一个基于 PHP8.0 的数据验证类库,最新版本已经从 ThinkPHP 核心独立出来单独维护更新,以优异的功能和突出的性能著称,提供了更优秀的性能和开发体验。使用 ThinkPHP 框架的话,无需额外安装会自动依赖。
主要特性:
- 基于 PHP8 和强类型实现
- 内置丰富的验证规则
- 支持验证器类、数组和链式方法定义验证规则
- 支持验证场景
- 支持独立数据验证
- 支持枚举验证
- 支持批量验证
- 支持抛出异常
一、验证器
ThinkPHP 推荐使用验证器来解决各种验证场景和需求。
1、验证器定义
为具体的验证场景或者数据表定义好验证器类,直接调用验证类的 check 方法即可完成验证。我们可以使用下面的指令快速生成验证器:
bash
php think make:validate 验证器名称
例如,现在使用该命令快速生成 User 验证器:
bash
php think make:validate User
执行该命令后,会自动创建 \app\validate\User 验证器类用于 User 的验证。
现在我们来看一下生成的 User 验证器类的内容:
php
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
/**
* 定义验证规则
* 格式:'字段名' => ['规则1','规则2'...]
*
* @var array
*/
protected $rule = [];
/**
* 定义错误信息
* 格式:'字段名.规则名' => '错误信息'
*
* @var array
*/
protected $message = [];
}
可以看到,代码中已经给出了十分清楚的注释。rule 属性用于定义验证规则,message 属性定义错误提示信息。
下面我们来定义验证器类 User 的验证规则和对应的错误提示信息:
php
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
/**
* 定义验证规则
* 格式:'字段名' => ['规则1','规则2'...]
*
* @var array
*/
protected $rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email'
];
/**
* 定义错误信息
* 格式:'字段名.规则名' => '错误信息'
*
* @var array
*/
protected $message = [
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄只能在1-120之间',
'email' => '邮箱格式错误'
];
}
如果没有定义错误提示信息,则使用系统默认的提示信息。
2、数据验证
这里以控制器验证为例(这是官方推荐的验证方式)进行说明验证器的用法,在需要进行 User 验证的控制器方法中,添加如下代码即可:
php
<?php
namespace app\controller;
use app\BaseController;
use app\validate\User;
use think\exception\ValidateException;
class Index extends BaseController
{
public function index()
{
try {
validate(User::class)->check([
'name' => 'zhangsan',
'email' => 'email',
]);
} catch (ValidateException $e) {
// 验证失败
dump($e->getError()); // 输出错误信息
dump($e->getKey()); // 验证错误的字段名
}
}
}
验证失败会显示对应的错误信息。需要说明一点的是,只会显示第一个验证失败的错误信息,不会将所有的验证失败信息进行展示。例如,name 属性和 email 属性都验证失败,则只显示第一个 name 属性的错误信息,不会显示 email 属性的错误信息。
如果没有定义验证器,也可以通过 validate 方法进行自定义验证规则:
php
<?php
namespace app\controller;
use app\BaseController;
use app\validate\User;
use think\exception\ValidateException;
class Index extends BaseController
{
public function index()
{
try {
validate([
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email',
])->message([
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄只能在1-120之间',
'email' => '邮箱格式错误',
])->check([
'name' => 'zhangsan',
'email' => 'email',
]);
} catch (ValidateException $e) {
// 验证失败
dump($e->getError()); // 输出错误信息
dump($e->getKey()); // 验证错误的字段名
}
}
}
二、验证规则
验证规则可以通过字符串、数组、闭包和规则类四种方式进行定义。在验证器中,只能使用前两种方式,而闭包和规则类的定义则适用于使用 rule 方法来动态定义验证规则。
1、属性定义
属性定义方式仅限于验证器,通常类似于下面的方式,在 rule 属性中定义验证规则:
php
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email'
];
}
系统内置了一些常用的验证规则可以满足大部分的验证需求,具体每个规则的含义稍后会进行说明。
因为一个字段可以使用多个验证规则(如上面的 age 字段定义了 number 和 between 两个验证规则),在一些特殊的情况下,为了避免混淆可以在 rule 属性中使用数组定义规则。
php
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => ['require', 'max' => 25, 'regex' => '/^[\w|\d]\w+/'],
'age' => ['number', 'between' => '1,120'],
'email' => 'email'
];
}
2、方法定义
方法定义功能需要 V8.1.2+ 版本支持。
可以通过进入 ThinkPHP 应用程序的根目录,执行以下命令来查看当前使用的版本。
bashphp think version
属性定义存在局限性,因此如果需要定义一些特殊的验证规则,可以改成方法定义。
php
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected function rules()
{
return [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email'
];
}
}
可以在 rules 方法里面返回数组或当前对象,区别在于使用返回数组方式,rule 属性定义的验证规则不再生效。而对象方式的 rules 定义规则会和 rule 属性定义的合并(存在相同的字段则会覆盖)。
php
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected function rules()
{
return $this
->rule('name', 'require|max:25', ['require' => '名称必须', 'max' => '名称最多不能超过25个字符'])
->rule('age', 'number|between:1,120', ['number' => '年龄必须是数字', 'between' => '年龄只能在1-120之间'])
->rule('email', 'email', '邮箱格式错误');
}
}
如果没有使用验证器而是独立验证(即手动调用验证类进行验证)方式的话,通常使用 rule 方法进行验证规则的设置。独立验证通常使用 Facade 或者自己实例化验证类。
php
<?php
namespace app\controller;
use app\BaseController;
use think\facade\Validate;
class Index extends BaseController
{
public function index()
{
// rule 方法传入数组表示批量设置规则
$validate = Validate::rule('age', 'number|between:1,120')
->rule([
'name' => 'require|max:25',
'email' => 'email'
]);
$data = [
'name' => 'zhangsan',
'email' => 'email'
];
if (!$validate->check($data)) {
dump($validate->getError());
}
}
}
rule 方法还可以支持使用对象化的规则定义,上面的验证代码可以更改改为:
php
<?php
namespace app\controller;
use app\BaseController;
use think\facade\Validate;
use think\validate\ValidateRule as Rule;
class Index extends BaseController
{
public function index()
{
$validate = Validate::rule('age', Rule::isNumber()->between([1, 120]))
->rule([
'name' => Rule::isRequire()->max(25),
'email' => Rule::isEmail(),
]);
$data = [
'name' => 'zhangsan',
'email' => 'email'
];
if (!$validate->check($data)) {
dump($validate->getError());
}
}
}
3、闭包定义
可以对某个字段使用闭包验证,例如:
php
$validate = Validate::rule([
'name' => function($value) {
return 'zhangsan' == strtolower($value) ? true : false;
}
]);
$data = ['name' => 'lisi'];
if (!$validate->check($data)) {
dump($validate->getError());
}
闭包支持传入两个参数,第一个参数是当前字段的值(必须) ,第二个参数是所有数据(可选)。
如果使用了闭包进行验证,则不再支持对该字段使用多个验证规则。
闭包函数如果返回 true 则表示验证通过,返回 false 表示验证失败并使用系统的错误信息;如果返回字符串,则表示验证失败并且以返回值作为错误提示信息。
php
$validate = Validate::rule([
'name' => function($value) {
return 'zhangsan' == strtolower($value) ? true : '用户名错误';
}
]);
4、规则别名
该功能需要 V8.1.2+ 版本支持。
可以使用 alias 属性给一些常见的规则定义别名,方便复用。
php
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $alias = [
'name' => 'require|alphaNum|max:25',
'age' => 'number|between:1,120'
];
protected $rule = [
// 使用规则别名
'name' => 'name',
'age' => 'age',
'email' => 'email'
];
}
规则别名对应的规则可以是任何有效的规则定义,包括字符串和数组方式。
5、数组验证
本功能需要 V8.1.0+ 版本支持。
支持对数组元素进行验证
php
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
// info是一个索引数组
'info.email' => 'email',
'info.score' => 'number'
];
}
也支持对多维数组进行验证。
php
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
// info是一个二维数组
'info.*.email' => 'email',
'info.*.score' => 'number'
];
}
6、批量验证
默认情况下,一旦有某个数据的验证规则不符合,就会停止后续数据及规则的验证,如果希望批量进行验证,可按如下方式设置:
php
<?php
namespace app\controller;
use app\BaseController;
use app\validate\User;
use think\exception\ValidateException;
class Index extends BaseController
{
public function index()
{
try {
// batch(true):batch方法传入true,代表进行批量验证
validate(User::class)->batch(true)->check([
'name' => '',
'age' => 'abc'
]);
} catch (ValidateException $e) {
// 验证失败 输出错误信息
// 错误信息是一个包括字段名和错误信息的数组
dump($e->getError());
dump($e->getKey());
}
}
}
7、自定义验证规则
系统内置了一些常用的规则(后文会进行说明),如果不能满足需求,可以在验证器单独添加额外的验证方法。例如:
php
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'checkName:zhangsan',
'email' => 'email'
];
protected $message = [
'email' => '邮箱格式错误'
];
// 自定义验证规则
protected function checkName($value, $rule, $data=[])
{
return $rule == $value ? true : '名称错误';
}
}
验证方法可以传入的参数共有 5 个(后面三个根据情况选用),依次为:
- 验证数据
- 验证规则
- 全部数据(数组)
- 字段名
- 字段描述
自定义的验证规则方法名不能和已有的规则冲突,并且必须使用驼峰命名规范。
8、独立验证
对数据进行相关规则的验证,不需要使用验证器。
php
use think\facade\Validate;
Validate::checkRule('test', 'email')
checkRule 方法返回布尔值,验证成功返回 true,否则返回 false,可以支持传入多个验证规则。
三、错误信息
验证规则的错误提示信息有三种定义方式。文章这里只记录两种方式,因为第三种是多语言方式,日常开发当中并不涉及多语言的内容,所以在这里就不作记录了,毕竟是以常用的快速开发为主,所以不需要的内容暂时就不做学习了,有兴趣的同学可以查看官方文档进行学习。
1、使用默认的错误提示信息
php
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email'
];
}
php
$data = [
'name' => 'zhangsan',
'age' => 121,
'email' => 'test@qq.com'
];
$validate = new \app\validate\User;
$result = $validate->check($data);
if(!$result){
echo $validate->getError();
}
会输出 age只能在 1 - 120 之间。
可以给 age 字段设置中文名,例如:
php
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age|年龄' => 'number|between:1,120',
'email' => 'email'
];
}
会输出 年龄只能在 1 - 120 之间。
2、单独定义提示信息
如果要输出自定义的错误信息,可以定义 message 属性:
php
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email'
];
protected $message = [
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄必须在1~120之间',
'email' => '邮箱格式错误'
];
}
php
$data = [
'name' => 'zhangsan',
'age' => 121,
'email' => 'test@qq.com'
];
$validate = new \app\validate\User;
$result = $validate->check($data);
if(!$result){
echo $validate->getError();
}
会输出 年龄必须在1~120之间。
错误信息可以支持数组定义,并且通过JSON方式传给前端。
php
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email'
];
protected $message = [
'name.require' => ['code' => 1001, 'msg' => '名称必须'],
'name.max' => ['code' => 1002, 'msg' => '名称最多不能超过25个字符'],
'age.number' => ['code' => 1003, 'msg' => '年龄必须是数字'],
'age.between' => ['code' => 1004, 'msg' => '年龄必须在1~120之间'],
'email' => ['code' => 1005, 'msg' =>'邮箱格式错误']
];
}
四、验证场景
验证场景仅针对验证器有效,独立验证不存在验证场景的概念。
验证器支持定义场景,并且验证不同场景的数据,scene 属性用于定义验证场景。例如:
php
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email'
];
protected $message = [
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄只能在1-120之间',
'email' => '邮箱格式错误'
];
protected $scene = [
'edit' => ['name','age']
];
}
然后在验证方法中使用 scene 方法指定验证的场景
php
$data = [
'name' => 'zhangsan',
'age' => 10,
'email' => 'test@qq.com'
];
try {
validate(app\validate\User::class)
->scene('edit')
->check($data);
} catch (ValidateException $e) {
// 验证失败 输出错误信息
dump($e->getError());
}
可以单独为某个场景定义方法(方法的命名规范是 scene + 场景名),并且对某些字段的规则重新设置。例如:
php
namespace app\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email',
];
protected $message = [
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄只能在1-120之间',
'email' => '邮箱格式错误'
];
// edit 验证场景定义
public function sceneEdit()
{
return $this->only(['name','age'])
->append('name', 'min:5')
->remove('age', 'between')
->append('age', 'require|max:100');
}
}
注意:场景名不区分大小写,且在调用的时候不能将驼峰写法转为下划线。
主要方法说明:
|---------|-----------------|
| 方法名 | 描述 |
| only | 场景需要验证的字段 |
| remove | 移除场景中的字段的部分验证规则 |
| append | 给场景中的字段需要追加验证规则 |
如果对同一个字段进行多次规则补充(包括移除和追加),必须使用下面的方式:
php
remove('field', ['rule1','rule2']);
// 或者
remove('field', 'rule1|rule2');
五、验证分组
该功能需要 V8.1.2+ 版本支持。
可以给验证规则定义分组,每个分组的规则彼此独立,但可以共用别名规则和错误信息,相当于把多个验证器类合并成一个验证类。分组使用 group 属性进行定义。
php
<?php
namespace app\validate;
use think\Validate;
class Project extends Validate
{
protected $message = [
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄只能在1-120之间',
'email' => '邮箱格式错误'
];
protected $group = [
'user' => [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email'
],
];
}
然后在方法 check 中指定验证的分组名称
php
$data = [
'name' => 'zhangsan',
'age' => 135,
'email' => 'test@qq.com'
];
try {
validate(\app\validate\Project::class)->check($data, 'user');
} catch (ValidateException $e) {
var_dump($e->getError());
}
可以单独为某个分组定义方法(方法的命名规范是 rules + 分组名),并且通过方法设置分组规则。例如:
php
<?php
namespace app\validate;
use think\Validate;
class Project extends Validate
{
protected $message = [
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄只能在1-120之间',
'email' => '邮箱格式错误'
];
// 分组规则定义
public function rulesUser()
{
return $this->rule([
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email'
]);
}
}
六、路由验证
可以在路由规则定义的时候调用 validate 方法指定验证器类对请求的数据进行验证。
例如下面的例子表示对请求数据使用验证器类 app\validate\User 进行自动验证,并且使用 edit 验证场景:
php
Route::post('hello/:id', 'index/hello')
->validate(\app\validate\User::class,'edit');
或者不使用验证器而直接传入验证规则
php
Route::post('hello/:id', 'index/hello')
->validate([
'name' => 'require|min:5|max:50',
'email' => 'email'
]);
validate 方法也支持传入错误信息
php
Route::post('hello/:id', 'index/hello')
->validate([
'name' => 'require|min:5|max:50',
'email' => 'email'
], message: [
'name.require' => '名称必须',
'name.min' => '名称最少需要5个字符',
'name.max' => '名称最多不能超过50个字符',
'email' => '邮箱格式错误'
]);
也支持使用对象化规则定义
php
Route::post('hello/:id', 'index/hello')
->validate([
'name' => ValidateRule::min(5)->max(50),
'email' => ValidateRule::isEmail()
]);
七、内置规则
系统内置了一些常用的验证规则,可以完成大部分场景的验证需求。
验证规则严格区分大小写。
1、格式验证类
格式验证类的验证规则如果在使用静态方法调用的时候需要加上 is (以 number 验证为例,需要使用 isNumber() )。
require
验证某个字段必须,例如:
php
'name' => 'require'
注意:如果验证规则没有添加 require 就表示没有值的话不进行验证。
number
验证某个字段的值是否为纯数字(采用 ctype_digit 验证,不包含负数和小数点),例如:
php
'num' => 'number'
integer
验证某个字段的值是否为整数,例如:
php
'num' => 'integer'
float
验证某个字段的值是否为浮点数字,例如:
php
'num' => 'float'
boolean 或者 bool
验证某个字段的值是否为布尔值,例如:
php
'num' => 'boolean'
验证某个字段的值是否为email地址,例如:
php
'email' => 'email'
array
验证某个字段的值是否为数组,例如:
php
'info' => 'array'
支持验证数组必须包含某些键名(键名之间用逗号分隔),例如:
php
'info' => 'array:name,email'
enum:枚举类名
验证某个字段的值是否在允许的枚举值范围(支持普通枚举和自定义枚举类),例如:
php
'status' => 'enum:' . StatusEnum::class
string
验证某个字段的值是否为字符串,例如:
php
'info' => 'string'
accepted
待验证的字段必须是 「yes」、「on」、1、「1」、true 或 「true」。这对于验证「服务条款」接受或类似字段非常有用。例如:
php
'accept' => 'accepted'
declined
验证某个字段的值必须是 「no」,「off」,0,「0」,false 或者 「false」。
multipleOf:value
验证某个字段的值必须是某个值的倍数,例如:
php
'number' => 'multipleOf:10'
date
验证值是否为有效的日期,例如:
php
'date' => 'date'
会对日期值进行 strtotime 后进行判断。
alpha
验证某个字段的值是否为纯字母,例如:
php
'name' => 'alpha'
alphaNum
验证某个字段的值是否为字母和数字,例如:
php
'name' => 'alphaNum'
alphaDash
验证某个字段的值是否为字母和数字,下划线 _ 及破折号 - ,例如:
php
'name' => 'alphaDash'
chs
验证某个字段的值只能是汉字,例如:
php
'name' => 'chs'
chsAlpha
验证某个字段的值只能是汉字、字母,例如:
php
'name' => 'chsAlpha'
chsAlphaNum
验证某个字段的值只能是汉字、字母和数字,例如:
php
'name' => 'chsAlphaNum'
chsDash
验证某个字段的值只能是汉字、字母、数字和下划线 _ 及破折号 - ,例如:
php
'name' => 'chsDash'
lower
验证某个字段的值只能是小写字符,例如:
php
'name' => 'lower'
upper
验证某个字段的值只能是大写字符,例如:
php
'name' => 'upper'
activeUrl
验证某个字段的值是否为有效的域名或者IP,例如:
php
'host' => 'activeUrl'
url
验证某个字段的值是否为有效的URL地址,例如:
php
'url' => 'url'
ip
验证某个字段的值是否为有效的IP地址,例如:
php
'ip' => 'ip'
支持验证ipv4和ipv6格式的IP地址。
dateFormat:format
验证某个字段的值是否为指定格式的日期,例如:
php
'create_time' => 'dateFormat:y-m-d'
mobile
验证某个字段的值是否为有效的手机,例如:
php
'mobile' => 'mobile'
idCard
验证某个字段的值是否为有效的身份证格式,例如:
php
'id_card' => 'idCard'
macAddr
验证某个字段的值是否为有效的MAC地址,例如:
php
'mac' => 'macAddr'
zip
验证某个字段的值是否为有效的邮政编码,例如:
php
'zip' => 'zip'
2、长度和区间验证类
in
验证某个字段的值是否在某个范围,例如:
php
'num' => 'in:1,2,3'
notIn
验证某个字段的值不在某个范围,例如:
php
'num' => 'notIn:1,2,3'
between
验证某个字段的值是否在某个区间,例如:
php
'num' => 'between:1,10'
notBetween
验证某个字段的值不在某个范围,例如:
php
'num' => 'notBetween:1,10'
length:num1,num2
验证某个字段的值的长度是否在某个范围,例如:
php
'name' => 'length:4,25'
或者指定长度
php
'name' => 'length:4'
如果验证的数据是数组,则判断数组的长度。
如果验证的数据是File对象,则判断文件的大小。
max:number
验证某个字段的值的最大长度,例如:
php
'name' => 'max:25'
如果验证的数据是数组,则判断数组的长度。
如果验证的数据是File对象,则判断文件的大小。
min:number
验证某个字段的值的最小长度,例如:
php
'name' => 'min:5'
如果验证的数据是数组,则判断数组的长度。
如果验证的数据是File对象,则判断文件的大小。
after:日期
验证某个字段的值是否在某个日期之后,例如:
php
'begin_time' => 'after:2025-3-18'
before:日期
验证某个字段的值是否在某个日期之前,例如:
php
'end_time' => 'before:2025-10-01'
expire:开始时间,结束时间
验证当前操作(注意不是某个值)是否在某个有效日期之内,例如:
php
'expire_time' => 'expire:2025-2-1,2025-10-01'
allowIp:allow1,allow2,...
验证当前请求的IP是否在某个范围,例如:
php
'ip' => 'allowIp:114.45.4.55'
该规则可以用于某个后台的访问权限,多个IP用逗号分隔。
denyIp:allow1,allow2,...
验证当前请求的IP是否禁止访问,例如:
php
'ip' => 'denyIp:114.45.4.55'
多个IP用逗号分隔。
3、字段比较类
confirm:field
验证某个字段是否和另外一个字段的值一致,例如:
php
// 验证 password 字段的值是否和 repassword 字段的值一样
'repassword' => 'confirm:password'
支持字段自动匹配验证规则,如 password 和 password_confirm 是自动相互验证的,只需要使用
php
'password' => 'require|confirm'
会和 password_confirm 进行字段比较是否一致。
different:field
验证某个字段是否和另外一个字段的值不一致,例如:
php
'name' => 'different:account'
startWith:str
验证某个字段是否以某个字符串开头,例如:
php
'name' => 'startWith:test'
endWith:str
验证某个字段是否以某个字符串结尾,例如:
php
'name' => 'endWith:test'
contain:str
验证某个字段是否以包含某个字符串,例如:
php
'name' => 'contain:test'
eq 或者 = 或者 same
验证是否等于某个值,例如:
php
'score' => 'eq:100'
'num' => '=:100'
'num' => 'same:100'
egt 或者 >=
验证是否大于等于某个值,例如:
php
'score' => 'egt:60'
'num' => '>=:100'
gt 或者 >
验证是否大于某个值,例如:
php
'score' => 'gt:60'
'num' => '>:100'
elt 或者 <=
验证是否小于等于某个值,例如:
php
'score' => 'elt:100'
'num' => '<=:100'
lt 或者 <
验证是否小于某个值,例如:
php
'score' => 'lt:100'
'num' => '<:100'
字段比较
验证对比其他字段大小(数值大小对比),例如:
php
// price 字段的值是否小于 market_price 字段的值
'price' => 'lt:market_price'
'price' => '<:market_price'
4、正则验证
支持直接使用正则验证,例如:
php
'zip' => '\d{6}'
// 或者
'zip' => 'regex:\d{6}'
如果正则表达式中包含有 | 符号的话,必须使用数组方式定义。
php
'accepted' => ['regex'=>'/^(yes|on|1)$/i'],
也可以实现预定义正则表达式后直接调用,例如在验证器类中定义 regex 属性
php
namespace app\index\validate;
use think\Validate;
class User extends Validate
{
protected $regex = ['zip' => '\d{6}'];
protected $rule = [
'name' => 'require|max:25',
'email' => 'email'
];
}
然后就可以使用
php
'zip' => 'regex:zip'
5、上传验证
file
验证是否是一个上传文件。
image:width,height,type
验证是否是一个图像文件,width height和type都是可选,width和height必须同时定义。
fileExt:允许的文件后缀
验证上传文件后缀。
fileMime:允许的文件类型
验证上传文件类型。
fileSize:允许的文件字节大小
验证上传文件大小。
6、其它验证
token:表单令牌名称
表单令牌验证。
unique:table,field,except,pk
验证当前请求的字段值是否为唯一的,例如:
php
// 表示验证name字段的值是否在user表(不包含前缀)中唯一
'name' => 'unique:user'
// 验证其他字段
'name' => 'unique:user,account'
// 排除某个主键值
'name' => 'unique:user,account,10'
// 指定某个主键值排除
'name' => 'unique:user,account,10,user_id'
requireIf:field,value
验证某个字段的值等于某个值的时候必须,例如:
php
// 当account的值等于1的时候password必须
'password' => 'requireIf:account,1'
requireWith:field
验证某个字段没有值的时候必须,例如:
php
// mobile和phone必须输入一个
'mobile' => 'requireWithout:phone',
'phone' => 'requireWithout:mobile'
八、表单令牌
1、添加令牌 Token 验证
验证规则支持对表单的令牌验证,首先需要在表单里面增加下面隐藏域:
html
<input type="hidden" name="__token__" value="{:token()}" />
也可以使用
html
{:token_field()}
默认的令牌Token名称是__token__,如果需要自定义名称及令牌生成规则可以使用
html
{:token_field('__hash__', 'md5')}
第二个参数表示 token 的生成规则,也可以使用闭包。
注意 :Token 的使用依赖 Session,所以要先开启 Session(think\middleware\SessionInit) 中间件。开启方式有两种,一种是在路由配置文件(config/route.php)中进行全局配置
phpreturn [ ..., 'middleware' => [think\middleware\SessionInit::class], ];第二种方式是在对应的控制器中配置该中间件
phpprotected $middleware = ['think\middleware\SessionInit'];
2、AJAX提交
如果是AJAX提交的表单,可以将 token 设置在 meta 中
html
<meta name="csrf-token" content="{:token()}">
或者使用
html
{:token_meta()}
然后在全局Ajax中使用如下方式设置 X-CSRF-Token 请求头并提交:
php
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
3、路由验证
然后在路由规则定义中,使用 token() 方法进行验证
php
Route::post('blog/save','blog/save')->token();
// 如果自定义了 token 名称,需要改成
Route::post('blog/save','blog/save')->token('__hash__');
令牌检测如果不通过,会抛出 think\exception\ValidateException 异常。
如果没有使用路由定义,可以在控制器里面手动进行令牌验证
php
namespace app\controller;
use think\exception\ValidateException;
use think\Request;
class Index
{
public function index(Request $request)
{
$check = $request->checkToken('__token__');
if(false === $check) {
throw new ValidateException('invalid token');
}
// ...
}
}
提交数据默认获取 post 数据,支持指定数据进行 Token 验证。
php
namespace app\controller;
use think\exception\ValidateException;
use think\Request;
class Index
{
public function index(Request $request)
{
$check = $request->checkToken('__token__', $request->param());
if(false === $check) {
throw new ValidateException('invalid token');
}
// ...
}
}
4、使用验证器验证
在验证规则中,添加 token 验证规则即可。例如,如果使用的是验证器的话,可以改为:
php
protected $rule = [
'name' => 'require|max:25|token',
'email' => 'email',
];
如果令牌名称不是 token(假设是 hash ),验证器中需要改为实际的令牌名称:
php
protected $rule = [
'name' => 'require|max:25|token:__hash__',
'email' => 'email',
];