跳转至内容

验证

简介

Laravel 提供了多种不同的方法来验证应用程序的传入数据。最常用的是使用所有传入 HTTP 请求中可用的 validate 方法。不过,我们也会讨论其他验证方法。

Laravel 包含了各种方便的验证规则,您可以将其应用于数据,甚至还提供了验证值在指定数据库表中是否唯一的能力。我们将详细介绍每一条验证规则,以便您熟悉 Laravel 的所有验证功能。

验证快速入门

为了了解 Laravel 强大的验证功能,让我们看一个验证表单并将错误消息显示回用户的完整示例。通过阅读此概览,您将能够很好地了解如何使用 Laravel 验证传入的请求数据。

定义路由

首先,假设我们在 routes/web.php 文件中定义了以下路由

1use App\Http\Controllers\PostController;
2 
3Route::get('/post/create', [PostController::class, 'create']);
4Route::post('/post', [PostController::class, 'store']);

GET 路由将显示一个供用户创建新博客文章的表单,而 POST 路由将把新的博客文章存储在数据库中。

创建控制器

接下来,让我们看一个处理这些路由传入请求的简单控制器。我们现在先将 store 方法留空

1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Http\RedirectResponse;
6use Illuminate\Http\Request;
7use Illuminate\View\View;
8 
9class PostController extends Controller
10{
11 /**
12 * Show the form to create a new blog post.
13 */
14 public function create(): View
15 {
16 return view('post.create');
17 }
18 
19 /**
20 * Store a new blog post.
21 */
22 public function store(Request $request): RedirectResponse
23 {
24 // Validate and store the blog post...
25 
26 $post = /** ... */
27 
28 return to_route('post.show', ['post' => $post->id]);
29 }
30}

编写验证逻辑

现在,我们准备好在 store 方法中填充验证新博客文章的逻辑了。为此,我们将使用 Illuminate\Http\Request 对象提供的 validate 方法。如果验证规则通过,您的代码将继续正常执行;但是,如果验证失败,将抛出 Illuminate\Validation\ValidationException 异常,并且适当的错误响应会自动发送回用户。

如果在传统的 HTTP 请求期间验证失败,将生成一个重定向到前一个 URL 的响应。如果传入请求是 XHR 请求,则会返回一个 包含验证错误消息的 JSON 响应

为了更好地理解 validate 方法,让我们回到 store 方法中

1/**
2 * Store a new blog post.
3 */
4public function store(Request $request): RedirectResponse
5{
6 $validated = $request->validate([
7 'title' => 'required|unique:posts|max:255',
8 'body' => 'required',
9 ]);
10 
11 // The blog post is valid...
12 
13 return redirect('/posts');
14}

如您所见,验证规则被传入了 validate 方法。不用担心 - 所有可用的验证规则都有 文档记录。同样,如果验证失败,将自动生成适当的响应。如果验证通过,我们的控制器将继续正常执行。

或者,验证规则可以指定为规则数组,而不是单个 | 分隔的字符串

1$validatedData = $request->validate([
2 'title' => ['required', 'unique:posts', 'max:255'],
3 'body' => ['required'],
4]);

此外,您可以使用 validateWithBag 方法来验证请求并将任何错误消息存储在 命名错误包

1$validatedData = $request->validateWithBag('post', [
2 'title' => ['required', 'unique:posts', 'max:255'],
3 'body' => ['required'],
4]);

在第一次验证失败时停止

有时您可能希望在第一次验证失败后停止对某个属性运行验证规则。为此,请将 bail 规则分配给该属性

1$request->validate([
2 'title' => 'bail|required|unique:posts|max:255',
3 'body' => 'required',
4]);

在此示例中,如果 title 属性上的 unique 规则失败,则不会检查 max 规则。规则将按照它们分配的顺序进行验证。

关于嵌套属性的说明

如果传入的 HTTP 请求包含“嵌套”字段数据,您可以使用“点”语法在验证规则中指定这些字段

1$request->validate([
2 'title' => 'required|unique:posts|max:255',
3 'author.name' => 'required',
4 'author.description' => 'required',
5]);

另一方面,如果您的字段名称包含文字句点,您可以通过用反斜杠转义句点来明确防止其被解释为“点”语法

1$request->validate([
2 'title' => 'required|unique:posts|max:255',
3 'v1\.0' => 'required',
4]);

显示验证错误

那么,如果传入的请求字段未通过给定的验证规则会怎样?如前所述,Laravel 会自动将用户重定向回其先前的位置。此外,所有的验证错误和 请求输入 都会自动 闪存到 session 中

$errors 变量由 web 中间件组提供的 Illuminate\View\Middleware\ShareErrorsFromSession 中间件与所有应用程序视图共享。当应用此中间件时,$errors 变量将在您的视图中始终可用,允许您方便地假设 $errors 变量已定义并可安全使用。$errors 变量将是 Illuminate\Support\MessageBag 的一个实例。有关使用此对象的更多信息,请 查看其文档

因此,在我们的示例中,当验证失败时,用户将被重定向到我们控制器的 create 方法,从而允许我们在视图中显示错误消息

1<!-- /resources/views/post/create.blade.php -->
2 
3<h1>Create Post</h1>
4 
5@if ($errors->any())
6 <div class="alert alert-danger">
7 <ul>
8 @foreach ($errors->all() as $error)
9 <li>{{ $error }}</li>
10 @endforeach
11 </ul>
12 </div>
13@endif
14 
15<!-- Create Post Form -->

自定义错误消息

Laravel 的内置验证规则每一条都有一个位于应用程序 lang/en/validation.php 文件中的错误消息。如果您的应用程序没有 lang 目录,您可以指示 Laravel 使用 lang:publish Artisan 命令来创建它。

lang/en/validation.php 文件中,您将找到每个验证规则的翻译条目。您可以根据应用程序的需要自由更改或修改这些消息。

此外,您可以将此文件复制到另一个语言目录,以翻译应用程序语言的消息。要了解有关 Laravel 本地化的更多信息,请查看完整的 本地化文档

默认情况下,Laravel 应用程序骨架不包含 lang 目录。如果您想自定义 Laravel 的语言文件,可以通过 lang:publish Artisan 命令发布它们。

XHR 请求和验证

在此示例中,我们使用传统表单将数据发送到应用程序。然而,许多应用程序会接收来自 JavaScript 前端的 XHR 请求。在 XHR 请求期间使用 validate 方法时,Laravel 不会生成重定向响应。相反,Laravel 会生成一个 包含所有验证错误的 JSON 响应。此 JSON 响应将以 422 HTTP 状态码发送。

@error 指令

您可以使用 @error Blade 指令快速确定给定属性是否存在验证错误消息。在 @error 指令中,您可以输出 $message 变量以显示错误消息

1<!-- /resources/views/post/create.blade.php -->
2 
3<label for="title">Post Title</label>
4 
5<input
6 id="title"
7 type="text"
8 name="title"
9 class="@error('title') is-invalid @enderror"
10/>
11 
12@error('title')
13 <div class="alert alert-danger">{{ $message }}</div>
14@enderror

如果您正在使用 命名错误包,则可以将错误包的名称作为第二个参数传递给 @error 指令

1<input ... class="@error('title', 'post') is-invalid @enderror">

回填表单

当 Laravel 因验证错误而生成重定向响应时,框架会自动 将所有请求的输入闪存到 session 中。这样做是为了让您可以在下一次请求中方便地获取输入并回填用户尝试提交的表单。

要从前一个请求中检索闪存的输入,请在 Illuminate\Http\Request 的实例上调用 old 方法。old 方法将从 session 中提取先前闪存的输入数据

1$title = $request->old('title');

Laravel 还提供了一个全局的 old 辅助函数。如果您要在 Blade 模板 中显示旧输入,使用 old 辅助函数来回填表单会更方便。如果给定字段没有旧输入,将返回 null

1<input type="text" name="title" value="{{ old('title') }}">

关于可选字段的说明

默认情况下,Laravel 在应用程序的全局中间件栈中包含 TrimStringsConvertEmptyStringsToNull 中间件。因此,如果您不希望验证器将 null 值视为无效,通常需要将“可选”请求字段标记为 nullable。例如

1$request->validate([
2 'title' => 'required|unique:posts|max:255',
3 'body' => 'required',
4 'publish_at' => 'nullable|date',
5]);

在此示例中,我们指定 publish_at 字段可以是 null,也可以是有效的日期表示形式。如果未将 nullable 修饰符添加到规则定义中,验证器将认为 null 是无效的日期。

验证错误响应格式

当您的应用程序抛出 Illuminate\Validation\ValidationException 异常且传入的 HTTP 请求期望 JSON 响应时,Laravel 将自动为您格式化错误消息并返回 422 Unprocessable Entity HTTP 响应。

下面,您可以查看验证错误的 JSON 响应格式示例。请注意,嵌套的错误键被扁平化为“点”符号格式

1{
2 "message": "The team name must be a string. (and 4 more errors)",
3 "errors": {
4 "team_name": [
5 "The team name must be a string.",
6 "The team name must be at least 1 characters."
7 ],
8 "authorization.role": [
9 "The selected authorization.role is invalid."
10 ],
11 "users.0.email": [
12 "The users.0.email field is required."
13 ],
14 "users.2.email": [
15 "The users.2.email must be a valid email address."
16 ]
17 }
18}

表单请求验证

创建表单请求

对于更复杂的验证场景,您可能希望创建一个“表单请求”。表单请求是自定义请求类,封装了它们自己的验证和授权逻辑。要创建表单请求类,您可以使用 make:request Artisan CLI 命令

1php artisan make:request StorePostRequest

生成的表单请求类将放置在 app/Http/Requests 目录中。如果该目录不存在,它将在您运行 make:request 命令时创建。Laravel 生成的每个表单请求都有两个方法:authorizerules

您可能已经猜到了,authorize 方法负责确定当前经过身份验证的用户是否可以执行请求所代表的操作,而 rules 方法返回应用于请求数据的验证规则

1/**
2 * Get the validation rules that apply to the request.
3 *
4 * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
5 */
6public function rules(): array
7{
8 return [
9 'title' => 'required|unique:posts|max:255',
10 'body' => 'required',
11 ];
12}

您可以在 rules 方法的签名中对您需要的任何依赖项进行类型提示。它们将通过 Laravel 服务容器 自动解析。

那么,验证规则是如何评估的呢?您所需要做的就是在控制器方法上对请求进行类型提示。传入的表单请求在调用控制器方法之前进行验证,这意味着您无需用任何验证逻辑使控制器变得杂乱

1/**
2 * Store a new blog post.
3 */
4public function store(StorePostRequest $request): RedirectResponse
5{
6 // The incoming request is valid...
7 
8 // Retrieve the validated input data...
9 $validated = $request->validated();
10 
11 // Retrieve a portion of the validated input data...
12 $validated = $request->safe()->only(['name', 'email']);
13 $validated = $request->safe()->except(['name', 'email']);
14 
15 // Store the blog post...
16 
17 return redirect('/posts');
18}

如果验证失败,将生成一个重定向响应,将用户发送回其先前的位置。错误也会闪存到 session 中,以便显示。如果请求是 XHR 请求,将向用户返回一个包含 422 状态码的 HTTP 响应,其中包含 验证错误的 JSON 表示形式

需要为您的 Inertia 驱动的 Laravel 前端添加实时表单请求验证吗?请查看 Laravel Precognition

执行附加验证

有时您需要在初始验证完成后执行附加验证。您可以使用表单请求的 after 方法来完成此操作。

after 方法应返回一个可调用对象或闭包数组,这些对象将在验证完成后被调用。给定的可调用对象将接收一个 Illuminate\Validation\Validator 实例,允许您在必要时引发附加的错误消息

1use Illuminate\Validation\Validator;
2 
3/**
4 * Get the "after" validation callables for the request.
5 */
6public function after(): array
7{
8 return [
9 function (Validator $validator) {
10 if ($this->somethingElseIsInvalid()) {
11 $validator->errors()->add(
12 'field',
13 'Something is wrong with this field!'
14 );
15 }
16 }
17 ];
18}

如前所述,after 方法返回的数组也可以包含可调用类。这些类的 __invoke 方法将接收一个 Illuminate\Validation\Validator 实例

1use App\Validation\ValidateShippingTime;
2use App\Validation\ValidateUserStatus;
3use Illuminate\Validation\Validator;
4 
5/**
6 * Get the "after" validation callables for the request.
7 */
8public function after(): array
9{
10 return [
11 new ValidateUserStatus,
12 new ValidateShippingTime,
13 function (Validator $validator) {
14 //
15 }
16 ];
17}

在第一次验证失败时停止

通过将 StopOnFirstFailure 属性添加到您的请求类,您可以通知验证器在发生单次验证失败后停止验证所有属性

1<?php
2 
3namespace App\Http\Requests;
4 
5use Illuminate\Foundation\Http\Attributes\StopOnFirstFailure;
6use Illuminate\Foundation\Http\FormRequest;
7 
8#[StopOnFirstFailure]
9class StorePostRequest extends FormRequest
10{
11 // ...
12}

自定义重定向位置

当表单请求验证失败时,将生成一个重定向响应,将用户送回其先前的位置。但是,您可以自由自定义此行为。为此,您可以在表单请求上使用 RedirectTo 属性

1<?php
2 
3namespace App\Http\Requests;
4 
5use Illuminate\Foundation\Http\Attributes\RedirectTo;
6use Illuminate\Foundation\Http\FormRequest;
7 
8#[RedirectTo('/dashboard')]
9class StorePostRequest extends FormRequest
10{
11 // ...
12}

或者,如果您想将用户重定向到命名路由,则可以使用 RedirectToRoute 属性

1<?php
2 
3namespace App\Http\Requests;
4 
5use Illuminate\Foundation\Http\Attributes\RedirectToRoute;
6use Illuminate\Foundation\Http\FormRequest;
7 
8#[RedirectToRoute('dashboard')]
9class StorePostRequest extends FormRequest
10{
11 // ...
12}

自定义错误包

当表单请求验证失败时,错误会闪存到 default 错误包中。如果您需要将错误存储在不同的 命名错误包 中,可以使用表单请求上的 ErrorBag 属性

1<?php
2 
3namespace App\Http\Requests;
4 
5use Illuminate\Foundation\Http\Attributes\ErrorBag;
6use Illuminate\Foundation\Http\FormRequest;
7 
8#[ErrorBag('login')]
9class LoginRequest extends FormRequest
10{
11 // ...
12}

授权表单请求

表单请求类还包含一个 authorize 方法。在此方法中,您可以确定经过身份验证的用户是否真的有权更新给定的资源。例如,您可以确定用户是否确实拥有他们试图更新的博客评论。您很可能会在此方法中与您的 授权门和策略 进行交互

1use App\Models\Comment;
2 
3/**
4 * Determine if the user is authorized to make this request.
5 */
6public function authorize(): bool
7{
8 $comment = Comment::find($this->route('comment'));
9 
10 return $comment && $this->user()->can('update', $comment);
11}

由于所有表单请求都扩展了基础 Laravel 请求类,我们可以使用 user 方法来访问当前经过身份验证的用户。另外,请注意上面示例中对 route 方法的调用。此方法授予您访问在路由上定义的 URI 参数的权限,例如下面示例中的 {comment} 参数

1Route::post('/comment/{comment}');

因此,如果您的应用程序正在利用 路由模型绑定,您可以通过将已解析的模型作为请求的属性来访问它,从而使代码更加简洁

1return $this->user()->can('update', $this->comment);

如果 authorize 方法返回 false,将自动返回 403 状态码的 HTTP 响应,并且您的控制器方法不会执行。

如果您计划在应用程序的其他部分处理请求的授权逻辑,您可以完全删除 authorize 方法,或者直接返回 true

1/**
2 * Determine if the user is authorized to make this request.
3 */
4public function authorize(): bool
5{
6 return true;
7}

您可以在 authorize 方法的签名中对您需要的任何依赖项进行类型提示。它们将通过 Laravel 服务容器 自动解析。

自定义错误消息

您可以通过覆盖 messages 方法来自定义表单请求使用的错误消息。此方法应返回一个属性/规则对及其对应的错误消息的数组

1/**
2 * Get the error messages for the defined validation rules.
3 *
4 * @return array<string, string>
5 */
6public function messages(): array
7{
8 return [
9 'title.required' => 'A title is required',
10 'body.required' => 'A message is required',
11 ];
12}

自定义验证属性

许多 Laravel 内置验证规则错误消息包含一个 :attribute 占位符。如果您希望验证消息的 :attribute 占位符被自定义属性名称替换,您可以通过覆盖 attributes 方法来指定自定义名称。此方法应返回一个属性/名称对的数组

1/**
2 * Get custom attributes for validator errors.
3 *
4 * @return array<string, string>
5 */
6public function attributes(): array
7{
8 return [
9 'email' => 'email address',
10 ];
11}

准备验证数据

如果您需要在应用验证规则之前准备或清理请求中的任何数据,可以使用 prepareForValidation 方法

1use Illuminate\Support\Str;
2 
3/**
4 * Prepare the data for validation.
5 */
6protected function prepareForValidation(): void
7{
8 $this->merge([
9 'slug' => Str::slug($this->slug),
10 ]);
11}

同样,如果您需要在验证完成后规范化任何请求数据,可以使用 passedValidation 方法

1/**
2 * Handle a passed validation attempt.
3 */
4protected function passedValidation(): void
5{
6 $this->replace(['name' => 'Taylor']);
7}

手动创建验证器

如果您不想在请求上使用 validate 方法,可以使用 Validator 门面 (facade) 手动创建一个验证器实例。门面上的 make 方法会生成一个新的验证器实例

1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Http\RedirectResponse;
6use Illuminate\Http\Request;
7use Illuminate\Support\Facades\Validator;
8 
9class PostController extends Controller
10{
11 /**
12 * Store a new blog post.
13 */
14 public function store(Request $request): RedirectResponse
15 {
16 $validator = Validator::make($request->all(), [
17 'title' => 'required|unique:posts|max:255',
18 'body' => 'required',
19 ]);
20 
21 if ($validator->fails()) {
22 return redirect('/post/create')
23 ->withErrors($validator)
24 ->withInput();
25 }
26 
27 // Retrieve the validated input...
28 $validated = $validator->validated();
29 
30 // Retrieve a portion of the validated input...
31 $validated = $validator->safe()->only(['name', 'email']);
32 $validated = $validator->safe()->except(['name', 'email']);
33 
34 // Store the blog post...
35 
36 return redirect('/posts');
37 }
38}

传递给 make 方法的第一个参数是正在验证的数据。第二个参数是应应用于数据的验证规则数组。

在确定请求验证是否失败后,您可以使用 withErrors 方法将错误消息闪存到 session 中。使用此方法时,$errors 变量在重定向后将自动与您的视图共享,使您可以轻松地将其显示回用户。withErrors 方法接受验证器、MessageBag 或 PHP 数组

在第一次验证失败时停止

stopOnFirstFailure 方法将通知验证器在发生单次验证失败后停止验证所有属性

1if ($validator->stopOnFirstFailure()->fails()) {
2 // ...
3}

自动重定向

如果您想手动创建验证器实例,但仍想利用 HTTP 请求的 validate 方法提供的自动重定向功能,则可以在现有的验证器实例上调用 validate 方法。如果验证失败,用户将被自动重定向,或者在 XHR 请求的情况下,将返回 JSON 响应

1Validator::make($request->all(), [
2 'title' => 'required|unique:posts|max:255',
3 'body' => 'required',
4])->validate();

如果验证失败,您可以使用 validateWithBag 方法将错误消息存储在 命名错误包

1Validator::make($request->all(), [
2 'title' => 'required|unique:posts|max:255',
3 'body' => 'required',
4])->validateWithBag('post');

命名错误包

如果您在一个页面上有多个表单,您可能希望命名包含验证错误的 MessageBag,以便您可以检索特定表单的错误消息。要实现这一点,请将名称作为第二个参数传递给 withErrors

1return redirect('/register')->withErrors($validator, 'login');

然后,您可以从 $errors 变量访问已命名的 MessageBag 实例

1{{ $errors->login->first('email') }}

自定义错误消息

如果需要,您可以提供验证器实例应使用的自定义错误消息,而不是 Laravel 提供的默认错误消息。有几种指定自定义消息的方法。首先,您可以将自定义消息作为第三个参数传递给 Validator::make 方法

1$validator = Validator::make($input, $rules, $messages = [
2 'required' => 'The :attribute field is required.',
3]);

在此示例中,:attribute 占位符将被正在验证的字段的实际名称替换。您还可以在验证消息中使用其他占位符。例如

1$messages = [
2 'same' => 'The :attribute and :other must match.',
3 'size' => 'The :attribute must be exactly :size.',
4 'between' => 'The :attribute value :input is not between :min - :max.',
5 'in' => 'The :attribute must be one of the following types: :values',
6];

为给定属性指定自定义消息

有时您可能希望仅为特定属性指定自定义错误消息。您可以使用“点”语法执行此操作。先指定属性名称,后跟规则

1$messages = [
2 'email.required' => 'We need to know your email address!',
3];

指定自定义属性值

许多 Laravel 内置错误消息包含一个 :attribute 占位符,该占位符被正在验证的字段或属性的名称替换。要自定义用于替换特定字段的这些占位符的值,您可以将自定义属性数组作为第四个参数传递给 Validator::make 方法

1$validator = Validator::make($input, $rules, $messages, [
2 'email' => 'email address',
3]);

执行附加验证

有时您需要在初始验证完成后执行附加验证。您可以使用验证器的 after 方法来完成此操作。after 方法接受闭包或可调用对象数组,这些对象将在验证完成后被调用。给定的可调用对象将接收一个 Illuminate\Validation\Validator 实例,允许您在必要时引发附加的错误消息

1use Illuminate\Support\Facades\Validator;
2 
3$validator = Validator::make(/* ... */);
4 
5$validator->after(function ($validator) {
6 if ($this->somethingElseIsInvalid()) {
7 $validator->errors()->add(
8 'field', 'Something is wrong with this field!'
9 );
10 }
11});
12 
13if ($validator->fails()) {
14 // ...
15}

如前所述,after 方法也接受可调用对象数组,如果您的“验证后”逻辑封装在可调用类中,这将特别方便,这些类将通过其 __invoke 方法接收一个 Illuminate\Validation\Validator 实例

1use App\Validation\ValidateShippingTime;
2use App\Validation\ValidateUserStatus;
3 
4$validator->after([
5 new ValidateUserStatus,
6 new ValidateShippingTime,
7 function ($validator) {
8 // ...
9 },
10]);

处理已验证的输入

在使用表单请求或手动创建的验证器实例验证传入的请求数据后,您可能希望检索实际通过验证的传入请求数据。这可以通过多种方式实现。首先,您可以在表单请求或验证器实例上调用 validated 方法。此方法返回已验证数据的数组

1$validated = $request->validated();
2 
3$validated = $validator->validated();

或者,您可以在表单请求或验证器实例上调用 safe 方法。此方法返回 Illuminate\Support\ValidatedInput 的一个实例。此对象公开了 onlyexceptall 方法,以检索已验证数据的子集或完整的已验证数据数组

1$validated = $request->safe()->only(['name', 'email']);
2 
3$validated = $request->safe()->except(['name', 'email']);
4 
5$validated = $request->safe()->all();

此外,可以像数组一样迭代和访问 Illuminate\Support\ValidatedInput 实例

1// Validated data may be iterated...
2foreach ($request->safe() as $key => $value) {
3 // ...
4}
5 
6// Validated data may be accessed as an array...
7$validated = $request->safe();
8 
9$email = $validated['email'];

如果您想向已验证的数据添加其他字段,可以调用 merge 方法

1$validated = $request->safe()->merge(['name' => 'Taylor Otwell']);

如果您想将已验证的数据检索为 集合 (collection) 实例,可以调用 collect 方法

1$collection = $request->safe()->collect();

处理错误消息

Validator 实例上调用 errors 方法后,您将收到一个 Illuminate\Support\MessageBag 实例,该实例具有多种用于处理错误消息的便捷方法。自动提供给所有视图的 $errors 变量也是 MessageBag 类的一个实例。

检索字段的第一条错误消息

要检索给定字段的第一条错误消息,请使用 first 方法

1$errors = $validator->errors();
2 
3echo $errors->first('email');

检索字段的所有错误消息

如果您需要检索给定字段的所有消息数组,请使用 get 方法

1foreach ($errors->get('email') as $message) {
2 // ...
3}

如果您正在验证数组表单字段,您可以使用 * 字符检索每个数组元素的所有消息

1foreach ($errors->get('attachments.*') as $message) {
2 // ...
3}

检索所有字段的所有错误消息

要检索所有字段的所有消息数组,请使用 all 方法

1foreach ($errors->all() as $message) {
2 // ...
3}

确定字段是否存在消息

has 方法可用于确定给定字段是否存在任何错误消息

1if ($errors->has('email')) {
2 // ...
3}

在语言文件中指定自定义消息

Laravel 的内置验证规则每一条都有一个位于应用程序 lang/en/validation.php 文件中的错误消息。如果您的应用程序没有 lang 目录,您可以指示 Laravel 使用 lang:publish Artisan 命令来创建它。

lang/en/validation.php 文件中,您将找到每个验证规则的翻译条目。您可以根据应用程序的需要自由更改或修改这些消息。

此外,您可以将此文件复制到另一个语言目录,以翻译应用程序语言的消息。要了解有关 Laravel 本地化的更多信息,请查看完整的 本地化文档

默认情况下,Laravel 应用程序骨架不包含 lang 目录。如果您想自定义 Laravel 的语言文件,可以通过 lang:publish Artisan 命令发布它们。

特定属性的自定义消息

您可以在应用程序的验证语言文件中自定义用于指定属性和规则组合的错误消息。为此,请将您的消息自定义添加到应用程序 lang/xx/validation.php 语言文件的 custom 数组中

1'custom' => [
2 'email' => [
3 'required' => 'We need to know your email address!',
4 'max' => 'Your email address is too long!'
5 ],
6],

在语言文件中指定属性

许多 Laravel 内置错误消息包含一个 :attribute 占位符,该占位符被正在验证的字段或属性的名称替换。如果您希望验证消息的 :attribute 部分被自定义值替换,您可以在 lang/xx/validation.php 语言文件的 attributes 数组中指定自定义属性名称

1'attributes' => [
2 'email' => 'email address',
3],

默认情况下,Laravel 应用程序骨架不包含 lang 目录。如果您想自定义 Laravel 的语言文件,可以通过 lang:publish Artisan 命令发布它们。

在语言文件中指定值

一些 Laravel 内置验证规则错误消息包含一个 :value 占位符,该占位符被请求属性的当前值替换。但是,有时您可能需要验证消息的 :value 部分被值的自定义表示形式替换。例如,考虑以下规则,该规则规定如果 payment_type 的值为 cc,则需要信用卡号

1Validator::make($request->all(), [
2 'credit_card_number' => 'required_if:payment_type,cc'
3]);

如果此验证规则失败,它将产生以下错误消息

1The credit card number field is required when payment type is cc.

您可以指定更友好的值表示形式,而不是在您的 lang/xx/validation.php 语言文件中将 cc 显示为支付类型值,方法是定义一个 values 数组

1'values' => [
2 'payment_type' => [
3 'cc' => 'credit card'
4 ],
5],

默认情况下,Laravel 应用程序骨架不包含 lang 目录。如果您想自定义 Laravel 的语言文件,可以通过 lang:publish Artisan 命令发布它们。

定义此值后,验证规则将产生以下错误消息

1The credit card number field is required when payment type is credit card.

可用验证规则

以下是所有可用验证规则及其功能的列表

布尔值

字符串

数字

数组

日期

文件

数据库

实用工具

accepted

验证的字段必须是 "yes""on"1"1"true"true"。这对于验证“服务条款”接受情况或类似字段很有用。

accepted_if:anotherfield,value,...

如果验证的另一个字段等于指定值,则验证的字段必须是 "yes""on"1"1"true"true"。这对于验证“服务条款”接受情况或类似字段很有用。

active_url

根据 PHP 的 dns_get_record 函数,验证的字段必须具有有效的 A 或 AAAA 记录。在传递给 dns_get_record 之前,提供的 URL 的主机名使用 PHP 的 parse_url 函数提取。

after:date

验证的字段必须是给定日期之后的值。日期将被传递给 PHP 的 strtotime 函数,以便转换为有效的 DateTime 实例

1'start_date' => 'required|date|after:tomorrow'

除了传递由 strtotime 评估的日期字符串外,您还可以指定另一个字段来与日期进行比较

1'finish_date' => 'required|date|after:start_date'

为方便起见,可以使用流式 date 规则构建器构建基于日期的规则

1use Illuminate\Validation\Rule;
2 
3'start_date' => [
4 'required',
5 Rule::date()->after(today()->addDays(7)),
6],

afterTodaytodayOrAfter 方法可用于流式表达日期,必须分别在今天之后或今天及之后

1'start_date' => [
2 'required',
3 Rule::date()->afterToday(),
4],

after_or_equal:date

验证的字段必须是给定日期之后或等于给定日期的值。有关更多信息,请参阅 after 规则。

为方便起见,可以使用流式 date 规则构建器构建基于日期的规则

1use Illuminate\Validation\Rule;
2 
3'start_date' => [
4 'required',
5 Rule::date()->afterOrEqual(today()->addDays(7)),
6],

anyOf

Rule::anyOf 验证规则允许您指定验证的字段必须满足给定验证规则集中的任意一个。例如,以下规则将验证 username 字段要么是电子邮件地址,要么是至少 6 个字符长的字母数字字符串(包括连字符)

1use Illuminate\Validation\Rule;
2 
3'username' => [
4 'required',
5 Rule::anyOf([
6 ['string', 'email'],
7 ['string', 'alpha_dash', 'min:6'],
8 ]),
9],

alpha

验证的字段必须完全是包含在 \p{L}\p{M} 中的 Unicode 字母字符。

要将此验证规则限制为 ASCII 范围内的字符 (a-zA-Z),您可以为验证规则提供 ascii 选项

1'username' => 'alpha:ascii',

alpha_dash

验证的字段必须完全是包含在 \p{L}\p{M}\p{N} 中的 Unicode 字母数字字符,以及 ASCII 连字符 (-) 和 ASCII 下划线 (_)。

要将此验证规则限制为 ASCII 范围内的字符 (a-zA-Z0-9),您可以为验证规则提供 ascii 选项

1'username' => 'alpha_dash:ascii',

alpha_num

验证的字段必须完全是包含在 \p{L}\p{M}\p{N} 中的 Unicode 字母数字字符。

要将此验证规则限制为 ASCII 范围内的字符 (a-zA-Z0-9),您可以为验证规则提供 ascii 选项

1'username' => 'alpha_num:ascii',

array

验证的字段必须是一个 PHP array

当为 array 规则提供其他值时,输入数组中的每个键都必须存在于提供给规则的值列表中。在以下示例中,输入数组中的 admin 键是无效的,因为它不包含在提供给 array 规则的值列表中

1use Illuminate\Support\Facades\Validator;
2 
3$input = [
4 'user' => [
5 'name' => 'Taylor Otwell',
6 'username' => 'taylorotwell',
7 'admin' => true,
8 ],
9];
10 
11Validator::make($input, [
12 'user' => 'array:name,username',
13]);

通常,您应该始终指定允许出现在数组中的数组键。

ascii

验证的字段必须完全是 7 位 ASCII 字符。

bail

在第一次验证失败后停止对该字段运行验证规则。

虽然 bail 规则仅在遇到验证失败时停止验证特定字段,但 stopOnFirstFailure 方法会通知验证器在发生单次验证失败后停止验证所有属性

1if ($validator->stopOnFirstFailure()->fails()) {
2 // ...
3}

before:date

验证的字段必须是给定日期之前的值。日期将被传递给 PHP 的 strtotime 函数,以便转换为有效的 DateTime 实例。此外,与 after 规则一样,可以提供另一个正在验证的字段的名称作为 date 的值。

为方便起见,也可以使用流式 date 规则构建器构建基于日期的规则

1use Illuminate\Validation\Rule;
2 
3'start_date' => [
4 'required',
5 Rule::date()->before(today()->subDays(7)),
6],

beforeTodaytodayOrBefore 方法可用于流式表达日期,必须分别在今天之前或今天及之前

1'start_date' => [
2 'required',
3 Rule::date()->beforeToday(),
4],

before_or_equal:date

验证的字段必须是给定日期之前或等于给定日期的值。日期将被传递给 PHP 的 strtotime 函数,以便转换为有效的 DateTime 实例。此外,与 after 规则一样,可以提供另一个正在验证的字段的名称作为 date 的值。

为方便起见,也可以使用流式 date 规则构建器构建基于日期的规则

1use Illuminate\Validation\Rule;
2 
3'start_date' => [
4 'required',
5 Rule::date()->beforeOrEqual(today()->subDays(7)),
6],

between:min,max

验证的字段的大小必须介于给定的 minmax(含)之间。字符串、数字、数组和文件的评估方式与 size 规则相同。

boolean

验证的字段必须能够转换为布尔值。接受的输入为 truefalse10"1""0"

您可以使用 strict 参数,仅当字段的值为 truefalse 时才将其视为有效

1'foo' => 'boolean:strict'

confirmed

验证的字段必须具有匹配的 {field}_confirmation 字段。例如,如果验证的字段是 password,则输入中必须存在匹配的 password_confirmation 字段。

您还可以传递自定义确认字段名称。例如,confirmed:repeat_username 将期望 repeat_username 字段与验证的字段匹配。

contains:foo,bar,...

验证的字段必须是一个包含所有给定参数值的数组。由于此规则通常需要您 implode 一个数组,因此可以使用 Rule::contains 方法来流式构建该规则

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rule;
3 
4Validator::make($data, [
5 'roles' => [
6 'required',
7 'array',
8 Rule::contains(['admin', 'editor']),
9 ],
10]);

doesnt_contain:foo,bar,...

验证的字段必须是一个不包含任何给定参数值的数组。由于此规则通常需要您 implode 一个数组,因此可以使用 Rule::doesntContain 方法来流式构建该规则

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rule;
3 
4Validator::make($data, [
5 'roles' => [
6 'required',
7 'array',
8 Rule::doesntContain(['admin', 'editor']),
9 ],
10]);

current_password

验证的字段必须与经过身份验证的用户密码匹配。您可以使用规则的第一个参数指定 身份验证守卫 (authentication guard)

1'password' => 'current_password:api'

date

根据 PHP 的 strtotime 函数,验证的字段必须是有效且非相对的日期。

date_equals:date

验证的字段必须等于给定的日期。日期将被传递给 PHP 的 strtotime 函数,以便转换为有效的 DateTime 实例。

date_format:format,...

验证的字段必须匹配给定的 formats 之一。您在验证字段时应该 要么 使用 date 要么 使用 date_format,不能同时使用两者。此验证规则支持 PHP DateTime 类支持的所有格式。

为方便起见,可以使用流式 date 规则构建器构建基于日期的规则

1use Illuminate\Validation\Rule;
2 
3'start_date' => [
4 'required',
5 Rule::date()->format('Y-m-d'),
6],

decimal:min,max

验证的字段必须是数字,并且必须包含指定的小数位数

1// Must have exactly two decimal places (9.99)...
2'price' => 'decimal:2'
3 
4// Must have between 2 and 4 decimal places...
5'price' => 'decimal:2,4'

declined

验证的字段必须是 "no""off"0"0"false"false"

declined_if:anotherfield,value,...

如果验证的另一个字段等于指定值,则验证的字段必须是 "no""off"0"0"false"false"

different:field

验证的字段必须具有与 field 不同的值。

digits:value

验证的整数必须具有 value 的确切长度。

digits_between:min,max

验证的整数必须具有介于给定的 minmax 之间的长度。

dimensions

验证的文件必须是符合规则参数所指定维度约束的图像

1'avatar' => 'dimensions:min_width=100,min_height=200'

可用的约束包括:min_widthmax_widthmin_heightmax_heightwidthheightratio

ratio 约束应表示为宽除以高。这可以指定为分数(如 3/2)或浮点数(如 1.5

1'avatar' => 'dimensions:ratio=3/2'

由于此规则需要多个参数,因此通常更方便使用 Rule::dimensions 方法来流式构建该规则

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rule;
3 
4Validator::make($data, [
5 'avatar' => [
6 'required',
7 Rule::dimensions()
8 ->maxWidth(1000)
9 ->maxHeight(500)
10 ->ratio(3 / 2),
11 ],
12]);

distinct

在验证数组时,验证的字段不能有任何重复值

1'foo.*.id' => 'distinct'

Distinct 默认使用松散变量比较。要使用严格比较,您可以在验证规则定义中添加 strict 参数

1'foo.*.id' => 'distinct:strict'

您可以将 ignore_case 添加到验证规则的参数中,以使规则忽略大小写差异

1'foo.*.id' => 'distinct:ignore_case'

doesnt_start_with:foo,bar,...

验证的字段不能以给定的值之一开头。

doesnt_end_with:foo,bar,...

验证的字段不能以给定的值之一结尾。

email

验证的字段必须格式化为电子邮件地址。此验证规则利用 egulias/email-validator 包来验证电子邮件地址。默认情况下,应用 RFCValidation 验证器,但您也可以应用其他验证样式

1'email' => 'email:rfc,dns'

上面的示例将应用 RFCValidationDNSCheckValidation 验证。以下是您可以应用的验证样式的完整列表

  • rfc: RFCValidation - 根据 支持的 RFC 验证电子邮件地址。
  • strict: NoRFCWarningsValidation - 根据 支持的 RFC 验证电子邮件,在发现警告(例如尾随点和连续多个点)时失败。
  • dns: DNSCheckValidation - 确保电子邮件地址的域具有有效的 MX 记录。
  • spoof: SpoofCheckValidation - 确保电子邮件地址不包含同形异义字或欺骗性 Unicode 字符。
  • filter: FilterEmailValidation - 根据 PHP 的 filter_var 函数确保电子邮件地址有效。
  • filter_unicode: FilterEmailValidation::unicode() - 根据 PHP 的 filter_var 函数确保电子邮件地址有效,允许一些 Unicode 字符。

为方便起见,可以使用流式规则构建器构建电子邮件验证规则

1use Illuminate\Validation\Rule;
2 
3$request->validate([
4 'email' => [
5 'required',
6 Rule::email()
7 ->rfcCompliant(strict: false)
8 ->validateMxRecord()
9 ->preventSpoofing()
10 ],
11]);

dnsspoof 验证器需要 PHP intl 扩展。

encoding:encoding_type

验证的字段必须匹配指定的字符编码。此规则使用 PHP 的 mb_check_encoding 函数来验证给定文件或字符串值的编码。为方便起见,可以使用 Laravel 的流式文件规则构建器构建 encoding 规则

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rules\File;
3 
4Validator::validate($input, [
5 'attachment' => [
6 'required',
7 File::types(['csv'])
8 ->encoding('utf-8'),
9 ],
10]);

ends_with:foo,bar,...

验证的字段必须以给定的值之一结尾。

enum

Enum 规则是一个基于类的规则,它验证验证的字段是否包含有效的枚举值。Enum 规则接受枚举名称作为其唯一的构造函数参数。在验证原始值时,应向 Enum 规则提供一个支持的枚举 (Backed Enum)

1use App\Enums\ServerStatus;
2use Illuminate\Validation\Rule;
3 
4$request->validate([
5 'status' => [Rule::enum(ServerStatus::class)],
6]);

Enum 规则的 onlyexcept 方法可用于限制应视为有效的枚举用例

1Rule::enum(ServerStatus::class)
2 ->only([ServerStatus::Pending, ServerStatus::Active]);
3 
4Rule::enum(ServerStatus::class)
5 ->except([ServerStatus::Pending, ServerStatus::Active]);

when 方法可用于有条件地修改 Enum 规则

1use Illuminate\Support\Facades\Auth;
2use Illuminate\Validation\Rule;
3 
4Rule::enum(ServerStatus::class)
5 ->when(
6 Auth::user()->isAdmin(),
7 fn ($rule) => $rule->only(...),
8 fn ($rule) => $rule->only(...),
9 );

exclude

验证的字段将从 validatevalidated 方法返回的请求数据中排除。

exclude_if:anotherfield,value

如果 anotherfield 字段等于 value,则验证的字段将从 validatevalidated 方法返回的请求数据中排除。

如果需要复杂的条件排除逻辑,可以利用 Rule::excludeIf 方法。此方法接受布尔值或闭包。当给出闭包时,闭包应返回 truefalse 以指示是否应排除正在验证的字段

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rule;
3 
4Validator::make($request->all(), [
5 'role_id' => Rule::excludeIf($request->user()->is_admin),
6]);
7 
8Validator::make($request->all(), [
9 'role_id' => Rule::excludeIf(fn () => $request->user()->is_admin),
10]);

exclude_unless:anotherfield,value

除非 anotherfield 字段等于 value,否则验证的字段将从 validatevalidated 方法返回的请求数据中排除。如果 valuenull (exclude_unless:name,null),则除非比较字段为 null 或请求数据中缺少比较字段,否则验证的字段将被排除。

exclude_with:anotherfield

如果 anotherfield 字段存在,则验证的字段将从 validatevalidated 方法返回的请求数据中排除。

exclude_without:anotherfield

如果 anotherfield 字段不存在,则验证的字段将从 validatevalidated 方法返回的请求数据中排除。

exists:table,column

验证的字段必须存在于给定的数据库表中。

Exists 规则的基本用法

1'state' => 'exists:states'

如果未指定 column 选项,将使用字段名称。因此,在这种情况下,规则将验证 states 数据库表是否包含一条记录,其 state 列的值与请求的 state 属性值匹配。

指定自定义列名

您可以通过将列名放在数据库表名之后,明确指定验证规则应使用的数据库列名

1'state' => 'exists:states,abbreviation'

有时,您可能需要指定用于 exists 查询的特定数据库连接。您可以通过在表名之前加上连接名来完成此操作

1'email' => 'exists:connection.staff,email'

除了直接指定表名外,您还可以指定应用于确定表名的 Eloquent 模型

1'user_id' => 'exists:App\Models\User,id'

如果您想自定义验证规则执行的查询,可以使用 Rule 类流式定义规则。在此示例中,我们还将验证规则指定为数组,而不是使用 | 字符来分隔它们

1use Illuminate\Database\Query\Builder;
2use Illuminate\Support\Facades\Validator;
3use Illuminate\Validation\Rule;
4 
5Validator::make($data, [
6 'email' => [
7 'required',
8 Rule::exists('staff')->where(function (Builder $query) {
9 $query->where('account_id', 1);
10 }),
11 ],
12]);

您可以通过提供列名作为 exists 方法的第二个参数,明确指定 Rule::exists 方法生成的 exists 规则应使用的数据库列名

1'state' => Rule::exists('states', 'abbreviation'),

有时,您可能希望验证值数组是否存在于数据库中。您可以通过将 existsarray 规则都添加到正在验证的字段来实现这一点

1'states' => ['array', Rule::exists('states', 'abbreviation')],

当这两个规则都被分配给字段时,Laravel 将自动构建一个查询,以确定所有给定值是否存在于指定表中。

extensions:foo,bar,...

验证的文件必须具有与列出的扩展名之一相对应的用户分配的扩展名

1'photo' => ['required', 'extensions:jpg,png'],

您绝对不应仅依赖通过用户分配的扩展名来验证文件。此规则通常应始终与 mimesmimetypes 规则结合使用。

file

验证的字段必须是成功上传的文件。

filled

如果字段存在,则验证的字段不能为空。

gt:field

验证的字段必须大于给定的 fieldvalue。这两个字段必须是相同类型。字符串、数字、数组和文件的评估方式与 size 规则的惯例相同。

gte:field

验证的字段必须大于或等于给定的 fieldvalue。这两个字段必须是相同类型。字符串、数字、数组和文件的评估方式与 size 规则的惯例相同。

hex_color

验证的字段必须包含 十六进制 格式的有效颜色值。

image

验证的文件必须是图像(jpg、jpeg、png、bmp、gif 或 webp)。

默认情况下,由于存在 XSS 漏洞的可能性,image 规则不允许 SVG 文件。如果您需要允许 SVG 文件,可以向 image 规则提供 allow_svg 指令 (image:allow_svg)。

in:foo,bar,...

验证的字段必须包含在给定的值列表中。由于此规则通常需要您 implode 一个数组,因此可以使用 Rule::in 方法来流式构建该规则

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rule;
3 
4Validator::make($data, [
5 'zones' => [
6 'required',
7 Rule::in(['first-zone', 'second-zone']),
8 ],
9]);

in 规则与 array 规则结合使用时,输入数组中的每个值都必须存在于提供给 in 规则的值列表中。在以下示例中,输入数组中的 LAS 机场代码是无效的,因为它不包含在提供给 in 规则的机场列表中

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rule;
3 
4$input = [
5 'airports' => ['NYC', 'LAS'],
6];
7 
8Validator::make($input, [
9 'airports' => [
10 'required',
11 'array',
12 ],
13 'airports.*' => Rule::in(['NYC', 'LIT']),
14]);

in_array:anotherfield.*

验证的字段必须存在于 anotherfield 的值中。

in_array_keys:value.*

验证的字段必须是一个数组,并且在数组中至少包含给定 values 之一作为键

1'config' => 'array|in_array_keys:timezone'

integer

验证的字段必须是一个整数。

您可以使用 strict 参数,仅当字段的类型为 integer 时才将其视为有效。带有整数值的字符串将被视为无效

1'age' => 'integer:strict'

此验证规则不验证输入是否为“整数”变量类型,仅验证输入是否为 PHP 的 FILTER_VALIDATE_INT 规则所接受的类型。如果您需要将输入验证为数字,请将此规则与 numeric 验证规则 结合使用。

ip

验证的字段必须是 IP 地址。

ipv4

验证的字段必须是 IPv4 地址。

ipv6

验证的字段必须是 IPv6 地址。

json

验证的字段必须是有效的 JSON 字符串。

lt:field

验证的字段必须小于给定的 field。这两个字段必须是相同类型。字符串、数字、数组和文件的评估方式与 size 规则的惯例相同。

lte:field

验证的字段必须小于或等于给定的 field。这两个字段必须是相同类型。字符串、数字、数组和文件的评估方式与 size 规则的惯例相同。

lowercase

验证的字段必须是小写。

list

验证的字段必须是一个列表数组。如果数组的键由从 0 到 count($array) - 1 的连续数字组成,则数组被视为列表。

mac_address

验证的字段必须是 MAC 地址。

max:value

验证的字段必须小于或等于最大 value。字符串、数字、数组和文件的评估方式与 size 规则相同。

max_digits:value

验证的整数必须具有 value 的最大长度。

mimetypes:text/plain,...

验证的文件必须匹配给定的 MIME 类型之一

1'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime',
2 
3'media' => 'mimetypes:image/*,video/*',

为了确定上传文件的 MIME 类型,将读取文件的内容,并且框架将尝试猜测 MIME 类型,这可能与客户端提供的 MIME 类型不同。

mimes:foo,bar,...

验证的文件必须具有与列出的扩展名之一相对应的 MIME 类型

1'photo' => 'mimes:jpg,bmp,png'

即使您只需要指定扩展名,此规则实际上是通过读取文件的内容并猜测其 MIME 类型来验证文件的 MIME 类型。MIME 类型及其对应扩展名的完整列表可以在以下位置找到

https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types

MIME 类型和扩展名

此验证规则不验证 MIME 类型与用户分配给文件的扩展名之间是否一致。例如,mimes:png 验证规则会将包含有效 PNG 内容的文件视为有效的 PNG 图像,即使该文件名为 photo.txt 也是如此。如果您想验证用户分配的文件扩展名,可以使用 extensions 规则。

min:value

验证的字段必须具有最小 value。字符串、数字、数组和文件的评估方式与 size 规则相同。

min_digits:value

验证的整数必须具有 value 的最小长度。

multiple_of:value

验证的字段必须是 value 的倍数。

missing

验证的字段不能出现在输入数据中。

missing_if:anotherfield,value,...

如果 anotherfield 字段等于任何 value,则验证的字段不能出现。

missing_unless:anotherfield,value

除非 anotherfield 字段等于任何 value,否则验证的字段不能出现。

missing_with:foo,bar,...

只有在 任何其他指定字段存在时,验证的字段才不能出现。

missing_with_all:foo,bar,...

只有在 所有其他指定字段存在时,验证的字段才不能出现。

not_in:foo,bar,...

验证的字段不能包含在给定的值列表中。可以使用 Rule::notIn 方法来流式构建该规则

1use Illuminate\Validation\Rule;
2 
3Validator::make($data, [
4 'toppings' => [
5 'required',
6 Rule::notIn(['sprinkles', 'cherries']),
7 ],
8]);

not_regex:pattern

验证的字段不能匹配给定的正则表达式。

在内部,此规则使用 PHP 的 preg_match 函数。指定的模式应遵守 preg_match 所需的相同格式,因此也包括有效的分隔符。例如: 'email' => 'not_regex:/^.+$/i'

当使用 regex / not_regex 模式时,可能需要使用数组而不是 | 分隔符来指定验证规则,特别是如果正则表达式包含 | 字符。

nullable

验证的字段可以是 null

numeric

验证的字段必须是 数字

您可以使用 strict 参数,仅当字段的值为整数或浮点类型时才将其视为有效。数字字符串将被视为无效

1'amount' => 'numeric:strict'

present

验证的字段必须存在于输入数据中。

present_if:anotherfield,value,...

如果 anotherfield 字段等于任何 value,则验证的字段必须出现。

present_unless:anotherfield,value

除非 anotherfield 字段等于任何 value,否则验证的字段必须出现。

present_with:foo,bar,...

只有在 任何其他指定字段存在时,验证的字段才必须出现。

present_with_all:foo,bar,...

只有在 所有其他指定字段存在时,验证的字段才必须出现。

prohibited

验证的字段必须缺失或为空。如果字段满足以下条件之一,则为“空”

  • 值为 null
  • 值是一个空字符串。
  • 值是一个空数组或空的 Countable 对象。
  • 值是一个路径为空的上传文件。

prohibited_if:anotherfield,value,...

如果 anotherfield 字段等于任何 value,则验证的字段必须缺失或为空。如果字段满足以下条件之一,则为“空”

  • 值为 null
  • 值是一个空字符串。
  • 值是一个空数组或空的 Countable 对象。
  • 值是一个路径为空的上传文件。

如果需要复杂的条件禁止逻辑,可以利用 Rule::prohibitedIf 方法。此方法接受布尔值或闭包。当给出闭包时,闭包应返回 truefalse 以指示是否应禁止正在验证的字段

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rule;
3 
4Validator::make($request->all(), [
5 'role_id' => Rule::prohibitedIf($request->user()->is_admin),
6]);
7 
8Validator::make($request->all(), [
9 'role_id' => Rule::prohibitedIf(fn () => $request->user()->is_admin),
10]);

prohibited_if_accepted:anotherfield,...

如果 anotherfield 字段等于 "yes""on"1"1"true"true",则验证的字段必须缺失或为空。

prohibited_if_declined:anotherfield,...

如果 anotherfield 字段等于 "no""off"0"0"false"false",则验证的字段必须缺失或为空。

prohibited_unless:anotherfield,value,...

除非 anotherfield 字段等于任何 value,否则验证的字段必须缺失或为空。如果字段满足以下条件之一,则为“空”

  • 值为 null
  • 值是一个空字符串。
  • 值是一个空数组或空的 Countable 对象。
  • 值是一个路径为空的上传文件。

prohibits:anotherfield,...

如果验证的字段不是缺失或为空的,则 anotherfield 中的所有字段都必须缺失或为空。如果字段满足以下条件之一,则为“空”

  • 值为 null
  • 值是一个空字符串。
  • 值是一个空数组或空的 Countable 对象。
  • 值是一个路径为空的上传文件。

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 方法。此方法接受布尔值或闭包。当传递闭包时,闭包应返回 truefalse 以指示是否需要验证的字段

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rule;
3 
4Validator::make($request->all(), [
5 'role_id' => Rule::requiredIf($request->user()->is_admin),
6]);
7 
8Validator::make($request->all(), [
9 'role_id' => Rule::requiredIf(fn () => $request->user()->is_admin),
10]);

required_if_accepted:anotherfield,...

如果 anotherfield 字段等于 "yes""on"1"1"true"true",则验证的字段必须存在且不能为空。

required_if_declined:anotherfield,...

如果 anotherfield 字段等于 "no""off"0"0"false"false",则验证的字段必须存在且不能为空。

required_unless:anotherfield,value,...

除非 anotherfield 字段等于任何 value,否则验证的字段必须存在且不能为空。这也意味着除非 valuenull,否则 anotherfield 必须存在于请求数据中。如果 valuenull (required_unless:name,null),则除非比较字段为 null 或请求数据中缺少比较字段,否则验证的字段将是必需的。

required_with:foo,bar,...

只有在 任何其他指定字段存在且不为空时,验证的字段才必须存在且不为空。

required_with_all:foo,bar,...

只有在 所有其他指定字段存在且不为空时,验证的字段才必须存在且不为空。

required_without:foo,bar,...

只有当 任何其他指定字段为空或不存在时,验证的字段才必须存在且不为空。

required_without_all:foo,bar,...

只有当 所有其他指定字段为空或不存在时,验证的字段才必须存在且不为空。

required_array_keys:foo,bar,...

验证的字段必须是数组,并且至少包含指定的键。

same:field

给定的 field 必须与验证的字段匹配。

size:value

验证的字段必须具有与给定 value 匹配的大小。对于字符串数据,value 对应于字符数。对于数字数据,value 对应于给定的整数值(属性也必须具有 numericinteger 规则)。对于数组,size 对应于数组的 count。对于文件,size 对应于以千字节为单位的文件大小。让我们看一些示例

1// Validate that a string is exactly 12 characters long...
2'title' => 'size:12';
3 
4// Validate that a provided integer equals 10...
5'seats' => 'integer|size:10';
6 
7// Validate that an array has exactly 5 elements...
8'tags' => 'array|size:5';
9 
10// Validate that an uploaded file is exactly 512 kilobytes...
11'image' => 'file|size:512';

starts_with:foo,bar,...

验证的字段必须以给定的值之一开头。

string

验证的字段必须是字符串。如果您希望允许该字段也为 null,则应将 nullable 规则分配给该字段。

为方便起见,字符串验证规则也可以使用流式 Rule::string() 规则构建器构建

1use Illuminate\Validation\Rule;
2 
3'title' => [
4 'required',
5 Rule::string()
6 ->min(3)
7 ->max(255)
8 ->alphaDash(ascii: true),
9],

字符串规则构建器提供了常见字符串约束的方法,包括 alphaalphaDashalphaNumericasciibetweendoesntEndWithdoesntStartWithendsWithexactlylowercasemaxminstartsWithuppercase。由于规则构建器是可条件的,您还可以使用 whenunless 方法来有条件地应用约束。

timezone

根据 DateTimeZone::listIdentifiers 方法,验证的字段必须是有效的时区标识符。

传递给此验证规则的参数可以是 DateTimeZone::listIdentifiers 方法接受的参数

1'timezone' => 'required|timezone:all';
2 
3'timezone' => 'required|timezone:Africa';
4 
5'timezone' => 'required|timezone:per_country,US';

unique:table,column

验证的字段不能存在于给定的数据库表中。

指定自定义表/列名

除了直接指定表名外,您还可以指定应用于确定表名的 Eloquent 模型

1'email' => 'unique:App\Models\User,email_address'

column 选项可用于指定字段对应的数据库列。如果未指定 column 选项,将使用验证的字段名称。

1'email' => 'unique:users,email_address'

指定自定义数据库连接

有时,您可能需要为验证器进行的数据库查询设置自定义连接。要完成此操作,您可以在表名之前加上连接名

1'email' => 'unique:connection.users,email_address'

强制唯一规则忽略给定 ID

有时,您可能希望在唯一验证期间忽略给定的 ID。例如,考虑一个包含用户姓名、电子邮件地址和位置的“更新个人资料”屏幕。您可能需要验证电子邮件地址是否唯一。但是,如果用户只更改姓名而不更改电子邮件字段,由于用户已经是相关电子邮件地址的所有者,您不希望抛出验证错误。

为了指示验证器忽略用户的 ID,我们将使用 Rule 类流式定义规则。在此示例中,我们还将验证规则指定为数组,而不是使用 | 字符来分隔规则

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rule;
3 
4Validator::make($data, [
5 'email' => [
6 'required',
7 Rule::unique('users')->ignore($user->id),
8 ],
9]);

您绝不应将任何用户控制的请求输入传递给 ignore 方法。相反,您应该只传递系统生成的唯一 ID,例如 Eloquent 模型实例中的自增 ID 或 UUID。否则,您的应用程序将容易受到 SQL 注入攻击。

除了将模型键的值传递给 ignore 方法外,您还可以传递整个模型实例。Laravel 将自动从模型中提取键

1Rule::unique('users')->ignore($user)

如果您的表使用的不是 id 的主键列名,则在调用 ignore 方法时可以指定列名

1Rule::unique('users')->ignore($user->id, 'user_id')

默认情况下,unique 规则会检查与被验证属性名称匹配的列的唯一性。但是,您可以传递一个不同的列名作为 unique 方法的第二个参数。

1Rule::unique('users', 'email_address')->ignore($user->id)

添加额外的 Where 子句

您可以通过使用 where 方法自定义查询来指定额外的查询条件。例如,让我们添加一个查询条件,将查询范围限制为仅搜索 account_id 列值为 1 的记录。

1'email' => Rule::unique('users')->where(fn (Builder $query) => $query->where('account_id', 1))

在唯一性检查中忽略软删除记录

默认情况下,unique 规则在确定唯一性时会包含软删除记录。若要从唯一性检查中排除软删除记录,可以调用 withoutTrashed 方法。

1Rule::unique('users')->withoutTrashed();

如果您的模型使用了除 deleted_at 之外的列名来记录软删除,您可以在调用 withoutTrashed 方法时提供该列名。

1Rule::unique('users')->withoutTrashed('was_deleted_at');

uppercase

验证的字段必须是大写的。

url

验证的字段必须是有效的 URL。

如果您想指定应被视为有效的 URL 协议,您可以将这些协议作为验证规则参数传递。

1'url' => 'url:http,https',
2 
3'game' => 'url:minecraft,steam',

ulid

验证的字段必须是有效的 通用唯一词典排序标识符 (ULID)。

uuid

验证的字段必须是符合 RFC 9562(版本 1、3、4、5、6、7 或 8)的有效通用唯一识别码 (UUID)。

您也可以按版本验证给定的 UUID 是否符合 UUID 规范。

1'uuid' => 'uuid:4'

条件添加规则

当字段具有特定值时跳过验证

有时您可能希望在另一个字段具有特定值时不验证某个字段。您可以使用 exclude_if 验证规则来实现这一点。在这个例子中,如果 has_appointment 字段的值为 false,则 appointment_datedoctor_name 字段将不会被验证。

1use Illuminate\Support\Facades\Validator;
2 
3$validator = Validator::make($data, [
4 'has_appointment' => 'required|boolean',
5 'appointment_date' => 'exclude_if:has_appointment,false|required|date',
6 'doctor_name' => 'exclude_if:has_appointment,false|required|string',
7]);

或者,您可以使用 exclude_unless 规则,除非另一个字段具有特定值,否则不验证某个字段。

1$validator = Validator::make($data, [
2 'has_appointment' => 'required|boolean',
3 'appointment_date' => 'exclude_unless:has_appointment,true|required|date',
4 'doctor_name' => 'exclude_unless:has_appointment,true|required|string',
5]);

存在时验证

在某些情况下,您可能希望在被验证的数据中存在某个字段时才对其运行验证检查。要快速实现这一点,请将 sometimes 规则添加到您的规则列表中。

1$validator = Validator::make($data, [
2 'email' => 'sometimes|required|email',
3]);

在上面的示例中,email 字段仅在 $data 数组中存在时才会被验证。

如果您尝试验证一个应该始终存在但可能为空的字段,请查看关于可选字段的注意事项

复杂的条件验证

有时您可能希望根据更复杂的逻辑添加验证规则。例如,您可能希望仅当另一个字段的值大于 100 时才要求某个字段必填。或者,您可能需要两个字段仅在另一个字段存在时才具有特定值。添加这些验证规则并不复杂。首先,使用您的静态规则(永远不会改变的规则)创建一个 Validator 实例。

1use Illuminate\Support\Facades\Validator;
2 
3$validator = Validator::make($request->all(), [
4 'email' => 'required|email',
5 'games' => 'required|integer|min:0',
6]);

假设我们的 Web 应用程序是为游戏收藏家准备的。如果一位游戏收藏家在我们应用注册且他们拥有的游戏超过 100 款,我们希望他们解释为何拥有这么多游戏。例如,也许他们经营着一家游戏转售店,或者只是单纯喜欢收集游戏。为了有条件地添加此要求,我们可以在 Validator 实例上使用 sometimes 方法。

1use Illuminate\Support\Fluent;
2 
3$validator->sometimes('reason', 'required|max:500', function (Fluent $input) {
4 return $input->games >= 100;
5});

传递给 sometimes 方法的第一个参数是我们正在进行条件验证的字段名称。第二个参数是我们想要添加的规则列表。如果作为第三个参数传递的闭包返回 true,则会添加这些规则。该方法使得构建复杂的条件验证变得轻而易举。您甚至可以一次为多个字段添加条件验证。

1$validator->sometimes(['reason', 'cost'], 'required', function (Fluent $input) {
2 return $input->games >= 100;
3});

传递给闭包的 $input 参数将是 Illuminate\Support\Fluent 的一个实例,可用于访问您正在验证的输入和文件。

复杂的条件数组验证

有时您可能希望根据同一个嵌套数组中您不知道索引的另一个字段来验证某个字段。在这种情况下,您可以允许您的闭包接收第二个参数,该参数将是被验证数组中的当前单个项目。

1$input = [
2 'channels' => [
3 [
4 'type' => 'email',
5 'address' => '[email protected]',
6 ],
7 [
8 'type' => 'url',
9 'address' => 'https://example.com',
10 ],
11 ],
12];
13 
14$validator->sometimes('channels.*.address', 'email', function (Fluent $input, Fluent $item) {
15 return $item->type === 'email';
16});
17 
18$validator->sometimes('channels.*.address', 'url', function (Fluent $input, Fluent $item) {
19 return $item->type !== 'email';
20});

与传递给闭包的 $input 参数一样,当属性数据是数组时,$item 参数是 Illuminate\Support\Fluent 的一个实例;否则,它是一个字符串。

验证数组

数组验证规则文档中所述,array 规则接受允许的数组键列表。如果数组中存在任何额外的键,验证将失败。

1use Illuminate\Support\Facades\Validator;
2 
3$input = [
4 'user' => [
5 'name' => 'Taylor Otwell',
6 'username' => 'taylorotwell',
7 'admin' => true,
8 ],
9];
10 
11Validator::make($input, [
12 'user' => 'array:name,username',
13]);

通常,您应该始终指定允许出现在数组中的数组键。否则,验证器的 validatevalidated 方法将返回所有经过验证的数据,包括数组及其所有键,即使这些键并未通过其他嵌套数组验证规则进行验证。

验证嵌套数组输入

验证基于嵌套数组的表单输入字段并不困难。您可以使用“点符号”来验证数组中的属性。例如,如果传入的 HTTP 请求包含 photos[profile] 字段,您可以这样验证它:

1use Illuminate\Support\Facades\Validator;
2 
3$validator = Validator::make($request->all(), [
4 'photos.profile' => 'required|image',
5]);

您也可以验证数组的每个元素。例如,要验证给定数组输入字段中的每个电子邮件是否唯一,您可以执行以下操作:

1$validator = Validator::make($request->all(), [
2 'users.*.email' => 'email|unique:users',
3 'users.*.first_name' => 'required_with:users.*.last_name',
4]);

同样,当在语言文件中指定自定义验证消息时,您可以使用 * 字符,从而轻松地为基于数组的字段使用单个验证消息。

1'custom' => [
2 'users.*.email' => [
3 'unique' => 'Each user must have a unique email address',
4 ]
5],

访问嵌套数组数据

有时,在为属性分配验证规则时,您可能需要访问给定嵌套数组元素的值。您可以使用 Rule::forEach 方法来实现这一点。forEach 方法接受一个闭包,该闭包将在被验证的数组属性的每次迭代时被调用,并接收属性的值和完整的展开属性名称。闭包应返回一个规则数组以分配给该数组元素。

1use App\Rules\HasPermission;
2use Illuminate\Support\Facades\Validator;
3use Illuminate\Validation\Rule;
4 
5$validator = Validator::make($request->all(), [
6 'companies.*.id' => Rule::forEach(function (string|null $value, string $attribute) {
7 return [
8 Rule::exists(Company::class, 'id'),
9 new HasPermission('manage-company', $value),
10 ];
11 }),
12]);

错误消息索引和位置

在验证数组时,您可能希望在应用程序显示的错误消息中引用验证失败的特定项的索引或位置。为此,您可以在自定义验证消息中包含 :index(从 0 开始)、:position(从 1 开始)或 :ordinal-position(从 1st 开始)占位符。

1use Illuminate\Support\Facades\Validator;
2 
3$input = [
4 'photos' => [
5 [
6 'name' => 'BeachVacation.jpg',
7 'description' => 'A photo of my beach vacation!',
8 ],
9 [
10 'name' => 'GrandCanyon.jpg',
11 'description' => '',
12 ],
13 ],
14];
15 
16Validator::validate($input, [
17 'photos.*.description' => 'required',
18], [
19 'photos.*.description.required' => 'Please describe photo #:position.',
20]);

根据上面的例子,验证将失败,用户将看到以下错误信息:“Please describe photo #2.”

如有必要,您可以通过 second-indexsecond-positionthird-indexthird-position 等引用更深层的嵌套索引和位置。

1'photos.*.attributes.*.string' => 'Invalid attribute for photo #:second-position.',

验证文件

Laravel 提供了多种可用于验证上传文件的验证规则,例如 mimesimageminmax。虽然您可以随意在验证文件时单独指定这些规则,但 Laravel 还提供了一个流畅的文件验证规则构建器,您可能会觉得它很方便。

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rules\File;
3 
4Validator::validate($input, [
5 'attachment' => [
6 'required',
7 File::types(['mp3', 'wav'])
8 ->min(1024)
9 ->max(12 * 1024),
10 ],
11]);

验证文件类型

即使在调用 types 方法时只需要指定扩展名,该方法实际上是通过读取文件内容并猜测其 MIME 类型来验证文件的 MIME 类型。有关 MIME 类型及其相应扩展名的完整列表,可以在以下位置找到。

https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types

验证文件大小

为方便起见,最小和最大文件大小可以指定为带有指示文件大小单位后缀的字符串。支持 kbmbgbtb 后缀。

1File::types(['mp3', 'wav'])
2 ->min('1kb')
3 ->max('10mb');

验证图像文件

如果您的应用程序接受用户上传的图像,您可以使用 File 规则的 image 构造方法来确保被验证的文件是图像(jpg、jpeg、png、bmp、gif 或 webp)。

此外,dimensions 规则可用于限制图像的尺寸。

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rule;
3use Illuminate\Validation\Rules\File;
4 
5Validator::validate($input, [
6 'photo' => [
7 'required',
8 File::image()
9 ->min(1024)
10 ->max(12 * 1024)
11 ->dimensions(Rule::dimensions()->maxWidth(1000)->maxHeight(500)),
12 ],
13]);

有关验证图像尺寸的更多信息,可以在尺寸规则文档中找到。

默认情况下,由于存在 XSS 漏洞的可能性,image 规则不允许使用 SVG 文件。如果您需要允许 SVG 文件,可以将 allowSvg: true 传递给 image 规则:File::image(allowSvg: true)

验证图像尺寸

您也可以验证图像的尺寸。例如,要验证上传的图像宽度至少为 1000 像素,高度至少为 500 像素,可以使用 dimensions 规则。

1use Illuminate\Validation\Rule;
2use Illuminate\Validation\Rules\File;
3 
4File::image()->dimensions(
5 Rule::dimensions()
6 ->maxWidth(1000)
7 ->maxHeight(500)
8)

有关验证图像尺寸的更多信息,可以在尺寸规则文档中找到。

验证密码

为了确保密码具有足够的复杂性,您可以使用 Laravel 的 Password 规则对象。

1use Illuminate\Support\Facades\Validator;
2use Illuminate\Validation\Rules\Password;
3 
4$validator = Validator::make($request->all(), [
5 'password' => ['required', 'confirmed', Password::min(8)],
6]);

Password 规则对象允许您轻松自定义应用程序的密码复杂性要求,例如指定密码必须至少包含一个字母、数字、符号或混合大小写字符。

1// Require at least 8 characters...
2Password::min(8)
3 
4// Require at least one letter...
5Password::min(8)->letters()
6 
7// Require at least one uppercase and one lowercase letter...
8Password::min(8)->mixedCase()
9 
10// Require at least one number...
11Password::min(8)->numbers()
12 
13// Require at least one symbol...
14Password::min(8)->symbols()

此外,您可以使用 uncompromised 方法确保密码未在公共密码数据泄露中被泄露。

1Password::min(8)->uncompromised()

在内部,Password 规则对象使用 k-匿名 (k-Anonymity) 模型,通过 haveibeenpwned.com 服务来确定密码是否被泄露,而不会牺牲用户的隐私或安全。

默认情况下,如果一个密码在数据泄露中出现至少一次,它将被视为已泄露。您可以使用 uncompromised 方法的第一个参数自定义此阈值。

1// Ensure the password appears less than 3 times in the same data leak...
2Password::min(8)->uncompromised(3);

当然,您可以链接上述示例中的所有方法。

1Password::min(8)
2 ->letters()
3 ->mixedCase()
4 ->numbers()
5 ->symbols()
6 ->uncompromised()

定义默认密码规则

您可能会发现在应用程序的一个位置指定密码的默认验证规则很方便。您可以使用接受闭包的 Password::defaults 方法轻松实现这一点。传递给 defaults 方法的闭包应返回 Password 规则的默认配置。通常,defaults 规则应在应用程序某个服务提供商的 boot 方法中调用。

1use Illuminate\Validation\Rules\Password;
2 
3/**
4 * Bootstrap any application services.
5 */
6public function boot(): void
7{
8 Password::defaults(function () {
9 $rule = Password::min(8);
10 
11 return $this->app->isProduction()
12 ? $rule->mixedCase()->uncompromised()
13 : $rule;
14 });
15}

然后,当您想对特定的密码应用默认规则时,可以调用不带参数的 defaults 方法。

1'password' => ['required', Password::defaults()],

有时,您可能希望将额外的验证规则附加到您的默认密码验证规则中。您可以使用 rules 方法来实现这一点。

1use App\Rules\ZxcvbnRule;
2 
3Password::defaults(function () {
4 $rule = Password::min(8)->rules([new ZxcvbnRule]);
5 
6 // ...
7});

自定义验证规则

使用规则对象

Laravel 提供了各种有用的验证规则;但是,您可能希望指定自己的一些规则。注册自定义验证规则的一种方法是使用规则对象。要生成一个新的规则对象,您可以使用 make:rule Artisan 命令。让我们使用这个命令来生成一个验证字符串是否为大写的规则。Laravel 会将新规则放置在 app/Rules 目录中。如果该目录不存在,Laravel 会在您执行 Artisan 命令创建规则时自动创建它。

1php artisan make:rule Uppercase

规则创建完成后,我们就可以定义它的行为。规则对象包含一个单一的方法:validate。此方法接收属性名称、其值以及一个回调函数,该回调函数应在验证失败时调用以显示错误消息。

1<?php
2 
3namespace App\Rules;
4 
5use Closure;
6use Illuminate\Contracts\Validation\ValidationRule;
7 
8class Uppercase implements ValidationRule
9{
10 /**
11 * Run the validation rule.
12 */
13 public function validate(string $attribute, mixed $value, Closure $fail): void
14 {
15 if (strtoupper($value) !== $value) {
16 $fail('The :attribute must be uppercase.');
17 }
18 }
19}

规则定义完成后,您可以通过将规则对象的实例与其他验证规则一起传递,将其附加到验证器。

1use App\Rules\Uppercase;
2 
3$request->validate([
4 'name' => ['required', 'string', new Uppercase],
5]);

翻译验证消息

除了向 $fail 闭包提供字面错误消息外,您还可以提供一个翻译字符串键,并指示 Laravel 翻译该错误消息。

1if (strtoupper($value) !== $value) {
2 $fail('validation.uppercase')->translate();
3}

如有必要,您可以将占位符替换和首选语言作为 translate 方法的第一个和第二个参数提供。

1$fail('validation.location')->translate([
2 'value' => $this->value,
3], 'fr');

访问附加数据

如果您的自定义验证规则类需要访问正在进行验证的所有其他数据,您的规则类可以实现 Illuminate\Contracts\Validation\DataAwareRule 接口。该接口要求您的类定义一个 setData 方法。Laravel 会在验证开始前自动调用此方法,并传入所有正在验证的数据。

1<?php
2 
3namespace App\Rules;
4 
5use Illuminate\Contracts\Validation\DataAwareRule;
6use Illuminate\Contracts\Validation\ValidationRule;
7 
8class Uppercase implements DataAwareRule, ValidationRule
9{
10 /**
11 * All of the data under validation.
12 *
13 * @var array<string, mixed>
14 */
15 protected $data = [];
16 
17 // ...
18 
19 /**
20 * Set the data under validation.
21 *
22 * @param array<string, mixed> $data
23 */
24 public function setData(array $data): static
25 {
26 $this->data = $data;
27 
28 return $this;
29 }
30}

或者,如果您的验证规则需要访问执行验证的验证器实例,您可以实现 ValidatorAwareRule 接口。

1<?php
2 
3namespace App\Rules;
4 
5use Illuminate\Contracts\Validation\ValidationRule;
6use Illuminate\Contracts\Validation\ValidatorAwareRule;
7use Illuminate\Validation\Validator;
8 
9class Uppercase implements ValidationRule, ValidatorAwareRule
10{
11 /**
12 * The validator instance.
13 *
14 * @var \Illuminate\Validation\Validator
15 */
16 protected $validator;
17 
18 // ...
19 
20 /**
21 * Set the current validator.
22 */
23 public function setValidator(Validator $validator): static
24 {
25 $this->validator = $validator;
26 
27 return $this;
28 }
29}

使用闭包

如果您只需要在整个应用程序中使用一次自定义规则的功能,可以使用闭包代替规则对象。闭包接收属性名称、属性值以及一个在验证失败时调用的 $fail 回调。

1use Illuminate\Support\Facades\Validator;
2use Closure;
3 
4$validator = Validator::make($request->all(), [
5 'title' => [
6 'required',
7 'max:255',
8 function (string $attribute, mixed $value, Closure $fail) {
9 if ($value === 'foo') {
10 $fail("The {$attribute} is invalid.");
11 }
12 },
13 ],
14]);

隐式规则

默认情况下,当被验证的属性不存在或包含空字符串时,常规验证规则(包括自定义规则)不会运行。例如,unique 规则不会针对空字符串运行。

1use Illuminate\Support\Facades\Validator;
2 
3$rules = ['name' => 'unique:users,name'];
4 
5$input = ['name' => ''];
6 
7Validator::make($input, $rules)->passes(); // true

为了使自定义规则即使在属性为空时也能运行,该规则必须暗示该属性是必填的。要快速生成一个新的隐式规则对象,您可以在使用 make:rule Artisan 命令时加上 --implicit 选项。

1php artisan make:rule Uppercase --implicit

“隐式”规则仅暗示属性是必填的。它是否真正使缺失或空的属性失效取决于您自己。