验证器定义

验证器定义

  1. 验证器的使用,我们必须先定义它,系统提供了一条命令直接生成想要的类;
php think make:validate User

QQ截图20200804163433.png

  1. 这条命令会自动在应用目录下生成一个validate文件夹,并生成User.php类;
class User extends Validate
  1. 自动生成了两个属性:$rule表示定义规则,$message表示错误提示信息;
protected $rule = [
  'name' => 'require|max:20', //不得为空,不得大于 20 位
  'price' => 'number|between:1,100', //必须是数值,1-100 之间
  'email' => 'email' //邮箱格式要正确
];
protected $message = [
  'name.require' => '姓名不得为空',
  'name.max' => '姓名不得大于 20 位',
  'price.number' => '价格必须是数字',
  'price.between' => '价格必须 1-100 之间',
  'email' => '邮箱的格式错误'
];
  1. 如果不设置$message定义的话,将提示默认的错误信息;
  2. 验证器定义好了之后,我们需要进行调用测试;
try {
    validate(User::class)->check([
        'name' => '蜡笔小新',
        'price' => 90,
        'email' => 'xiaoxin@163.com'
    ]);
} catch (ValidateException $e) {
    dump($e->getError());
}
  1. 默认情况下,出现一个错误就会停止后面字段的验证,我们也可以设置批量验证;
try {
    validate(User::class)->batch(true)->check([
        'name' => '蜡笔小新',
        'price' => 90,
        'email' => 'xiaoxin@163.com'
    ]);
} catch (ValidateException $e) {
    dump($e->getError());
}

QQ截图20200804163908.png

  1. 系统提供了常用的规则让开发者直接使用,也可以自行定义独有的特殊规则;
protected $rule = [
  'name' => 'require|max:20|checkName:李炎恢',
];
//自定义规则,名称中不得是“李炎恢”
protected function checkName($value, $rule)
{
  return $rule != $value ? true : '名称存在非法称谓';
}
  1. 对于自定义规则中,一共可以有五个参数,我们分别了解一下;
protected function checkName($value, $rule, $data, $field, $title)
{
    dump($data); //所有数据信息
    dump($field); //当前字段名
    dump($title); //字段描述,没有就是字段名
}
  1. 如何设置字段描述,只要在字段名用|后设置即可:
    'name|用户名' => 'require|max:20|checkName:李炎恢',

验证规则和错误信息

验证规则

  1. 在上一节验证器定义的时候,我们采用的字符串模式,也支持数组模式;
protected $rule = [
    'name' => [
        'require',
        'max' => 10,
        'checkName' => '李炎恢'
    ],
    'price' => [
        'number',
        'between' => '1,100'
    ],
    'email' => 'email'
];

QQ截图20200804165449.png

  1. 数组模式在验证规则很多很乱的情况下,更容易管理,可读性更高;
  2. 如果你想使用独立验证,就是手动调用验证类,而不是调用User.php验证类;
  3. 这种调用方式,一般来说,就是独立、唯一,并不共享的调用方式;
$validate = Validate::rule([
    'name' => 'require|max:20',
    'price' => 'number|between:1,100',
    'email' => 'email'
]);
$result = $validate->check([
    'name' => '1997sty',
    'price' => 90,
    'email' => 'xiaoxin163.com'
]);
if (!$result) {
    dump($validate->getError());
}

QQ截图20200804165553.png

  1. 独立验证默认也是返回一条错误信息,如果要批量返回所有错误使用batch();
$validate = Validate::rule([
    'name' => 'require|max:20',
    'price' => 'number|between:1,100',
    'email' => 'email'
]);
$result = $validate->batch(true)->check([
    'name' => '1997sty',
    'price' => 90,
    'email' => 'xiaoxin163.com'
]);
if (!$result) {
    dump($validate->getError());
}

QQ截图20200804165716.png

  1. 独立验证支持对象化的定义方式,但不支持在属性方式的定义;
$validate = Validate::rule([
    'name' => ValidateRule::isRequire()->max(20),
    'price' => ValidateRule::isNumber()->between([1, 100]),
    'email' => ValidateRule::isEmail()
]);

QQ截图20200804165843.png

  1. 独立验支持闭包的自定义方式,但这种方式会不支持字段的多规则;
$validate = Validate::rule([
    'name' => function ($value) {
        return $value != '' ? true : '姓名不得为空';
    },
    'price'=> function ($value) {
        return $value > 0 ? true : '价格不得小于零';
    }
]);

QQ截图20200804165903.png

错误信息

  1. 独立验证的自定义错误提示,可以在方法的第二参数,参数一是规则;
ValidateRule::isEmail(null, '邮箱格式不正确!');
ValidateRule::isNumber()->between([1, 100], '价格范围 1-100 之间');

QQ截图20200804170039.png

  1. 也可以独立使用 message()方法,来设置相关错误信息;
$validate->message([
    // 'name.require' => '姓名不得为空',
    'name.require' => ['code'=>1001, 'msg'=>'姓名不得为空'],
    'name.max' => '姓名不可以超过 20 个子'
]);

QQ截图20200804170216.png

验证场景和路由验证

验证场景

  1. 验证场景设置,即特定的场景下是否进行验证,独立验证不存在场景验证;
  2. 举一个简单的例子,新增数据需要验证邮箱,而修改更新时不验证邮箱;
  3. 可以在验证类User.php中,设置一个$scene属性,用来限定场景验证;
protected $scene = [
    'insert' => ['name', 'price', 'email'],
    'edit' => ['name', 'price'],
];
  1. 上述中,insert新增需要验证三个字段,而edit更新则只要验证两个字段;
  2. 在控制器端,验证时,根据不同的验证手段,绑定相关场景进行验证即可;
$validate->scene('edit')->check($data);

QQ截图20200804172054.png

  1. 在验证类端,可以设置一个公共方法对场景的细节进行定义;
public function sceneEdit()
{
    $edit = $this->only(['name', 'price']) //仅对两个字段验证
    ->remove('name', 'max') //移出掉最大字段的限制
    ->append('price', 'require'); //增加一个不能为空的限制
    return $edit;
}
  1. 注意:请不要对一个字段进行两个或以上的移出和添加,会被覆盖;
remove('name', 'xxx|yyy|zzz')或 remove('name', ['xxx', 'yyy', 'zzz']);
而不是
remove('name', 'xxx')->remove('name', 'yyy')->remove('name', 'zzz');

路由验证

  1. 路由验证,即在路由的参数来调用验证类进行验证,和字段验证一模一样;
protected $rule = [
    'id' => 'number|between:1,10'
];
protected $message = [
    'id.between' => 'id 只能是 1-10 之间',
    'id.number' => 'id 必须是数字'
];
Route::rule('vr/:id','Verify/route')->validate(\app\validate\User::class, 'route');
// 特别注意:这里有一个 BUG,v6.0.2 修复了,使用 composer update。
  1. 如果不使用验证器类,也可以使用独立的验证方式,也可以使用对象化;
Route::rule('vr/:id','Verify/route')->validate([
    'id' => 'number|between:1,10',
    'email' => \think\validate\ValidateRule::isEmail()
], null, [
    'id.between' => 'id 限定在 1-10 之间',
    'email' => '邮箱格式错误'
], true);

验证内置规则

内置规则

  1. 内置的规则内容较多,并且严格区分大小写,这里按照类别一一列出;
  2. 静态方法支持两种形式,比如::number()或者isNumber()均可;
  3. require是PHP保留字,那么就必须用isRequire()must();
  4. 格式验证类:
'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', //是否是有效邮编
  1. 长度和区间验证类:
'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', 
  1. 字段比较类:
'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' 7. 其它验证类:
'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 必须有一个有值

单个验证和注解验证

单个验证

  1. 静态调用,即使用facade模式进行调用验证,非常适合单个数据的验证;
  2. 引入facade中的Validate时,和其它Validate会冲突,要特别注意;
//验证邮箱是否合法
dump(Validate::isEmail('xiaoxin@163.com'));
//验证是否为空
dump(Validate::isRequre(''));
//验证是否为数值
dump(Validate::isNumber(10));
  1. 静态调用返回的结果是falsetrue,方便你进行条件判断;
  2. 静态调用,也是支持多规则验证的,使用checkRule()方法实现;
//验证数值合法性
dump(Validate::checkRule(10, 'number|between:1,10'));
  1. checkRule()不支持错误信息,需要自己实现,但支持对象化规则定义;
dump(Validate::checkRule(10, ValidateRule::isNumber()->between('1,10')));

注解验证

  1. 可以结合之前课程中注解路由的传参,使用验证方式,对其进行验证;
use think\annotation\Route;
use think\annotation\route\Validate;
/**
* @param $id
* @return string
* @route("vr/:id")
* @Validate(User::class)
*/