ThinkPHP8学习篇(十五):验证

在Web应用开发中,数据验证是确保数据合法性、完整性与安全性的关键环节。ThinkPHP 内置的验证器组件提供了一套声明式、高可读的验证机制,能够将繁琐的数据校验逻辑封装为简洁的规则定义,有效提升代码的健壮性与开发效率。本文将集中学习验证器的核心用法,涵盖验证规则的定义与组合、错误信息的定制与获取、验证场景的灵活切换、验证分组的精细管理、路由中便捷的验证调用、丰富内置规则的选用,以及防范重复提交的表单令牌机制。掌握这些内容,将帮助我们为应用构建起简洁而可靠的数据验证层。

验证

一、验证器

1、验证器定义

2、数据验证

二、验证规则

1、属性定义

2、方法定义

3、闭包定义

4、规则别名

5、数组验证

6、批量验证

7、自定义验证规则

8、独立验证

三、错误信息

1、使用默认的错误提示信息

2、单独定义提示信息

四、验证场景

五、验证分组

六、路由验证

七、内置规则

1、格式验证类

2、长度和区间验证类

3、字段比较类

4、正则验证

5、上传验证

6、其它验证

八、表单令牌

[1、添加令牌 Token 验证](#1、添加令牌 Token 验证)

2、AJAX提交

3、路由验证

4、使用验证器验证


验证

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 应用程序的根目录,执行以下命令来查看当前使用的版本。

bash 复制代码
php 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

验证某个字段的值是否为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)中进行全局配置

php 复制代码
return [
    ...,
    'middleware' => [think\middleware\SessionInit::class],
];

第二种方式是在对应的控制器中配置该中间件

php 复制代码
protected $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',
];
相关推荐
wr2005142 小时前
渗透笔记和疑惑
开发语言·php
Y_cheng_2 小时前
php环境配置与伪协议
开发语言·php
Shi_haoliu12 小时前
SolidTime 在 Rocky Linux 9.5 上的完整部署流程
linux·运维·nginx·postgresql·vue·php·laravel
成工小白18 小时前
网络复习(1)
服务器·网络·php
恃宠而骄的佩奇19 小时前
蚁剑 php一句话木马简单免杀(编码)绕过360,火绒
开发语言·web安全·php·免杀·一句话木马·火绒安全
m0_7381207220 小时前
渗透测试——y0usef靶机渗透提权详细过程(插件伪造请求头)
服务器·网络·web安全·ssh·php
qq_406176141 天前
JS防抖与节流:从原理到实战的性能优化方案
服务器·数据库·php
独行soc1 天前
2026年渗透测试面试题总结-1(题目+回答)
android·开发语言·网络·安全·web安全·渗透测试·php
IT瑞先生1 天前
php unicode与中文互转
android·开发语言·php