正常情况都需要对用户输入参数进行校验,此时就会用到验证器。验证器可以验证控制器中参数,也支持验证 Websocket 参数以及 RPC 参数验证,提供默认和自定义两种类型的验证器,还可添加自定义验证规则。
配置
需要启用验证器,这里以 Http-server 启用为例,其它一样(app/bean.php)
return [
// ......
'httpDispatcher' => [
// ......
'afterMiddlewares' => [
\Swoft\Http\Server\Middleware\ValidatorMiddleware::class
]
// ......
],
// ......
]
说明 afterMiddlewares 与 middlewares 中间件 中间件的不同在于 afterMiddlewares 中间件 总是在 middlewares 中间件全部执行完后执行.
声明验证器简单示例
一个验证器由多个验证条件组合,建议验证器按数据库表进行组合,这样可以充分的重复利用验证器里面的组合条件。
<?php
namespace App\Http\MyValidator;
use Swoft\Validator\Annotation\Mapping\IsInt;
use Swoft\Validator\Annotation\Mapping\Max;
use Swoft\Validator\Annotation\Mapping\Min;
use Swoft\Validator\Annotation\Mapping\Validator;
/**
* 商品验证
* @Validator(name="orders")
*/
class OrderValidator{
/**
* @IsInt(message="用户ID不能为空")
* @Min(value=1,message="用户ID不正确")
* @var int
*/
protected $user_id;
/**
* @IsInt(message="订单状态不能空")
* @Min(value=0,message="状态不正确min")
* @Max(value=5,message="状态不正确max")
* @var int
*/
protected $order_status;
/**
* @IsInt(message="订单金额不为空")
* @Min(value=1,message="订单金额不正确")
* @var int
*/
protected $order_money;
}
代码解析
注解
@Validator 声明该类是一个验证器,推荐给验证器命名,这里我们给验证器命名为 orders
验证项
验证项是组成验证器的唯一条件,标记有类型注解的属性就是一个验证项,一个验证器可以有多个验证项。
- 属性的默认值就是参数的默认值,如果属性没有定义默认值,代表参数没有定义默认值且必须传递。
- 一个属性必须定义一个类型注解,否则不是一个验证项且对参数验证无效。
- 一个属性可以多个条件注解,按照定义顺序验证数据。
- 默认属性名称就是需要验证的参数名称,也可以通过类型注解的 name 参数映射需要验证的字段名称。
- 若验证不通过时,将会抛出 Swoft\Validator\Exception\ValidatorException 异常。
验证器使用
1 注解使用
<?php
namespace App\Http\Controller;
use App\Models\KfMain;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;
use Swoft\Validator\Annotation\Mapping\Validate;
/**
* Class Order
* @Controller(prefix="/order")
*/
class Order{
/**
* @Validate(validator="orders")
* @RequestMapping(route="new",method={RequestMethod::POST})
*/
public function createOrder(){
$req=Swoft\Context\Context::mustGet()->getRequest();
$raw = $req->getBody()->getContents();
$data = json_decode($raw, true);// key=>value数组
return $ordersPost;
}
}
说明 只需要使用 Validate 注解并指定验证器名称,就能自动验证数据.默认情况是验证 post 数据,如果需要验证 get 数据
@Validate(validator="orders",type="get")
设置type参数为 get 即可
- 非注解使用
全局方法 不推荐使用
function validate(array $data, string $validatorName, array $fields = [], array $userValidators = []): array
全局函数使用,当验证器失败会抛出 Swoft\Validator\Exception\ValidatorException 异常
参数说明:
- $data 需要验证的数据,必须是数组 KV 格式
- $validatorName 使用的验证器( @Validator() 注解标记的 )
- $fields 需要验证的字段,为空验证器所有字段
- $userValidators 同时使用的自定义验证器,支持两种格式。
常用验证规则
@IsArray
验证规则:
验证参数值必须是数组,使用 is_array()函数进行校验。
参数说明:
- name: 映射需要验证的字段名称,默认属性名称。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@IsArray(name="field", message="error message")
@IsBool
验证规则:
验证参数值必须是 bool 类型,注意字符串 true false ,会验证成 bool 类型,其余数据将会使用is_bool()函数进行验证。
参数说明:
- name: 映射需要验证的字段名称,默认属性名称。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@IsBool(name="field", message="error message")
@IsFloat
验证规则:
验证参数值必须是浮点数,使用filter_var()函数进行验证。
参数说明:
- name: 映射需要验证的字段名称,默认属性名称。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@IsFloat(name="field", message="error message")
@IsInt
验证规则:
验证参数值必须是整数,使用filter_var()函数进行验证。
参数说明:
- name: 映射需要验证的字段名称,默认属性名称。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@IsInt(name="field", message="error message")
@IsString
验证规则:
验证参数值必须是字符串,使用is_string()函数进行验证。
参数说明:
- name: 映射需要验证的字段名称,默认属性名称。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@IsString(name="field", message="error message")
条件注解
- 一个属性可以多个条件注解,按照定义顺序验证数据。
@AfterDate
验证规则:
验证参数值必须在某个日期之后,参数支持 字符串时间戳、格式化日期字符串(只支持 Y-m-d H:i:s)、整型时间戳,可在@IsString 或 @IsInt 类型注解中使用。
参数说明:
- date: 要对比的日期值,只能是 Y-m-d H:i:s 格式。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@AfterDate(date="2019-01-01 00:00:00", message="error message")
@Alpha
验证规则:
验证参数值必须是 大写字母 或 小写字母。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Alpha(message="error message")
@AlphaDash
验证规则:
验证参数值必须是 大写字母 、 小写字母、数字、短横 -、下划线 _。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@AlphaDash(message="error message")
@AlphaNum
验证规则:
验证参数值必须是 大写字母 、 小写字母、数字。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@AlphaNum(message="error message")
@BeforeDate
验证规则:
验证参数值必须在某个日期之前,支持 字符串时间戳、格式化日期字符串(只支持 Y-m-d H:i:s)、整型时间戳,可在@IsString 或 @IsInt 类型注解中使用。
参数说明:
- date: 要对比的日期值,只能是 Y-m-d H:i:s 格式。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@BeforeDate(date="2019-01-01 00:00:00", message="error message")
@Chs
验证规则:
验证参数值只能是 中文。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Chs(message="error message")
@ChsAlpha
验证规则:
验证参数值必须是 中文、大写字母 、 小写字母。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@ChsAlpha(message="error message")
@ChsAlphaDash
验证规则:
验证参数值必须是 中文、大写字母 、 小写字母、数字、短横 -、下划线 _。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@ChsAlphaDash(message="error message")
@ChsAlphaNum
验证规则:
验证参数值必须是 中文、大写字母 、 小写字母、数字。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@ChsAlphaNum(message="error message")
@Confirm
验证规则:
验证参数值必须和另外一个字段参数值相同。
参数说明:
- name: 需要确认对比的字段名,在类型注解中设置过的 name 或者是默认的 属性名。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Confirm(name="field", message="error message")
@Different
验证规则:
验证参数值必须和另外一个字段参数值不同。
参数说明:
- name: 需要确认对比的字段名,在类型注解中设置过的 name 或者是默认的 属性名。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Different(name="field", message="error message")
@GreaterThan
验证规则:
验证参数值必须比另外一个字段参数值大,只支持 int 或 float, 字符串会被转化为 float 后进行对比。
参数说明:
- name: 需要确认对比的字段名,在类型注解中设置过的 name 或者是默认的 属性名。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@GreaterThan(name="field", message="error message")
@LessThan
验证规则:
验证参数值必须比另外一个字段参数值小,只支持 int 或 float, 字符串会被转化为 float 后进行对比。
参数说明:
- name: 需要确认对比的字段名,在类型注解中设置过的 name 或者是默认的 属性名。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@LessThan(name="field", message="error message")
@Date
验证规则:
验证参数值必须是日期格式,支持 字符串时间戳、格式化日期字符串(只支持 Y-m-d H:i:s)、整型时间戳,可在@IsString 或 @IsInt 类型注解中使用。
注意由于时间戳的特殊性默认为一个整型 大于 PHP_INT_MIN , 小于 PHP_INT_MAX 常量的数值均为有效时间戳。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Date(message="error message")
@DateRange
验证规则:
验证参数值必须在某个日期范围之内(可以等于临界日期),支持 字符串时间戳、格式化日期字符串(只支持 Y-m-d H:i:s)、整型时间戳,可在@IsString 或 @IsInt 类型注解中使用。
参数说明:
- start: 要对比的开始日期值,只能是 Y-m-d H:i:s 格式。
- end: 要对比的结束日期值,只能是 Y-m-d H:i:s 格式。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@DateRange(start="2019-01-01 00:00:00",end="2019-01-01 00:00:00", message="error message")
@Dns
验证规则:
验证参数值必须是一个具有有效 DNS 记录域名或者ip,使用 checkdnsrr() 函数校验。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Dns(message="error message")
验证规则:
验证参数值格式必须为邮箱
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Email(message="error message")
@Enum
验证规则:
验证参数值必须在枚举数组里面。
参数说明:
- values: 枚举数组集合
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Enum(values={1,2,3},message="error message")
@File
验证规则:
验证此参数的值必须是文件,可以是单个文件,也可以是表单数组上传的多个文件。注意文件上传后文件域的获取需要通过 Swoft\Http\Message\Request 对象去获取。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@File(message="error message")
@FileMediaType
验证规则:
使用此条件前必须使用 @File 规则为基础。 验证每个上传的文件 mediaType 类型,支持表单数组,批量文件。
参数说明:
- mediaType: mediaType类型数组。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@FileMediaType(mediaType={"image/gif","image/png"},message="error message")
@FileSize
验证规则:
使用此条件前必须使用 @File 规则为基础。 验证每个上传的文件尺寸大小(单位 byte 字节),支持表单数组,批量文件。
参数说明:
- size: 文件尺寸大小,单位 byte。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@FileSize(size=1024,message="error message")
@FileSuffix
验证规则:
使用此条件前必须使用 @File 规则为基础。 验证每个上传的文件后缀名,支持表单数组,批量文件。
参数说明:
- suffix: 后缀名数组。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@FileSuffix(suffix={"png","jpg"},message="error message")
@Ip
验证规则:
验证参数值必须是个IP类型。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Ip(message="error message")
@Length
验证规则:
验证参数值长度限制。
参数说明:
- min: 最小值(包含当前值)。
- max: 最大值(包含当前值)。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Length(min=1,max=4,message="error message")
@Low
验证规则:
验证参数值必须是小写字母。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Low(message="error message")
@Max
验证规则:
最大值验证,必须是整数。
参数说明:
- value 最大值(包含当前值)
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Max(value=5,message="error message")
@Min
验证规则:
最小值验证
参数说明:
- value 最小值(包含当前值)
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Min(value=5,message="error message")
@Mobile
验证规则:
手机号验证。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Mobile(message="error message")
@NotEmpty
验证规则:
参数值不能为空验证。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@NotEmpty(message="error message")
@NotInEnum
验证规则:
验证参数值必须不在枚举数组中。
参数说明:
- values 枚举数组集合。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@NotInEnum(values={1,2,3},message="error message")
@NotInRange
验证规则:
验证参数值必须不在范围内
参数说明:
-
- min: 最小值(包含当前值)。
- max: 最大值(包含当前值)。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@NotInRange(min=1,max=5,message="error message")
@Pattern
验证规则:
正则表达式验证。
参数说明:
- regex: 正则表达式。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Pattern(regex="/^1\d{10}$/", message="error message")
@Range
验证规则:
参数值范围验证。
参数说明:
- min: 最小值(包含当前值)。
- max: 最大值(包含当前值)。
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Range(min=1,max=5,message="error message")
@Upper
验证规则:
验证参数值必须是大写字母。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Upper(message="error message")
@Url
验证规则:
验证参数值必须是有效的URL格式,使用 filter_var()函数验证。
参数说明:
- message: 验证失败时的错误提示,若不设置则默认使用框架内置的。
- 使用示例:
@Url(message="error message")
自定义验证器
常见的业务默认验证器就能解决,但是有些业务默认验证器是没法验证,此时就需要用户根据自己业务需求,定义满足自己业务的验证器。
自定义验证定义需要定义3个文件,注解文件,注解解析文件,验证器规则
简单示例
我们定义一个验证2个字段数据是否相等的验证器规则
1 注解定义
文件 App/Annotation/Mapping/Eq.php
<?php declare(strict_types=1);
namespace App\Annotation\Mapping;
use Doctrine\Common\Annotations\Annotation\Attribute;
use Doctrine\Common\Annotations\Annotation\Attributes;
/**
* Class Eq
*
* @since 2.0
*
* @Annotation
* @Attributes({
* @Attribute("message",type="string"),
@Attribute("prop",type="string")
* })
*/
class Eq
{
/**
* @var string
*/
private $message = '';
/**
* @var string
*/
private $name = '';
private $prop = '';
/**
* StringType constructor.
*
* @param array $values
*/
public function __construct(array $values)
{
if (isset($values['value'])) {
$this->message = $values['value'];
}
if (isset($values['message'])) {
$this->message = $values['message'];
}
if (isset($values['name'])) {
$this->name = $values['name'];
}
if (isset($values['prop'])) {
$this->prop = $values['prop'];
}
}
/**
* @return string
*/
public function getMessage(): string
{
return $this->message;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @return string
*/
public function getProp(): string
{
return $this->prop;
}
}
说明 这你定义其他验证器注解的时候只需要改变类名称,内容保持一样即可
文件 App/Annotation/Parser/EqParser.php
<?php declare(strict_types=1);
namespace App\Annotation\Parser;
use ReflectionException;
use Swoft\Annotation\Annotation\Mapping\AnnotationParser;
use Swoft\Annotation\Annotation\Parser\Parser;
use App\Annotation\Mapping\Eq;
use Swoft\Validator\Exception\ValidatorException;
use Swoft\Validator\ValidatorRegister;
/**
* Class EqParser
*
* @AnnotationParser(annotation=Eq::class)
*/
class EqParser extends Parser
{
/**
* @param int $type
* @param object $annotationObject
*
* @return array
* @throws ReflectionException
* @throws ValidatorException
*/
public function parse(int $type, $annotationObject): array
{
if ($type != self::TYPE_PROPERTY) {
return [];
}
ValidatorRegister::registerValidatorItem($this->className, $this->propertyName, $annotationObject);
return [];
}
}
说明 这个类是注解的解析类,你只需要修改注解 @AnnotationParser 参数 annotation 为你自己定义的注解定义类即可.同时别忘了改类名.
文件 App/Validator/Rule/EqRule.php
<?php declare(strict_types=1);
namespace App\Validator\Rule;
use App\Annotation\Mapping\Eq;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Validator\Contract\RuleInterface;
use Swoft\Validator\Exception\ValidatorException;
/**
* Class AlphaDashRule
*
* @Bean(Eq::class)
*/
class EqRule implements RuleInterface
{
/**
* @param array $data
* @param string $propertyName
* @param object $item
* @param null $default
*
* @return array
* @throws ValidatorException
*/
public function validate(array $data, string $propertyName, $item, $default = null): array
{
if(!isset($data[$item->getProp()])){
throw new ValidatorException($item->getProp()."必须要传入");
}
if($data[ $propertyName]==$data[$item->getProp()]){
return $data;
}
throw ValidatorException($item->getMessage());
}
}
代码说明
- 首先需要定义Bean注解,并且 bean注解 并且值需要是你的 注解类的class名称 我们这里是 Eq
- 需要继承 RuleInterface 接口 并实现 validate 方法
- validate 方法有4个参数,下面介绍一下
- $data 数据对象 传过来需要验证的的 k=>v 数组
- $propertyName 需要验证的属性名称 也就是你注解加在哪个属性这里就是哪个属性名
- $item 注解对象,可以调用注解的 getter 方法取得注解定义的参数
- $default 默认值
使用示例
定义验证器
文件 App/Validator/TestValidator2.php
<?php declare(strict_types=1);
namespace App\Validator;
use App\Annotation\Mapping\Eq;
use Swoft\Validator\Annotation\Mapping\IsString;
use Swoft\Validator\Annotation\Mapping\Validator;
/**
* Class TestValidator2
*
* @since 2.0
*
* @Validator(name="TestValidator2")
*/
class TestValidator2
{
/**
* @IsString()
* @Eq(message="name和name1不一致",prop="name1")
*
* @var string
*/
protected $name;
}
注意这里的 IsString 注解不能省,因为需要验证数据类型
定义使用
文件 App/Http/Controller/ValidatorController.php
<?php declare(strict_types=1);
namespace App\Http\Controller;
use App\Validator\TestValidator2;
use Swoft\Http\Message\Request;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Validator\Annotation\Mapping\Validate;
/**
* Class ValidatorController
*
* @Controller()
*/
class ValidatorController
{
/**
* Verify all defined fields in the TestValidator validator
*
* @RequestMapping("/testValidator)
* @Validate(validator="TestValidator2")
*
* @param Request $request
*
* @return array
*/
public function validateAll(Request $request): array
{
return $request->getParsedBody();
}
}
控制台输出