验证
介绍
Laravel 提供了几种不同的方法来验证应用程序的传入数据。默认情况下,Laravel 的基础控制器类使用 ValidatesRequests
trait,它提供了一种方便的方法来使用各种强大的验证规则验证传入的 HTTP 请求。
验证快速入门
为了了解 Laravel 强大的验证功能,让我们来看一个完整的示例,验证表单并将错误消息显示给用户。
定义路由
首先,假设我们在 routes/web.php
文件中定义了以下路由:
Route::get('post/create', 'PostController@create');
Route::post('post', 'PostController@store');
GET
路由将显示一个表单,供用户创建新的博客文章,而 POST
路由将把新的博客文章存储到数据库中。
创建控制器
接下来,让我们看看一个简单的控制器,它处理这些路由。我们将暂时留空 store
方法:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* 显示创建新博客文章的表单。
*
* @return Response
*/
public function create()
{
return view('post.create');
}
/**
* 存储新的博客文章。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
// 验证并存储博客文章...
}
}
编写验证逻辑
现在我们准备在 store
方法中填写验证新博客文章的逻辑。为此,我们将使用 Illuminate\Http\Request
对象提供的 validate
方法。如果验证规则通过,代码将正常执行;如果验证失败,将抛出异常,并自动向用户发送适当的错误响应。在传统的 HTTP 请求中,将生成重定向响应,而对于 AJAX 请求,将发送 JSON 响应。
为了更好地理解 validate
方法,让我们回到 store
方法:
/**
* 存储新的博客文章。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// 博客文章是有效的...
}
如您所见,我们将所需的验证规则传递给 validate
方法。同样,如果验证失败,将自动生成适当的响应。如果验证通过,我们的控制器将继续正常执行。
或者,可以将验证规则指定为规则数组,而不是单个 |
分隔的字符串:
$validatedData = $request->validate([
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
]);
您可以使用 validateWithBag
方法验证请求,并将任何错误消息存储在 命名错误包 中:
$validatedData = $request->validateWithBag('post', [
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
]);
在第一次验证失败时停止
有时您可能希望在属性的第一次验证失败后停止运行验证规则。为此,请为属性分配 bail
规则:
$request->validate([
'title' => 'bail|required|unique:posts|max:255',
'body' => 'required',
]);
在此示例中,如果 title
属性上的 unique
规则失败,则不会检查 max
规则。规则将按分配的顺序进行验证。
关于嵌套属性的说明
如果您的 HTTP 请求包含“嵌套”参数,您可以使用“点”语法在验证规则中指定它们:
$request->validate([
'title' => 'required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);
显示验证错误
那么,如果传入的请求参数未通过给定的验证规则怎么办?如前所述,Laravel 将自动将用户重定向回其先前的位置。此外,所有验证错误将自动 闪存到会话。
再次注意,我们不必在 GET
路由中显式绑定错误消息到视图。这是因为 Laravel 将检查会话数据中的错误,并在可用时自动将它们绑定到视图。$errors
变量将是 Illuminate\Support\MessageBag
的实例。有关此对象的更多信息,请查看其 文档。
$errors
变量由 Illuminate\View\Middleware\ShareErrorsFromSession
中间件绑定到视图,该中间件由 web
中间件组提供。当应用此中间件时,您的视图中将始终可用 $errors
变量,允许您方便地假设 $errors
变量始终已定义并可以安全使用。
因此,在我们的示例中,当验证失败时,用户将被重定向到我们控制器的 create
方法,允许我们在视图中显示错误消息:
<!-- /resources/views/post/create.blade.php -->
<h1>创建文章</h1>
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- 创建文章表单 -->
@error
指令
您还可以使用 @error
Blade 指令快速检查给定属性是否存在验证错误消息。在 @error
指令中,您可以回显 $message
变量以显示错误消息:
<!-- /resources/views/post/create.blade.php -->
<label for="title">文章标题</label>
<input id="title" type="text" class="@error('title') is-invalid @enderror">
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
关于可选字段的说明
默认情况下,Laravel 在应用程序的全局中间件堆栈中包含 TrimStrings
和 ConvertEmptyStringsToNull
中间件。这些中间件由 App\Http\Kernel
类列在堆栈中。因此,如果您不希望验证器将 null
值视为无效,通常需要将“可选”请求字段标记为 nullable
。例如:
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
在此示例中,我们指定 publish_at
字段可以是 null
或有效的日期表示。如果未将 nullable
修饰符添加到规则定义中,验证器将视 null
为无效日期。
AJAX 请求与验证
在此示例中,我们使用传统表单将数据发送到应用程序。然而,许多应用程序使用 AJAX 请求。在 AJAX 请求期间使用 validate
方法时,Laravel 不会生成重定向响应。相反,Laravel 会生成一个包含所有验证错误的 JSON 响应。此 JSON 响应将以 422 HTTP 状态代码发送。
表单请求验证
创建表单请求
对于更复杂的验证场景,您可能希望创建一个“表单请求”。表单请求是包含验证逻辑的自定义请求类。要创建表单请求类,请使用 make:request
Artisan CLI 命令:
php artisan make:request StoreBlogPost
生成的类将放置在 app/Http/Requests
目录中。如果此目录不存在,运行 make:request
命令时将创建它。让我们在 rules
方法中添加一些验证规则:
/**
* 获取适用于请求的验证规则。
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
您可以在 rules
方法的签名中类型提示您需要的任何依赖项。它们将通过 Laravel 服务容器 自动解析。
那么,验证规则是如何评估的?您只需在控制器方法中类型提示请求即可。在调用控制器方法之前,将验证传入的表单请求,这意味着您不需要在控制器中混杂任何验证逻辑:
/**
* 存储传入的博客文章。
*
* @param StoreBlogPost $request
* @return Response
*/
public function store(StoreBlogPost $request)
{
// 传入的请求是有效的...
// 检索验证后的输入数据...
$validated = $request->validated();
}
如果验证失败,将生成重定向响应以将用户发送回其先前的位置。错误也将闪存到会话中,以便显示。如果请求是 AJAX 请求,将返回一个包含 422 状态代码的 HTTP 响应,其中包括验证错误的 JSON 表示。
向表单请求添加后钩子
如果您想向表单请求添加“后”钩子,可以使用 withValidator
方法。此方法接收完全构造的验证器,允许您在实际评估验证规则之前调用其任何方法:
/**
* 配置验证器实例。
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', '此字段有问题!');
}
});
}
授权表单请求
表单请求类还包含一个 authorize
方法。在此方法中,您可以检查经过身份验证的用户是否确实有权更新给定资源。例如,您可以确定用户是否确实拥有他们尝试更新的博客评论:
/**
* 确定用户是否有权发出此请求。
*
* @return bool
*/
public function authorize()
{
$comment = Comment::find($this->route('comment'));
return $comment && $this->user()->can('update', $comment);
}
由于所有表单请求都扩展了基础 Laravel 请求类,我们可以使用 user
方法访问当前经过身份验证的用户。还要注意上面示例中的 route
方法调用。此方法允许您访问正在调用的路由上定义的 URI 参数,例如示例中的 {comment}
参数:
Route::post('comment/{comment}');
如果 authorize
方法返回 false
,将自动返回一个带有 403 状态代码的 HTTP 响应,并且您的控制器方法将不会执行。
如果您计划在应用程序的其他部分中进行授权逻辑,请从 authorize
方法返回 true
:
/**
* 确定用户是否有权发出此请求。
*
* @return bool
*/
public function authorize()
{
return true;
}
您可以在 authorize
方法的签名中类型提示您需要的任何依赖项。它们将通过 Laravel 服务容器 自动解析。
自定义错误消息
您可以通过覆盖 messages
方法来自定义表单请求使用的错误消息。此方法应返回一个属性/规则对及其对应错误消息的数组:
/**
* 获取定义的验证规则的错误消息。
*
* @return array
*/
public function messages()
{
return [
'title.required' => '需要一个标题',
'body.required' => '需要一条消息',
];
}
自定义验证属性
如果您希望将验证消息中的 :attribute
部分替换为自定义属性名称,可以通过覆盖 attributes
方法指定自定义名称。此方法应返回一个属性/名称对的数组:
/**
* 获取验证器错误的自定义属性。
*
* @return array
*/
public function attributes()
{
return [
'email' => '电子邮件地址',
];
}
准备验证输入
如果您需要在应用验证规则之前对请求中的任何数据进行清理,可以使用 prepareForValidation
方法:
use Illuminate\Support\Str;
/**
* 准备验证的数据。
*
* @return void
*/
protected function prepareForValidation()
{
$this->merge([
'slug' => Str::slug($this->slug),
]);
}
手动创建验证器
如果您不想在请求上使用 validate
方法,可以使用 Validator
facade 手动创建验证器实例。facade 上的 make
方法生成一个新的验证器实例:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class PostController extends Controller
{
/**
* 存储新的博客文章。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
return redirect('post/create')
->withErrors($validator)
->withInput();
}
// 存储博客文章...
}
}
传递给 make
方法的第一个参数是正在验证的数据。第二个参数是应应用于数据的验证规则。
在检查请求验证是否失败后,您可以使用 withErrors
方法将错误消息闪存到会话中。使用此方法时,重定向后将自动与视图共享 $errors
变量,允许您轻松地将它们显示给用户。withErrors
方法接受一个验证器、一个 MessageBag
或一个 PHP array
。
自动重定向
如果您希望手动创建验证器实例,但仍然利用请求的 validate
方法提供的自动重定向,可以在现有验证器实例上调用 validate
方法。如果验证失败,用户将自动重定向,或者在 AJAX 请求的情况下,将返回 JSON 响应:
Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
])->validate();
如果验证失败,您可以使用 validateWithBag
方法将错误消息存储在 命名错误包 中:
Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
])->validateWithBag('post');
命名错误包
如果您在单个页面上有多个表单,您可能希望命名错误消息的 MessageBag
,以便您可以检索特定表单的错误消息。将名称作为第二个参数传递给 withErrors
:
return redirect('register')
->withErrors($validator, 'login');
然后,您可以从 $errors
变量中访问命名的 MessageBag
实例:
{{ $errors->login->first('email') }}
验证后钩子
验证器还允许您附加在验证完成后运行的回调。这使您可以轻松地执行进一步的验证,甚至将更多错误消息添加到消息集合中。要开始,请在验证器实例上使用 after
方法:
$validator = Validator::make(...);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', '此字段有问题!');
}
});
if ($validator->fails()) {
//
}
处理错误消息
在 Validator
实例上调用 errors
方法后,您将收到一个 Illuminate\Support\MessageBag
实例,该实例具有多种方便的方法来处理错误消息。自动提供给所有视图的 $errors
变量也是 MessageBag
类的实例。
检索字段的第一个错误消息
要检索给定字段的第一个错误消息,请使用 first
方法:
$errors = $validator->errors();
echo $errors->first('email');
检索字段的所有错误消息
如果您需要检索给定字段的所有消息数组,请使用 get
方法:
foreach ($errors->get('email') as $message) {
//
}
如果您正在验证数组表单字段,可以使用 *
字符检索每个数组元素的所有消息:
foreach ($errors->get('attachments.*') as $message) {
//
}
检索所有字段的所有错误消息
要检索所有字段的所有消息数组,请使用 all
方法:
foreach ($errors->all() as $message) {
//
}
确定字段是否存在消息
可以使用 has
方法确定给定字段是否存在任何错误消息:
if ($errors->has('email')) {
//
}
自定义错误消息
如果需要,您可以为验证使用自定义错误消息,而不是默认消息。有几种方法可以指定自定义消息。首先,您可以将自定义消息作为第三个参数传递给 Validator::make
方法:
$messages = [
'required' => '需要 :attribute 字段。',
];
$validator = Validator::make($input, $rules, $messages);
在此示例中,:attribute
占位符将被替换为正在验证的字段的实际名称。您还可以在验证消息中使用其他占位符。例如:
$messages = [
'same' => ':attribute 和 :other 必须匹配。',
'size' => ':attribute 必须正好是 :size。',
'between' => ':attribute 值 :input 不在 :min - :max 之间。',
'in' => ':attribute 必须是以下类型之一::values',
];
为给定属性指定自定义消息
有时您可能希望仅为特定字段指定自定义错误消息。您可以使用“点”表示法来实现。首先指定属性的名称,然后是规则:
$messages = [
'email.required' => '我们需要知道您的电子邮件地址!',
];
在语言文件中指定自定义消息
在大多数情况下,您可能会在语言文件中指定自定义消息,而不是直接传递给 Validator
。为此,请将您的消息添加到 resources/lang/xx/validation.php
语言文件中的 custom
数组中。
'custom' => [
'email' => [
'required' => '我们需要知道您的电子邮件地址!',
],
],
指定自定义属性值
如果您希望将验证消息中的 :attribute
部分替换为自定义属性名称,可以在 resources/lang/xx/validation.php
语言文件的 attributes
数组中指定自定义名称:
'attributes' => [
'email' => '电子邮件地址',
],
您还可以将自定义属性作为第四个参数传递给 Validator::make
方法:
$customAttributes = [
'email' => '电子邮件地址',
];
$validator = Validator::make($input, $rules, $messages, $customAttributes);
在语言文件中指定自定义值
有时您可能需要将验证消息中的 :value
部分替换为值的自定义表示。例如,考虑以下规则,该规则指定如果 payment_type
的值为 cc
,则需要信用卡号:
$request->validate([
'credit_card_number' => 'required_if:payment_type,cc'
]);
如果此验证规则失败,它将生成以下错误消息:
信用卡号字段在支付类型为 cc 时是必需的。
您可以在 validation
语言文件中定义 values
数组来指定支付类型值的自定义表示,而不是显示 cc
:
'values' => [
'payment_type' => [
'cc' => '信用卡'
],
],
现在,如果验证规则失败,它将生成以下消息:
信用卡号字段在支付类型为信用卡时是必需的。
可用的验证规则
以下是所有可用验证规则及其功能的列表:
接受活动 URL之后 (日期)之后或等于 (日期)字母字母破折号字母数字数组中止之前 (日期)之前或等于 (日期)之间布尔确认日期日期等于日期格式不同数字数字之间尺寸 (图像文件)不同电子邮件以...结束排除如果排除除非存在 (数据库)文件已填充大于大于或等于图像 (文件)在在数组中整数IP 地址JSON小于小于或等于最大MIME 类型通过文件扩展名的 MIME 类型最小不在非正则表达式可为空数字密码存在正则表达式必需必需如果必需除非必需与必需与所有必需无必需无所有相同大小有时以...开始字符串时区唯一 (数据库)URLUUID
accepted
验证字段必须是 yes、on、1 或 true。这对于验证“服务条款”接受非常有用。
active_url
验证字段必须具有有效的 A 或 AAAA 记录,根据 dns_get_record
PHP 函数。提供的 URL 的主机名使用 parse_url
PHP 函数提取,然后传递给 dns_get_record
。
after:date
验证字段的值必须在给定日期之后。日期将传递给 strtotime
PHP 函数:
'start_date' => 'required|date|after:tomorrow'
除了传递一个日期字符串给 strtotime
评估,你还可以指定另一个字段来与日期进行比较:
'finish_date' => 'required|date|after:start_date'
after_or_equal:date
验证字段的值必须在给定日期之后或等于给定日期。有关更多信息,请参阅 after 规则。
alpha
验证字段必须完全是字母字符。
alpha_dash
验证字段可以包含字母数字字符,以及破折号和下划线。
alpha_num
验证字段必须完全是字母数字字符。
array
验证字段必须是 PHP array
。
bail
在第一次验证失败后停止运行验证规则。
before:date
验证字段的值必须在给定日期之前。日期将传递给 PHP strtotime
函数。此外,像 after
规则一样,可以将另一个验证字段的名称作为 date
的值提供。
before_or_equal:date
验证字段的值必须在给定日期之前或等于给定日期。日期将传递给 PHP strtotime
函数。此外,像 after
规则一样,可以将另一个验证字段的名称作为 date
的值提供。
between:min,max
验证字段的大小必须在给定的 min 和 max 之间。字符串、数字、数组和文件的评估方式与 size
规则相同。
boolean
验证字段必须能够被转换为布尔值。接受的输入是 true
、false
、1
、0
、"1"
和 "0"
。
confirmed
验证字段必须有一个匹配的 foo_confirmation
字段。例如,如果验证字段是 password
,则输入中必须存在一个匹配的 password_confirmation
字段。
date
验证字段必须是一个有效的、非相对的日期,根据 strtotime
PHP 函数。
date_equals:date
验证字段必须等于给定日期。日期将传递给 PHP strtotime
函数。
date_format:format
验证字段必须匹配给定的 format。在验证字段时,您应该使用 either date
或 date_format
。此验证规则支持 PHP 的 DateTime 类支持的所有格式。
different:field
验证字段的值必须与 field 不同。
digits:value
验证字段必须是 numeric 并且必须具有 value 的确切长度。
digits_between:min,max
验证字段必须是 numeric 并且必须具有在给定 min 和 max 之间的长度。
dimensions
验证的文件必须是符合规则参数指定的尺寸约束的图像:
'avatar' => 'dimensions:min_width=100,min_height=200'
可用的约束有:min_width、max_width、min_height、max_height、width、height、ratio。
ratio 约束应表示为宽度除以高度。可以通过 3/2
这样的声明或 1.5
这样的浮点数来指定:
'avatar' => 'dimensions:ratio=3/2'
由于此规则需要多个参数,您可以使用 Rule::dimensions
方法来流畅地构建规则:
use Illuminate\Validation\Rule;
Validator::make($data, [
'avatar' => [
'required',
Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2),
],
]);
distinct
在处理数组时,验证字段不得有任何重复值。
'foo.*.id' => 'distinct'
email
验证字段必须格式化为电子邮件地址。在后台,此验证规则使用 egulias/email-validator
包来验证电子邮件地址。默认情况下,应用 RFCValidation
验证器,但您也可以应用其他验证样式:
'email' => 'email:rfc,dns'
上面的示例将应用 RFCValidation
和 DNSCheckValidation
验证。以下是您可以应用的验证样式的完整列表:
rfc
:RFCValidation
strict
:NoRFCWarningsValidation
dns
:DNSCheckValidation
spoof
:SpoofCheckValidation
filter
:FilterEmailValidation
filter
验证器在后台使用 PHP 的 filter_var
函数,随 Laravel 一起提供,是 Laravel 5.8 之前的行为。dns
和 spoof
验证器需要 PHP intl
扩展。
ends_with:foo,bar,...
验证字段必须以给定值之一结尾。
exclude_if:anotherfield,value
如果 anotherfield 字段等于 value,则验证字段将从 validate
和 validated
方法返回的请求数据中排除。
exclude_unless:anotherfield,value
除非 anotherfield 字段等于 value,否则验证字段将从 validate
和 validated
方法返回的请求数据中排除。
exists:table,column
验证字段必须存在于给定的数据库表中。
基本用法
'state' => 'exists:states'
如果未指定 column
选项,将使用字段名称。
指定自定义列名
'state' => 'exists:states,abbreviation'
有时,您可能需要指定用于 exists
查询的特定数据库连接。您可以通过使用“点”语法将连接名称添加到表名来实现这一点:
'email' => 'exists:connection.staff,email'
您可以指定应使用的 Eloquent 模型来确定表名,而不是直接指定表名:
'user_id' => 'exists:App\User,id'
如果您想自定义验证规则执行的查询,可以使用 Rule
类来流畅地定义规则。在此示例中,我们还将指定验证规则为数组,而不是使用 |
字符来分隔它们:
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::exists('staff')->where(function ($query) {
$query->where('account_id', 1);
}),
],
]);
file
验证字段必须是成功上传的文件。
filled
验证字段在存在时不得为空。
gt:field
验证字段必须大于给定的 field。两个字段必须是相同类型。字符串、数字、数组和文件的评估方式与 size
规则相同。
gte:field
验证字段必须大于或等于给定的 field。两个字段必须是相同类型。字符串、数字、数组和文件的评估方式与 size
规则相同。
image
验证的文件必须是图像(jpeg、png、bmp、gif、svg 或 webp)
in:foo,bar,...
验证字段必须包含在给定值列表中。由于此规则通常需要您 implode
一个数组,因此可以使用 Rule::in
方法来流畅地构建规则:
use Illuminate\Validation\Rule;
Validator::make($data, [
'zones' => [
'required',
Rule::in(['first-zone', 'second-zone']),
],
]);
in_array:anotherfield.*
验证字段必须存在于 anotherfield 的值中。
integer
验证字段必须是整数。
此验证规则不验证输入是否为“整数”变量类型,仅验证输入是包含整数的字符串或数字值。
ip
验证字段必须是 IP 地址。
ipv4
验证字段必须是 IPv4 地址。
ipv6
验证字段必须是 IPv6 地址。
json
验证字段必须是有效的 JSON 字符串。
lt:field
验证字段必须小于给定的 field。两个字段必须是相同类型。字符串、数字、数组和文件的评估方式与 size
规则相同。
lte:field
验证字段必须小于或等于给定的 field。两个字段必须是相同类型。字符串、数字、数组和文件的评估方式与 size
规则相同。
max:value
验证字段必须小于或等于最大 value。字符串、数字、数组和文件的评估方式与 size
规则相同。
mimetypes:text/plain,...
验证的文件必须匹配给定的 MIME 类型之一:
'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime'
为了确定上传文件的 MIME 类型,将读取文件的内容,框架将尝试猜测 MIME 类型,这可能与客户端提供的 MIME 类型不同。
mimes:foo,bar,...
验证的文件必须具有与列出的扩展名对应的 MIME 类型。
MIME 规则的基本用法
'photo' => 'mimes:jpeg,bmp,png'
即使您只需要指定扩展名,此规则实际上通过读取文件的内容并猜测其 MIME 类型来验证文件的 MIME 类型。
可以在以下位置找到 MIME 类型及其对应扩展名的完整列表:https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
min:value
验证字段必须具有最小 value。字符串、数字、数组和文件的评估方式与 size
规则相同。
not_in:foo,bar,...
验证字段不得包含在给定值列表中。可以使用 Rule::notIn
方法来流畅地构建规则:
use Illuminate\Validation\Rule;
Validator::make($data, [
'toppings' => [
'required',
Rule::notIn(['sprinkles', 'cherries']),
],
]);
not_regex:pattern
验证字段不得匹配给定的正则表达式。
在内部,此规则使用 PHP preg_match
函数。指定的模式应遵循 preg_match
所需的相同格式,并因此包括有效的分隔符。例如:'email' => 'not_regex:/^.+$/i'
。
注意: 使用 regex
/ not_regex
模式时,可能需要在数组中指定规则,而不是使用管道分隔符,特别是当正则表达式包含管道字符时。
nullable
验证字段可以是 null
。这在验证可以包含 null
值的字符串和整数等原始类型时特别有用。
numeric
验证字段必须是数字。
password
验证字段必须与经过身份验证的用户的密码匹配。您可以使用规则的第一个参数指定身份验证守卫:
'password' => 'password:api'
present
验证字段必须存在于输入数据中,但可以为空。
regex:pattern
验证字段必须匹配给定的正则表达式。
在内部,此规则使用 PHP preg_match
函数。指定的模式应遵循 preg_match
所需的相同格式,并因此包括有效的分隔符。例如:'email' => 'regex:/^.+@.+$/i'
。
注意: 使用 regex
/ not_regex
模式时,可能需要在数组中指定规则,而不是使用管道分隔符,特别是当正则表达式包含管道字符时。
required
验证字段必须存在于输入数据中且不为空。如果以下条件之一为真,则字段被视为“空”:
- 值是
null
。 - 值是空字符串。
- 值是空数组或空的
Countable
对象。 - 值是没有路径的上传文件。
required_if:anotherfield,value,...
如果 anotherfield 字段等于任何 value,则验证字段必须存在且不为空。
如果您想为 required_if
规则构建更复杂的条件,可以使用 Rule::requiredIf
方法。此方法接受一个布尔值或一个闭包。当传递一个闭包时,闭包应返回 true
或 false
以指示验证字段是否为必需:
use Illuminate\Validation\Rule;
Validator::make($request->all(), [
'role_id' => Rule::requiredIf($request->user()->is_admin),
]);
Validator::make($request->all(), [
'role_id' => Rule::requiredIf(function () use ($request) {
return $request->user()->is_admin;
}),
]);
required_unless:anotherfield,value,...
除非 anotherfield 字段等于任何 value,否则验证字段必须存在且不为空。
required_with:foo,bar,...
验证字段必须存在且不为空,仅当 其他指定字段中的任何一个存在时。
required_with_all:foo,bar,...
验证字段必须存在且不为空,仅当 所有其他指定字段都存在时。
required_without:foo,bar,...
验证字段必须存在且不为空,仅当 其他指定字段中的任何一个不存在时。
required_without_all:foo,bar,...
验证字段必须存在且不为空,仅当 所有其他指定字段都不存在时。
same:field
给定的 field 必须与验证字段匹配。
size:value
验证字段的大小必须与给定的 value 匹配。对于字符串数据,value 对应于字符数。对于数字数据,value 对应于给定的整数值(属性还必须具有 numeric
或 integer
规则)。对于数组,size 对应于数组的 count
。对于文件,size 对应于文件大小(以千字节为单位)。让我们看一些例子:
// 验证字符串是否正好为 12 个字符长...
'title' => 'size:12';
// 验证提供的整数是否等于 10...
'seats' => 'integer|size:10';
// 验证数组是否正好有 5 个元素...
'tags' => 'array|size:5';
// 验证上传的文件是否正好为 512 千字节...
'image' => 'file|size:512';
starts_with:foo,bar,...
验证字段必须以给定值之一开头。
string
验证字段必须是字符串。如果您希望字段也可以为 null
,则应为字段分配 nullable
规则。
timezone
验证字段必须是根据 timezone_identifiers_list
PHP 函数的有效时区标识符。
unique:table,column,except,idColumn
验证字段不得存在于给定的数据库表中。
指定自定义表/列名:
您可以指定应使用的 Eloquent 模型来确定表名,而不是直接指定表名:
'email' => 'unique:App\User,email_address'
column
选项可用于指定字段对应的数据库列。如果未指定 column
选项,将使用字段名称。
'email' => 'unique:users,email_address'
自定义数据库连接
有时,您可能需要为验证器执行的数据库查询设置自定义连接。如上所示,设置 unique:users
作为验证规则将使用默认数据库连接查询数据库。要覆盖此设置,请使用“点”语法指定连接和表名:
'email' => 'unique:connection.users,email_address'
强制唯一规则忽略给定 ID:
有时,您可能希望在唯一检查期间忽略给定的 ID。例如,考虑一个包含用户姓名、电子邮件地址和位置的“更新个人资料”屏幕。您可能希望验证电子邮件地址是唯一的。但是,如果用户仅更改名称字段而不是电子邮件字段,您不希望抛出验证错误,因为用户已经是电子邮件地址的所有者。
要指示验证器忽略用户的 ID,我们将使用 Rule
类来流畅地定义规则。在此示例中,我们还将指定验证规则为数组,而不是使用 |
字符来分隔规则:
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
]);
您不应将任何用户控制的请求输入传递给 ignore
方法。相反,您应该只传递系统生成的唯一 ID,例如来自 Eloquent 模型实例的自动递增 ID 或 UUID。否则,您的应用程序将容易受到 SQL 注入攻击。
您可以传递整个模型实例,而不是将模型键的值传递给 ignore
方法。Laravel 将自动从模型中提取键:
Rule::unique('users')->ignore($user)
如果您的表使用的主键列名不是 id
,则可以在调用 ignore
方法时指定列名:
Rule::unique('users')->ignore($user->id, 'user_id')
默认情况下,unique
规则将检查与正在验证的属性名称匹配的列的唯一性。但是,您可以将不同的列名作为 unique
方法的第二个参数传递:
Rule::unique('users', 'email_address')->ignore($user->id),
添加额外的 Where 子句:
您还可以通过使用 where
方法自定义查询来指定额外的查询约束。例如,让我们添加一个验证 account_id
为 1
的约束:
'email' => Rule::unique('users')->where(function ($query) {
return $query->where('account_id', 1);
})
url
验证字段必须是有效的 URL。
uuid
验证字段必须是有效的 RFC 4122(版本 1、3、4 或 5)通用唯一标识符 (UUID)。
有条件地添加规则
当字段具有特定值时跳过验证
有时,您可能希望在另一个字段具有特定值时不验证给定字段。您可以使用 exclude_if
验证规则来实现这一点。在此示例中,如果 has_appointment
字段的值为 false
,则不会验证 appointment_date
和 doctor_name
字段:
$v = Validator::make($data, [
'has_appointment' => 'required|bool',
'appointment_date' => 'exclude_if:has_appointment,false|required|date',
'doctor_name' => 'exclude_if:has_appointment,false|required|string',
]);
或者,您可以使用 exclude_unless
规则来不验证给定字段,除非另一个字段具有给定值:
$v = Validator::make($data, [
'has_appointment' => 'required|bool',
'appointment_date' => 'exclude_unless:has_appointment,true|required|date',
'doctor_name' => 'exclude_unless:has_appointment,true|required|string',
]);
当存在时进行验证
在某些情况下,您可能希望仅在输入数组中存在该字段时对其进行验证。要快速实现这一点,请将 sometimes
规则添加到您的规则列表中:
$v = Validator::make($data, [
'email' => 'sometimes|required|email',
]);
在上面的示例中,只有在 $data
数组中存在 email
字段时才会对其进行验证。
如果您尝试验证一个应该始终存在但可能为空的字段,请查看关于可选字段的说明
复杂的条件验证
有时,您可能希望根据更复杂的条件逻辑添加验证规则。例如,您可能希望仅在另一个字段的值大于 100 时才要求给定字段。或者,您可能需要两个字段在另一个字段存在时具有给定值。添加这些验证规则不必是件麻烦事。首先,创建一个包含您永远不会改变的_静态规则_的 Validator
实例:
$v = Validator::make($data, [
'email' => 'required|email',
'games' => 'required|numeric',
]);
假设我们的 Web 应用程序是为游戏收藏家设计的。如果游戏收藏家注册我们的应用程序并且他们拥有超过 100 个游戏,我们希望他们解释为什么拥有这么多游戏。例如,也许他们经营一个游戏转售商店,或者他们只是喜欢收藏。要有条件地添加此要求,我们可以在 Validator
实例上使用 sometimes
方法。
$v->sometimes('reason', 'required|max:500', function ($input) {
return $input->games >= 100;
});
传递给 sometimes
方法的第一个参数是我们有条件验证的字段名称。第二个参数是我们想要添加的规则。如果作为第三个参数传递的 Closure
返回 true
,则将添加这些规则。此方法使构建复杂的条件验证变得轻而易举。您甚至可以一次为多个字段添加条件验证:
$v->sometimes(['reason', 'cost'], 'required', function ($input) {
return $input->games >= 100;
});
传递给您的 Closure
的 $input
参数将是 Illuminate\Support\Fluent
的一个实例,可以用于访问您的输入和文件。
验证数组
验证基于数组的表单输入字段不必是件麻烦事。您可以使用“点符号”来验证数组中的属性。例如,如果传入的 HTTP 请求包含一个 photos[profile]
字段,您可以这样验证它:
$validator = Validator::make($request->all(), [
'photos.profile' => 'required|image',
]);
您还可以验证数组的每个元素。例如,要验证给定数组输入字段中的每个电子邮件都是唯一的,您可以执行以下操作:
$validator = Validator::make($request->all(), [
'person.*.email' => 'email|unique:users',
'person.*.first_name' => 'required_with:person.*.last_name',
]);
同样,您可以在语言文件中指定验证消息时使用 *
字符,这使得为基于数组的字段使用单个验证消息变得轻而易举:
'custom' => [
'person.*.email' => [
'unique' => '每个人必须有一个唯一的电子邮件地址',
]
],
自定义验证规则
使用规则对象
Laravel 提供了多种有用的验证规则;然而,您可能希望指定一些自己的规则。注册自定义验证规则的一种方法是使用规则对象。要生成新的规则对象,您可以使用 make:rule
Artisan 命令。让我们使用此命令生成一个验证字符串为大写的规则。Laravel 会将新规则放在 app/Rules
目录中:
php artisan make:rule Uppercase
一旦创建了规则,我们就可以定义其行为。规则对象包含两个方法:passes
和 message
。passes
方法接收属性值和名称,并应根据属性值是否有效返回 true
或 false
。message
方法应返回验证失败时应使用的验证错误消息:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class Uppercase implements Rule
{
/**
* 确定验证规则是否通过。
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
return strtoupper($value) === $value;
}
/**
* 获取验证错误消息。
*
* @return string
*/
public function message()
{
return 'The :attribute 必须是大写的。';
}
}
如果您希望从翻译文件中返回错误消息,可以从 message
方法中调用 trans
助手:
/**
* 获取验证错误消息。
*
* @return string
*/
public function message()
{
return trans('validation.uppercase');
}
定义规则后,您可以通过将规则对象的实例与其他验证规则一起传递给验证器来附加它:
use App\Rules\Uppercase;
$request->validate([
'name' => ['required', 'string', new Uppercase],
]);
使用闭包
如果您只需要在应用程序中使用一次自定义规则的功能,则可以使用闭包而不是规则对象。闭包接收属性的名称、属性的值和一个 $fail
回调,如果验证失败,则应调用该回调:
$validator = Validator::make($request->all(), [
'title' => [
'required',
'max:255',
function ($attribute, $value, $fail) {
if ($value === 'foo') {
$fail($attribute.' 是无效的。');
}
},
],
]);
使用扩展
注册自定义验证规则的另一种方法是使用 Validator
facade 上的 extend
方法。让我们在 service provider 中使用此方法注册自定义验证规则:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;
class AppServiceProvider extends ServiceProvider
{
/**
* 注册任何应用程序服务。
*
* @return void
*/
public function register()
{
//
}
/**
* 启动任何应用程序服务。
*
* @return void
*/
public function boot()
{
Validator::extend('foo', function ($attribute, $value, $parameters, $validator) {
return $value == 'foo';
});
}
}
自定义验证器闭包接收四个参数:正在验证的 $attribute
的名称、属性的 $value
、传递给规则的 $parameters
数组和 Validator
实例。
您还可以将类和方法传递给 extend
方法,而不是闭包:
Validator::extend('foo', 'FooValidator@validate');
定义错误消息
您还需要为自定义规则定义错误消息。您可以使用内联自定义消息数组或通过在验证语言文件中添加条目来实现。这条消息应该放在数组的第一级,而不是在 custom
数组中,custom
数组仅用于特定属性的错误消息:
"foo" => "您的输入无效!",
"accepted" => "The :attribute 必须被接受。",
// 其余的验证错误消息...
在创建自定义验证规则时,您可能有时需要为错误消息定义自定义占位符替换。您可以通过创建自定义验证器并在 service provider 的 boot
方法中调用 Validator
facade 上的 replacer
方法来实现:
/**
* 启动任何应用程序服务。
*
* @return void
*/
public function boot()
{
Validator::extend(...);
Validator::replacer('foo', function ($message, $attribute, $rule, $parameters) {
return str_replace(...);
});
}
隐式扩展
默认情况下,当被验证的属性不存在或包含空字符串时,正常的验证规则(包括自定义扩展)不会运行。例如,unique
规则不会对空字符串运行:
$rules = ['name' => 'unique:users,name'];
$input = ['name' => ''];
Validator::make($input, $rules)->passes(); // true
要使规则即使在属性为空时也能运行,该规则必须暗示该属性是必需的。要创建这样的“隐式”扩展,请使用 Validator::extendImplicit()
方法:
Validator::extendImplicit('foo', function ($attribute, $value, $parameters, $validator) {
return $value == 'foo';
});
“隐式”扩展仅_暗示_该属性是必需的。是否实际使缺失或空的属性无效取决于您。
隐式规则对象
如果您希望规则对象在属性为空时运行,您应该实现 Illuminate\Contracts\Validation\ImplicitRule
接口。此接口作为验证器的“标记接口”,因此不包含您需要实现的任何方法。