thinkphp-验证场景和路由验证、验证内置规则、单个验证和注解验证

5359次阅读 227人点赞 作者: WuBin 发布时间: 2024-05-29 08:05:09
扫码到手机查看

验证场景

验证场景设置,即特定的场景下是否进行验证,独立验证不存在场景验证;

举一个简单的例子,比如一个类中有新增方法和修改方法,新增数据需要验证邮箱,而修改更新时不验证邮箱,而他们的验证信息写在验证类里,是通用的,所以这时候需要设置一个场景,给谁验证,给谁不验证。

可以在验证类app/validate/User.php 中,设置一个$scene 属性,用来限定场景验证;

<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;

class User extends Validate
{
    /**
     * 定义验证规则
     * 格式:'字段名' =>  ['规则1','规则2'...]
     *
     * @var array
     */
    protected $rule = [
        'name|用户名' => 'require|max:20',
        'price' => 'number|between:1,100',
        'email' => 'email'
    ];

    /**
     * 定义错误信息
     * 格式:'字段名.规则名' =>  '错误信息'
     *
     * @var array
     */
    protected $message = [
        'name.require' => '姓名不得为空',
        'name.max' => '姓名不得大于20 位',
        'price.number' => '价格必须是数字',
        'price.between' => '价格必须1-100 之间',
        'email' => '邮箱的格式错误'
    ];

    
    protected $scene = [
        // 新增时候验证那些规则
        'insert' => ['name', 'price', 'email'],
        // 修改时验证那些规则 键名称自定义即可 只要调用时候配对就行
        'edit' => ['name', 'price']
    ];
}

在控制器端,验证时,根据不同的验证手段,绑定相关场景进行验证即可;

$validate->scene('edit')->check($data)
在控制器中进行调用
namespace app\controller;

// 引入额外的验证类-index
use app\validate\User;
use think\exception\ValidateException;

class Verify
{
    public function index()
    {
        try {

            // 使用助手函数,直接放一个验证类进去
            validate(User::class)
                ->batch(true)
                ->scene('edit') // 写入场景规则,不验证邮箱
                ->check([
                    'name' => '',
                    'price' => 100,
                    'email' => 'xiaoxin@163.com'
                ]);

        } catch(ValidateException $e) {
            dump($e->getError());
        }
    }
}

在验证类端,可以设置一个公共方法对场景的细节进行定义;在app/validate/User.php

protected $scene = [
        // 新增时候验证那些规则
        'insert' => ['name', 'price', 'email'],
        // 修改时验证那些规则 键名称自定义即可 只要调用时候配对就行
        // 'edit' => ['name', 'price']
];

    // 通过sceneEdit方法,替代上面的'edit' 注意命名规则sceneE(大写)
 protected function sceneEdit()
{
        // only 方法指定到底执行那些规则
        $edit = $this->only(['name', 'price']);
        return $edit;
}

比如下面这个验证

// 使用助手函数,直接放一个验证类进去
            validate(User::class)
                ->batch(true)
                ->scene('edit') // 写入场景规则,不验证邮箱
                ->check([
                    'name' => '孙悟空孙悟空孙悟空孙悟空孙悟空孙悟空孙悟空孙悟空孙悟空孙悟空',
                    'price' => 100,
                    'email' => 'xiaoxin163.com'
                ]);
protected $scene = [
        // 新增时候验证那些规则
        'insert' => ['name', 'price', 'email'],
        // 修改时验证那些规则 键名称自定义即可 只要调用时候配对就行
        // 'edit' => ['name', 'price']
    ];

    // 通过sceneEdit方法,替代上面的'edit' 注意命名规则sceneE(大写)
    protected function sceneEdit()
    {
        // only 方法指定到底执行那些规则
        $edit = $this->only(['name', 'price'])
                     ->remove('name', 'max') // remove('验证规则名', '要移除的规则 这里是移除max')
        ; 
        return $edit;
    }

移除之后,就不会再验证name规则里面的max规则了。

validate(User::class)
                ->batch(true)
                ->scene('edit') // 写入场景规则,不验证邮箱
                ->check([
                    'name' => '孙悟空孙悟空孙悟空孙悟空孙悟空孙悟空孙悟空孙悟空孙悟空孙悟空',
                    'price' => '',
                    'email' => 'xiaoxin163.com'
]);

为其添加一个价格不能为空的验证规则

protected function sceneEdit()
    {
        // only 方法指定到底执行那些规则
        $edit = $this->only(['name', 'price'])
                     ->remove('name', 'max') // remove('验证规则名', '要移除的规则 这里是移除max')
                     ->append('price', 'require'); //增加一个不能为空的限制
        ; 
        return $edit;
}

注意:请不要对一个字段进行两个或以上的移出和添加,会被覆盖;

remove('name', 'xxx|yyy|zzz')或remove('name', ['xxx', 'yyy', 'zzz']);

而不是,后面的会覆盖掉前面的

remove('name', 'xxx')->remove('name', 'yyy')->remove('name', 'zzz'); 错误!

路由验证

首先修改验证规则,添加id验证

<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;

class User extends Validate
{
    /**
     * 定义验证规则
     * 格式:'字段名' =>  ['规则1','规则2'...]
     *
     * @var array
     */
    protected $rule = [
        // 这里的名称不一定要与数据库一模一样 可以自己写自己的
        'name|用户名' => 'require|max:20|checkName:wubin.work', //对应表中username字段,不得为空,不得大于20 位
        'price' => 'number|between:1,100', //必须是数值,1-100 之间
        'email' => 'email', //邮箱格式要正确
        'id' => 'number|between:1,10'
    ];

    /**
     * 定义错误信息
     * 格式:'字段名.规则名' =>  '错误信息'
     *
     * @var array
     */
    protected $message = [
        'name.require' => '姓名不得为空',
        'name.max' => '姓名不得大于20 位',
        'price.number' => '价格必须是数字',
        'price.between' => '价格必须1-100 之间',
        'email' => '邮箱的格式错误',
        'id.number' => 'id必须是数字',
        'id.between' => 'id必须在1-10之间'
    ];

    
    protected $scene = [
        // 新增时候验证那些规则
        'insert' => ['name', 'price', 'email'],
        // 修改时验证那些规则 键名称自定义即可 只要调用时候配对就行
        // 'edit' => ['name', 'price']
        // 只针对路由的验证,只验证id
        'route' => ['id']
    ];

    // 通过sceneEdit方法,替代上面的'edit' 注意命名规则sceneE(大写)
    protected function sceneEdit()
    {
        // only 方法指定到底执行那些规则
        $edit = $this->only(['name', 'price'])
                     ->remove('name', 'max') // remove('验证规则名', '要移除的规则 这里是移除max')
                     ->append('price', 'require'); //增加一个不能为空的限制
        ; 
        return $edit;
    }

    // 自定义规则 支持5个参数,$value, $rule最重要
    protected function checkName($value, $rule, $data, $field, $title)
    {
        return $value != $rule ? true : '非法名称,不得注册';
    }

}

在route/app.php中 先写一个路由,并添加验证规则,场景参数传入定义好的场景:route

Route::rule('vr/:id', 'Verify/route')->validate(\app\validate\User::class, 'route');

访问:http://localhost/xuexi/tp6/public/vr/4,如果验证失败,会抛出一个错误。

如果不使用验证器类,也可以使用独立的验证方式,也可以使用对象化;

Route::rule('vr/:id', 'Verify/route')
    ->validate([
        'id' => 'number|between:1,10',
        'email' => \think\validate\ValidateRule::isEmail(null, '邮箱格式不正确')
    ]);

当访问:http://localhost/xuexi/tp6/public/vr/4?email=11,会抛出邮箱格式不正确的错误。

注意这里的email是额外的参数,就是?之后的参数,而id则是/id?email=xxx

Route::rule('vr/:id', 'Verify/route')
    ->validate(
        [
            'id' => 'number|between:1,10',
            'email' => \think\validate\ValidateRule::isEmail(null, '邮箱格式不正确')
        ],
        null, // 第二个参数是场景,默认null,没有的话传入Null占位即可
        // 第三个参数是错误提示
        [
            "id.number" => '编号必须是数字'
        ],
        // 是否都验证,即显示所有不符合验证规则的结果 默认false
        true
);

当最后一个参数传入true时候,http://localhost/xuexi/tp6/public/vr/xx?email=11,抛出的错误会显示:

#0 [0]ValidateException in Validate.php line 534
编号必须是数字
邮箱格式不正确

验证内置规则

https://www.kancloud.cn/manual/thinkphp6_0/1037629

如果打不开,就https://www.thinkphp.cn/doc 中找tp6->验证->内置规则

内置规则

内置的规则内容较多,并且严格区分大小写,这里按照类别一一列出;

静态方法支持两种形式,比如::number()或者isNumber()均可;

require 是PHP 保留字,那么就必须用isRequire()或must();

格式验证类:

'field' => 'require', //不得为空::isRequire 或::must
'field' => 'number', //是否是纯数字,非负数非小数点
'field' => 'integer', //是否是整数
'field' => 'float', //是否是浮点数
'field' => 'boolean', //是否是布尔值,或者bool
'field' => 'email', //是否是email
'field' => 'array', //是否是数组
'field' => 'accepted', //是否是“yes”“no”“1”这三个值
'field' => 'date', //是否是有效日期
'field' => 'alpha', //是否是纯字母
'field' => 'alphaNum', //是否是字母和数字
'field' => 'alphaDash', //是否是字母和数字以及_-(下划线和破折号)
'field' => 'chs', //是否是纯汉字
'field' => 'chsAlpha', //是否是汉字字母
'field' => 'chsAlphaNum', //是否是汉字字母数字
'field' => 'chsDash', //是否是汉字字母数字以及_-(下划线和破折号)
'field' => 'cntrl', //是否是控制字符(换行、缩进、空格)
'field' => 'graph', //是否是可打印字符(空格除外)
'field' => 'print', //是否是可打印字符(包含空格)
'field' => 'lower', //是否是小写字符
'field' => 'upper', //是否是大写字符
'field' => 'space', //是否是空白字符
'field' => 'xdigit', //是否是十六进制
'field' => 'activeUrl', //是否是有效域名或IP 地址
'field' => 'url', //是否是有效URL 地址
'field' => 'ip', //是否是有效IP(支持ipv4,ipv6)
'field' => 'dateFormat:Y-m-d', //是否是指定日期格式
'field' => 'mobile', //是否是有效手机
'field' => 'idCard', //是否是有效身份证
'field' => 'macAddr', //是否是有效MAC 地址
'field' => 'zip', //是否是有效邮编

应用示例如下

// 使用门面模式引入验证类-rule
use think\facade\Validate;
use think\validate\ValidateRule;

$validate = Validate::rule([
    'name' => ValidateRule::isRequire()->max(20), 
    'price' => ValidateRule::isNumber()->between([1, 100], '价格在1-100之间'), 
    'email' => ValidateRule::isEmail(null, '邮箱格式不正确'),

    // test 不能为空
    'test' => 'require'
    'test' => ValidateRule::isRequire()
    'test' => ValidateRule::must()

    /*
    后续规则会添加在此处
    */
]);

// 使用message方法 对错误信息单独定义
$validate->message([
    'name.require' => ['code'=>1001, 'msg'=>'姓名不得为空'],
    'name.max' => '姓名不得大于20 位',
    ...
]);

// 传入测试数据 对规则进行验证
$result = $validate->batch(true)->check([
    'name' => '蜡笔小新',
    'price' => 100,
    'email' => 'xiaoxin@163.com',
    'test' => ''
    ...
]);
// 如果没有结果 那么输出错误信息
if(!$result) {
    dump($validate->getError());
}

验证必须是数字

// 必须是数字
'test' => ValidateRule::number()
'test' => ValidateRule::isNumber() 建议

必须是纯汉字

// 必须是纯汉字
'test' => 'chs'
'test' => ValidateRule::isChs()

长度和区间验证类:

'field' => 'in:1,2,3', //是否是有某个值
'field' => 'notIn:1,2,3', //是否是没有某个值
'field' => 'between:1,100', //是否是在区间中
'field' => 'notBetween:1,100', //是否是不在区间中
'field' => 'length:2,20', //是否字符长度在范围中
'field' => 'length:4', //是否字符长度匹配
'field' => 'max:20', //是否字符最大长度
'field' => 'min:5', //是否字符最小长度
//length、max、min 也可以判断数组长度和File 文件大小
'field' => 'after:2020-1-1', //是否在指定日期之后
'field' => 'before:2020-1-1', //是否在指定日期之前
//是否在当前操作是否在某个有效期内
'field' => 'expire:2019-1-1,2020-1-1',
//验证当前请求的IP 是否在某个范围之间,
'field' => 'allowIp:221.221.78.1, 192.168.0.1',
//验证当前请求的IP 是否被禁用
'field' => 'denyIp:221.221.78.1, 127.0.0.1',

区间长度

// 要求长度是4位
 'test' => 'length:4'
 'test' => ValidateRule::length(4)
// 长度区间2-4
 'test' => 'length:2,4'
'test' => ValidateRule::length([2,4])
'test' => ValidateRule::length('2,4')

字段比较类

'field' => 'confirm:password', //是否和另一个字段匹配
'field' => 'differnet:password',//是否和另一个字段不匹配
'field' => 'eq:100', //是否等于某个值,=、same 均可
'field' => 'gt:100', //是否大于某个值,支持>
'field' => 'egt:100', //是否大于等于某个值,支持>=
'field' => 'lt:100', //是否小于某个值,支持<
'field' => 'elt:100', //是否小于等于某个值,支持<=
//比较方式也支持字段比较,比如:'field'=>'lt:price'

字符串比较类

'test' => 'eq:100' // 不比较类型
 'test' => ValidateRule::eq(100)
'test' => ValidateRule::same(100)

不同字段进行比较(对密码与确认密码时候可以用)

'test' => 'confirm:price' // test字段与price字段进行比较

错误会返回

array:1 [
  "test" => "test和确认字段不一致"
]

其它验证类:

'field' => '\d{6}', //正则表达式验证
'field' => 'regex:\d{6}', //正则表达式验证
'field' => 'file', //判断是否是上传文件
'field' => 'image:150,150,gif', //判断图片(参数可选)
'field' => 'fileExt:jpg,txt', //判断文件允许的后缀
'field' => 'fileMime:text/html',//判断文件允许的文件类型
'field' => 'fileSize:2048', //判断文件允许的字节大小
'field' => 'unique:user', //验证field 字段的值是否在user 表
'field' => 'requireWith:account',//当account 有值时,requireWidth 必须
'email' => 'requireWithout:name',
'name' => 'requireWithout:email', //name 和email 必须有一个有值

比如图片上传后的后缀之类的判断,以及对表中字段的判断。

比如我要判断我输入的名字,是否在user表中存在。都不需要写SQL语句

# 和表的字段比较
'username' => 'unique:user' // '表里面的字段名username' => unique(唯一性):哪张表
$result = $validate->batch(true)->check([
            'username' => '蜡笔小新' // 表中存在username列中含有’蜡笔小新‘的值,所以会报错
            # 'username' => 'wubin' // 因为表中不存在username列中含有wubin的值,所以不报错
        ]);
        // 如果没有结果 那么输出错误信息
        if(!$result) {
            dump($validate->getError());
        }

如果输入的是蜡笔小新,因为username名重复,则报错

 array:1 [
  "username" => "username已存在"
]

单个验证和注解验证

静态调用,即使用facade 模式进行调用验证,非常适合单个数据的验证;引入facade 中的Validate 时,和其它Validate 会冲突,要特别注意;

use think\facade\Validate; 
dump( Validate::isEmail('xiaoxin@163.com') );

验证正确返回true,验证失败返回false

这个方法是tp5遗留下来的方法,随着以后版本更迭,可能会被删掉。
//验证是否为空
dump(Validate::isRequre(''));
//验证是否为数值
dump(Validate::isNumber(10));

静态调用返回的结果是false 和true,方便你进行条件判断;

静态调用,也是支持多规则验证的,使用checkRule()方法实现;

// 添加多个验证规则,是不是整数并且在1~10之间
dump( Validate::checkRule(110, 'number|between:1,10') );

另一种写法

dump( Validate::checkRule(10, ValidateRule::isNumber()->between('1, 10')) );

checkRule()不支持错误信息,需要自己实现,但支持对象化规则定义;

注解验证

可以结合之前课程中注解路由的传参,使用验证方式,对其进行验证;

# 注解验证必须引用下面两个命名空间
use think\annotation\Route;
// 由于这里与门面模式冲突了 所以这里要使用别名
use think\annotation\route\Validate as V;
/**
* @param $id
* @return string
* @route("vr/:id")
* @Validate(User::class)
*/

点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:thinkphp
推荐阅读
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    9603次阅读 623人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • Vue

    盘点Vue2和Vue3的10种组件通信方式

    Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异;本文将通过选项式API组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式。

    4297次阅读 317人点赞 发布时间: 2022-08-19 09:40:16 立即查看
  • JS

    几个高级前端常用的API

    推荐4个前端开发中常用的高端API,分别是MutationObserver、IntersectionObserver、getComputedstyle、getBoundingClientRect、requ...

    14452次阅读 948人点赞 发布时间: 2021-11-11 09:39:54 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    13497次阅读 491人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    12015次阅读 963人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    16376次阅读 1307人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    15187次阅读 1234人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    29849次阅读 2347人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    25911次阅读 1994人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录