dimtrovich / validation
PHP 独立验证库。扩展 rakit/validation
Requires
- php: >=8.0
- blitz-php/traits: ^1
- rakit/validation: ^1.4
Requires (Dev)
- blitz-php/coding-standard: ^1.1
- blitz-php/filesystem: ^1.2
- guzzlehttp/psr7: ^2.6
- kahlan/kahlan: ^5.2
- phpstan/phpstan: ^1.4.7
Suggests
- gblitz-php/filesystem: Required for file validation (^1.2).
- guzzlehttp/psr7: Required for upload file validation (^2.6).
README
PHP 独立数据验证库。灵感来源于 Laravel 的 Illuminate\Validation
,并扩展了 Rakit Validation。
特性
- Laravel 验证类似的 API。
- 数组验证。
- 支持多个文件的
$_FILES
验证。 - 自定义属性别名。
- 自定义验证消息。
- 自定义规则。
要求
- PHP 8.0 或更高版本
- Composer 用于安装
快速入门
安装
composer require "dimtrovich/validation"
使用
使用此库验证数据有两种方式。使用 make
创建验证对象,然后使用 validate
验证。或者直接使用 validate
。示例
使用 make
<?php require('vendor/autoload.php'); use Dimtrovich\Validation\Validator; // make it $validation = Validator::make($_POST + $_FILES, [ 'name' => 'required', 'email' => 'required|email', 'password' => 'required|min:6|confirmed', 'avatar' => 'required|uploaded_file:0,500K,png,jpeg', 'skills' => 'array', 'skills.*.id' => 'required|numeric', 'skills.*.percentage' => 'required|numeric' ]); if ($validation->fails()) { // handling errors $errors = $validation->errors(); echo "<pre>"; print_r($errors->firstOfAll()); echo "</pre>"; exit; } else { // validation passes echo "Success!"; }
属性别名
默认情况下,我们将您的属性转换为更易读的文本。例如,confirm_password
将显示为 Confirm password
。但您可以使用 alias
或 aliases
方法将其设置为任何您想要的内容。
示例
$validation = Validator::make([ 'province_id' => $_POST['province_id'], 'district_id' => $_POST['district_id'] ], [ 'province_id' => 'required|numeric', 'district_id' => 'required|numeric' ]); // now you can set aliases using this way: $validation->alias('province_id', 'Province'); $validation->alias('district_id', 'District'); // or this way: $validation->alias([ 'province_id' => 'Province', 'district_id' => 'District' ]); // then validate it $validation->validate();
如果 province_id
的值为空,错误消息将是 'Province is required'。
自定义验证消息
在注册/设置自定义消息之前,这里有一些您可以在自定义消息中使用变量
:attribute
: 将替换为属性别名。:value
: 将替换为属性的字符串化值。对于数组和对象将替换为 JSON。
还有根据其规则的一些消息变量。
以下是一些注册/设置您的自定义消息的方式
Validator 的自定义消息
使用这种方式,每次您使用 make
或 validate
进行验证时,都会设置您的自定义消息。这对于本地化非常有用。
为此,您可以像这样将自定义消息作为构造函数的第一个参数设置
$validator = new Validator([ 'required' => ':attribute harus diisi', 'email' => ':email tidak valid', // etc ]); // then validation belows will use those custom messages $validation_a = $validator->validate($dataset_a, $rules_for_a); $validation_b = $validator->validate($dataset_b, $rules_for_b);
或使用 messages
方法像这样
$validation = Validator::make(...); $validator->messages([ 'required' => ':attribute harus diisi', 'email' => ':email tidak valid', // etc ]); // now validation belows will use those custom messages $validation_a = $validator->validate($dataset_a, $rules_for_dataset_a); $validation_b = $validator->validate($dataset_b, $rules_for_dataset_b);
验证的自定义消息
有时您可能想为特定的验证设置自定义消息。为此,您可以将自定义消息设置为 Validator::make
的第三个参数,如下所示
$validator = Validator::make($dataset_a, $rules_for_dataset_a, [ 'required' => ':attribute harus diisi', 'email' => ':email tidak valid', // etc ]);
或者您可以使用 $validation->messages
如此
$validation_a = Validator::make($dataset_a, $rules_for_dataset_a); $validation_a->messages([ 'required' => ':attribute harus diisi', 'email' => ':email tidak valid', // etc ]); ... $validation_a->validate();
特定属性规则的自定义消息
有时您可能想为特定规则的属性设置自定义消息。为此,您可以使用冒号 :
作为消息分隔符或使用链式方法。
示例
$validation_a = Validator::make($dataset_a, [ 'age' => 'required|min:18' ]); $validation_a->messages([ 'age:min' => '18+ only', ]); $validation_a->validate();
或者使用链式方法
$validation_a = Validator::make($dataset_a, [ 'photo' => [ 'required', Validator::rule('uploaded_file')->fileTypes('jpeg|png')->message('Photo must be jpeg/png image') ] ]); $validation_a->validate();
翻译
翻译与自定义消息不同。当您为规则 in
、not_in
、mimes
和 uploaded_file
使用自定义消息时可能需要翻译。
例如,如果您使用规则 in:1,2,3
,我们将设置无效消息 "The Attribute only allows '1', '2', or '3'",其中部分 "'1', '2', or '3'" 来自 ":allowed_values" 标签。因此,如果您有自定义印度尼西亚语消息 ":attribute hanya memperbolehkan :allowed_values",我们将设置无效消息 "Attribute hanya memperbolehkan '1', '2', or '3'",其中 "or" 一词不是印度尼西亚语的一部分。
因此,为了解决这个问题,我们可以使用翻译如下
// Set translation for words 'and' and 'or'. $validation->translations([ 'and' => 'dan', 'or' => 'atau' ]); // Set custom message for 'in' rule $validation->message('in', ":attribute hanya memperbolehkan :allowed_values"); // Validate $validation = Validator::validate($inputs, [ 'nomor' => 'in:1,2,3' ]); $message = $validation->errors()->first('nomor'); // "Nomor hanya memperbolehkan '1', '2', atau '3'"
实际上,我们内置的规则只使用单词 "and" 和 "or",您可能需要翻译。
处理错误消息
错误消息收集在 Rakit\Validation\ErrorBag
对象中,您可以使用 errors()
方法获取它。
$validation = Validator::validate($inputs, $rules); $errors = $validation->errors(); // << ErrorBag
现在您可以使用以下方法检索错误消息
all(string $format = ':message')
获取所有消息作为扁平数组。
示例
$messages = $errors->all(); // [ // 'Email is not valid email', // 'Password minimum 6 character', // 'Password must contains capital letters' // ] $messages = $errors->all('<li>:message</li>'); // [ // '<li>Email is not valid email</li>', // '<li>Password minimum 6 character</li>', // '<li>Password must contains capital letters</li>' // ]
首先(string $format = ':message', bool $dotNotation = false)
从所有现有键中获取仅第一条消息。
示例
$messages = $errors->firstOfAll(); // [ // 'email' => Email is not valid email', // 'password' => 'Password minimum 6 character', // ] $messages = $errors->firstOfAll('<li>:message</li>'); // [ // 'email' => '<li>Email is not valid email</li>', // 'password' => '<li>Password minimum 6 character</li>', // ]
参数 $dotNotation
用于数组验证。如果它是 false
,则将返回原始数组结构;如果它是 true
,则将返回具有点符号键的扁平化数组。
例如
$messages = $errors->firstOfAll(':message', false); // [ // 'contacts' => [ // 1 => [ // 'email' => 'Email is not valid email', // 'phone' => 'Phone is not valid phone number' // ], // ], // ] $messages = $errors->firstOfAll(':message', true); // [ // 'contacts.1.email' => 'Email is not valid email', // 'contacts.1.phone' => 'Email is not valid phone number', // ]
first(string $key)
从给定键获取第一条消息。如果键有任何错误消息,则返回 string
;如果没有错误,则返回 null
。
例如
if ($emailError = $errors->first('email')) { echo $emailError; }
toArray()
按其键分组获取所有消息。
例如
$messages = $errors->toArray(); // [ // 'email' => [ // 'Email is not valid email' // ], // 'password' => [ // 'Password minimum 6 character', // 'Password must contains capital letters' // ] // ]
count()
获取消息计数。
has(string $key)
检查给定键是否有错误。如果键有错误,则返回 bool
,否则返回。
获取已验证、有效和无效数据
例如,你有如下验证
$validation = $validator->validate([ 'title' => 'Lorem Ipsum', 'body' => 'Lorem ipsum dolor sit amet ...', 'published' => null, 'something' => '-invalid-' ], [ 'title' => 'required', 'body' => 'required', 'published' => 'default:1|required|in:0,1', 'something' => 'required|numeric' ]);
您可以使用以下示例中的方法获取已验证数据、有效数据或无效数据
$validatedData = $validation->getValidatedData(); // [ // 'title' => 'Lorem Ipsum', // 'body' => 'Lorem ipsum dolor sit amet ...', // 'published' => '1' // notice this // 'something' => '-invalid-' // ] $validData = $validation->getValidData(); // [ // 'title' => 'Lorem Ipsum', // 'body' => 'Lorem ipsum dolor sit amet ...', // 'published' => '1' // ] $invalidData = $validation->getInvalidData(); // [ // 'something' => '-invalid-' // ]
可用规则
点击查看详细信息。
required
此验证字段下必须存在且不为 'empty'。
以下是一些示例
对于上传的文件,$_FILES['key']['error']
必须不是 UPLOAD_ERR_NO_FILE
。
required_if:another_field,value_1,value_2,...
此规则下的字段必须存在且不为空,如果 anotherfield 字段等于任何值。
例如,required_if:something,1,yes,on
当 something
的值为 1
、'1'
、'yes'
或 'on'
之一时,将强制要求。
required_unless:another_field,value_1,value_2,...
验证字段必须存在且不为空,除非 anotherfield 字段等于任何值。
required_with:field_1,field_2,...
验证字段必须存在且不为空,只有当其他指定的字段之一存在时。
required_without:field_1,field_2,...
验证字段必须存在且不为空,只有当其他指定的字段之一不存在时。
required_with_all:field_1,field_2,...
验证字段必须存在且不为空,只有当所有其他指定的字段都存在时。
required_without_all:field_1,field_2,...
验证字段必须存在且不为空,只有当所有其他指定的字段都不存在时。
uploaded_file:min_size,max_size,extension_a,extension_b,...
此规则将验证来自 $_FILES
的数据。此规则下的字段必须遵循以下规则才能有效:
$_FILES['key']['error']
必须是UPLOAD_ERR_OK
或UPLOAD_ERR_NO_FILE
。对于UPLOAD_ERR_NO_FILE
,您可以使用required
规则进行验证。- 如果指定了最小大小,上传的文件大小 不得 低于最小大小。
- 如果指定了最大大小,上传的文件大小 不得 超过最大大小。
- 如果指定了文件类型,MIME 类型必须是给定类型之一。
以下是一些示例定义和说明
uploaded_file
:上传文件是可选的。当它不为空时,它必须是ERR_UPLOAD_OK
。required|uploaded_file
:上传文件是必需的,并且必须是ERR_UPLOAD_OK
。uploaded_file:0,1M
:上传文件大小必须在 0 - 1 MB 之间,但上传文件是可选的。required|uploaded_file:0,1M,png,jpeg
:上传文件大小必须在 0 - 1MB 之间,并且 MIME 类型必须是image/jpeg
或image/png
。
可选地,如果您想在不同的大小和类型验证之间有单独的错误消息,您可以使用 mimes
规则来验证文件类型,并使用 min
、max
或 between
来验证其大小。
对于多个文件上传,PHP会提供不理想的数组$_FILES
结构(详细信息请参阅此处)。因此,我们创建了uploaded_file
规则来自动将$_FILES
值解析为有组织的数组结构。这意味着,您不仅可以使用min
、max
、between
或mimes
规则来验证多个文件上传。您只需将uploaded_file
规则应用于解析其值,并确保该值是正确的已上传文件值。
例如,如果您有如下输入文件
<input type="file" name="photos[]"/> <input type="file" name="photos[]"/> <input type="file" name="photos[]"/>
您可以简单地这样验证
$validation = $validator->validate($_FILES, [ 'photos.*' => 'uploaded_file:0,2M,jpeg,png' ]); // or $validation = $validator->validate($_FILES, [ 'photos.*' => 'uploaded_file|max:2M|mimes:jpeg,png' ]);
或者如果您有如下输入文件
<input type="file" name="images[profile]"/> <input type="file" name="images[cover]"/>
您可以这样验证
$validation = $validator->validate($_FILES, [ 'images.*' => 'uploaded_file|max:2M|mimes:jpeg,png', ]); // or $validation = $validator->validate($_FILES, [ 'images.profile' => 'uploaded_file|max:2M|mimes:jpeg,png', 'images.cover' => 'uploaded_file|max:5M|mimes:jpeg,png', ]);
现在,当您使用getValidData()
或getInvalidData()
时,您将得到像单文件上传一样的良好数组结构。
mimes:extension_a,extension_b,...
在验证过程中,$_FILES
项必须具有与列表中某个扩展名对应的MIME类型。
default/defaults
这是一个特殊的规则,它不会进行验证。它只是在属性为空或不存在时为您的属性设置默认值。
例如,如果您有如下验证
$validation = $validator->validate([ 'enabled' => null ], [ 'enabled' => 'default:1|required|in:0,1' 'published' => 'default:0|required|in:0,1' ]); $validation->passes(); // true // Get the valid/default data $valid_data = $validation->getValidData(); $enabled = $valid_data['enabled']; $published = $valid_data['published'];
验证通过,因为我们为enabled
和published
设置了默认值1
和0
,它们是有效的。然后我们可以获取有效/默认的数据。
此验证下的字段必须是有效的电子邮件地址。
uppercase
此验证下的字段必须是有效的大写。
lowercase
此验证下的字段必须是有效的小写。
json
此验证下的字段必须是有效的JSON字符串。
alpha
此规则下的字段必须完全由字母字符组成。
numeric
此规则下的字段必须是数字。
alpha_num
此规则下的字段必须完全由字母数字字符组成。
alpha_dash
此规则下的字段可以有字母数字字符,以及破折号和下划线。
alpha_spaces
此规则下的字段可以有字母字符,以及空格。
in:value_1,value_2,...
此规则下的字段必须在给定的值列表中。
此规则使用in_array
来检查值。默认情况下,in_array
禁用严格检查。因此,它不检查数据类型。如果您想启用严格检查,可以像以下示例中调用验证器一样
$validation = $validator->validate($data, [ 'enabled' => [ 'required', $validator('in', [true, 1])->strict() ] ]);
然后'enabled'值应该是布尔值true
或整数值1
。
not_in:value_1,value_2,...
此规则下的字段不得包含在给定的值列表中。
此规则也使用in_array
。您可以通过调用验证器并调用strict()
来启用严格检查,如上述in
规则中的示例所示。
min:number
此规则下的字段的大小必须大于或等于给定的数字。
对于字符串值,大小对应于字符数。对于整数或浮点值,大小对应于其数值。对于数组,大小对应于数组中的元素数量。如果您的值是数值字符串,您可以添加numeric
规则来按数值值而不是字符数来处理其大小。
您还可以使用此规则来验证上传的文件,以验证上传文件的最小大小。例如
$validation = $validator->validate([ 'photo' => $_FILES['photo'] ], [ 'photo' => 'required|min:1M' ]);
max:number
此规则下的字段的大小必须小于或等于给定的数字。值大小计算方式与min
规则相同。
您还可以使用此规则来验证上传的文件,以验证上传文件的最大大小。例如
$validation = $validator->validate([ 'photo' => $_FILES['photo'] ], [ 'photo' => 'required|max:2M' ]);
between:min,max
根据此规则的字段大小必须在min和max参数之间。值大小以与min
和max
规则相同的方式进行计算。
您还可以使用此规则验证上传的文件,以验证上传文件的大小。例如
$validation = $validator->validate([ 'photo' => $_FILES['photo'] ], [ 'photo' => 'required|between:1M,2M' ]);
digits:value
正在验证的字段必须是数值型,并且必须具有value
的确切长度。
digits_between:min,max
正在验证的字段长度必须在给定的min
和max
之间。
url
根据此规则的字段必须是有效的URL格式。默认情况下,它检查常见的URL方案格式,如any_scheme://...
。但您可以根据需要指定URL方案。
例如
$validation = $validator->validate($inputs, [ 'random_url' => 'url', // value can be `any_scheme://...` 'https_url' => 'url:http', // value must be started with `https://` 'http_url' => 'url:http,https', // value must be started with `http://` or `https://` 'ftp_url' => 'url:ftp', // value must be started with `ftp://` 'custom_url' => 'url:custom', // value must be started with `custom://` 'mailto_url' => 'url:mailto', // value must conatin valid mailto URL scheme like `mailto:a@mail.com,b@mail.com` 'jdbc_url' => 'url:jdbc', // value must contain valid jdbc URL scheme like `jdbc:mysql://localhost/dbname` ]);
对于常见的URL方案和mailto,我们结合
FILTER_VALIDATE_URL
来验证URL格式,以及使用preg_match
来验证它的方案。除了JDBC URL之外,目前它仅检查有效的JDBC方案。
integer
根据t规则的字段必须是整数。boolean
根据此规则的字段必须是布尔型。接受的输入是true
、false
、1
、0
、"1"
和"0"
。
ip
根据此规则的字段必须是有效的IPv4或IPv6。
ipv4
根据此规则的字段必须是有效的IPv4。
ipv6
根据此规则的字段必须是有效的IPv6。
extension:extension_a,extension_b,...
根据此规则的字段必须以列表中指定的扩展名之一结尾。
这对于验证给定路径或URL的文件类型非常有用。应使用mimes
规则来验证上传。
array
根据此规则的字段必须是数组。
same:another_field
根据此规则的字段值必须与another_field
的值相同。
regex:/your-regex/
根据此规则的字段必须与给定的正则表达式匹配。
date:format
根据此规则的字段必须是有效的日期格式。参数format
是可选的,默认格式是Y-m-d
。
accepted
根据此规则的字段必须是'on'
、'yes'
、'1'
、'true'
或true
之一。
present
根据此规则的字段必须存在,无论其值如何。
different:another_field
same
的对立面。根据此规则的字段值必须与another_field
的值不同。
after:tomorrow
可以将任何可以被strtotime
解析的参数传递给此规则。有效的示例包括
- after:next week
- after:2016-12-31
- after:2016
- after:2016-12-31 09:56:02
before:yesterday
这同样可以像after规则一样工作。传递任何可以被strtotime
解析的内容。
callback
您可以使用此规则来定义自己的验证规则。此规则不能使用字符串管道进行注册。要使用此规则,您应该在规则数组中放置闭包。
例如
$validation = $validator->validate($_POST, [ 'even_number' => [ 'required', function ($value) { // false = invalid return (is_numeric($value) AND $value % 2 === 0); } ] ]);
您可以通过返回一个字符串来设置无效消息。例如,上面的示例将是
$validation = $validator->validate($_POST, [ 'even_number' => [ 'required', function ($value) { if (!is_numeric($value)) { return ":attribute must be numeric."; } if ($value % 2 !== 0) { return ":attribute is not even number."; } // you can return true or don't return anything if value is valid } ] ]);
注意:
dimtrovich\Validation\Rules\Callback
实例已绑定到您的闭包中。因此,您可以使用$this
访问规则属性和方法。
nullable
根据此规则的字段可能是空的。
注册/覆盖规则
使用自定义验证规则的另一种方法是创建一个扩展dimtrovich\Validation\Rule
的类。然后使用setValidator
或addValidator
进行注册。
例如,您想要创建一个检查字段在数据库中可用性的unique
验证器。
首先,让我们创建UniqueRule
类
<?php use Dimtrovich\Validation\Rules\AbstractRule; class UniqueRule extends AbstractRule { protected $message = ":attribute :value has been used"; protected $fillableParams = ['table', 'column', 'except']; protected $pdo; public function __construct(PDO $pdo) { $this->pdo = $pdo; } public function check($value): bool { // make sure required parameters exists $this->requireParameters(['table', 'column']); // getting parameters $column = $this->parameter('column'); $table = $this->parameter('table'); $except = $this->parameter('except'); if ($except AND $except == $value) { return true; } // do query $stmt = $this->pdo->prepare("select count(*) as count from `{$table}` where `{$column}` = :value"); $stmt->bindParam(':value', $value); $stmt->execute(); $data = $stmt->fetch(PDO::FETCH_ASSOC); // true for valid, false for invalid return intval($data['count']) === 0; } }
然后您需要将UniqueRule
实例注册到验证器中,如下所示
use Dimtrovich\Validation\Validator; $validator = new Validator; $validator->addValidator('unique', new UniqueRule($pdo));
现在您可以使用它像这样
$validation = $validator->validate($_POST, [ 'email' => 'email|unique:users,email,exception@mail.com' ]);
在上面的 UniqueRule
中,属性 $message
用于默认无效信息。而属性 $fillable_params
用于 fillParameters
方法(在 dimtrovich\Validation\Rule
类中定义)。默认情况下,fillParameters
将填充 $fillable_params
中列出的参数。例如,上面的示例中的 unique:users,email,exception@mail.com
将设置
$params['table'] = 'users'; $params['column'] = 'email'; $params['except'] = 'exception@mail.com';
如果您希望自定义规则接受如
in
、not_in
或uploaded_file
规则的参数列表,您只需在自定义规则类中覆盖fillParameters(array $params)
方法。
注意,我们上面创建的 unique
规则也可以这样使用
$validation = $validator->validate($_POST, [ 'email' => [ 'required', 'email', $validator('unique', 'users', 'email')->message('Custom message') ] ]);
因此,您可以通过添加一些返回自身实例的方法来改进上面的 UniqueRule
类
<?php use dimtrovich\Validation\Rule; class UniqueRule extends Rule { ... public function table($table) { $this->params['table'] = $table; return $this; } public function column($column) { $this->params['column'] = $column; return $this; } public function except($value) { $this->params['except'] = $value; return $this; } ... }
然后您可以用这种方式使用它
$validation = $validator->validate($_POST, [ 'email' => [ 'required', 'email', $validator('unique')->table('users')->column('email')->except('exception@mail.com')->message('Custom message') ] ]);
隐式规则
隐式规则是一种规则,如果它无效,则忽略后续规则。例如,如果属性未通过 required*
规则,则大多数情况下,后续规则也将无效。因此,为了防止我们的后续规则消息被收集,我们将 required*
规则设置为隐式。
要使您的自定义规则成为隐式的,您可以设置 $implicit
属性值为 true
。例如
<?php use dimtrovich\Validation\Rule; class YourCustomRule extends Rule { protected $implicit = true; }
修改值
在某些情况下,您可能希望自定义规则能够修改其属性值,例如我们的 default/defaults
规则。因此,在当前和后续规则检查中,将使用您修改的值。
为此,您应该实现 dimtrovich\Validation\Rules\Interfaces\ModifyValue
并在自定义规则类中创建 modifyValue($value)
方法。
例如
<?php use dimtrovich\Validation\Rule; use dimtrovich\Validation\Rules\Interfaces\ModifyValue; class YourCustomRule extends Rule implements ModifyValue { ... public function modifyValue($value) { // Do something with $value return $value; } ... }
在验证之前
您可能希望在验证运行之前做一些准备工作。例如,我们的 uploaded_file
规则将把来自 $_FILES
(不理想的)数组的属性值解析为有组织的数组结构,这样我们就可以像验证其他数据一样验证多个文件上传。
为此,您应该实现 dimtrovich\Validation\Rules\Interfaces\BeforeValidate
并在自定义规则类中创建 beforeValidate()
方法。
例如
<?php use dimtrovich\Validation\Rule; use dimtrovich\Validation\Rules\Interfaces\BeforeValidate; class YourCustomRule extends Rule implements BeforeValidate { ... public function beforeValidate() { $attribute = $this->getAttribute(); // dimtrovich\Validation\Attribute instance $validation = $this->validation; // dimtrovich\Validation\Validation instance // Do something with $attribute and $validation // For example change attribute value $validation->setValue($attribute->getKey(), "your custom value"); } ... }