Skip to content
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

验证

简介

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

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

验证快速入门

要了解 Laravel 强大的验证功能,让我们来看一个验证表单并将错误消息显示给用户的完整示例。通过阅读这个高级概述,你将能够很好地了解如何使用 Laravel 验证传入的请求数据。

定义路由

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

php
use App\Http\Controllers\PostController;

Route::get('/post/create', [PostController::class, 'create']);
Route::post('/post', [PostController::class, 'store']);

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

创建控制器

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

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class PostController extends Controller
{
    /**
     * 显示创建新博客文章的表单。
     */
    public function create(): View
    {
        return view('post.create');
    }

    /**
     * 存储一篇新博客文章。
     */
    public function store(Request $request): RedirectResponse
    {
        // 验证并存储博客文章...

        $post = /** ... */

        return to_route('post.show', ['post' => $post->id]);
    }
}

编写验证逻辑

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

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

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

php
/**
 * 存储一篇新博客文章。
 */
public function store(Request $request): RedirectResponse
{
    $validated = $request->validate([
        'title' => ['required', 'unique:posts', 'max:255'],
        'body' => ['required'],
    ]);

    // 博客文章有效...

    return redirect('/posts');
}

如你所见,验证规则被传递到 validate 方法中。别担心——所有可用的验证规则都已 文档化。同样,如果验证失败,将自动生成正确的响应。如果验证通过,我们的控制器将继续正常执行。

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

php
$validated = $request->validateWithBag('post', [
    'title' => ['required', 'unique:posts', 'max:255'],
    'body' => ['required'],
]);

在第一次验证失败后停止

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

php
$request->validate([
    'title' => ['bail', 'required', 'unique:posts', 'max:255'],
    'body' => ['required'],
]);

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

关于嵌套字段的说明

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

php
$request->validate([
    'title' => ['required', 'unique:posts', 'max:255'],
    'author.name' => ['required'],
    'author.description' => ['required'],
]);

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

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

显示验证错误

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

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

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

blade
<!-- /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

<!-- 创建文章表单 -->

自定义错误消息

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

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 变量以显示错误消息:

blade
<!-- /resources/views/post/create.blade.php -->

<label for="title">文章标题</label>

<input
    id="title"
    type="text"
    name="title"
    class="@error('title') is-invalid @enderror"
/>

@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror

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

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

重新填充表单

当 Laravel 因验证错误生成重定向响应时,框架将自动 将所有请求的输入闪存到会话。这样做是为了让你可以在下一个请求期间方便地访问输入,并重新填充用户尝试提交的表单。

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

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

Laravel 还提供了一个全局的 old 辅助函数。如果你在 Blade 模板 中显示旧输入,使用 old 辅助函数重新填充表单更方便。如果给定字段不存在旧输入,将返回 null

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

关于可选字段的说明

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

php
$request->validate([
    'title' => ['required', 'unique:posts', 'max:255'],
    'body' => ['required'],
    'publish_at' => ['nullable', 'date'],
]);

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

验证错误响应格式

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

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

json
{
    "message": "The team name must be a string. (and 4 more errors)",
    "errors": {
        "team_name": [
            "The team name must be a string.",
            "The team name must be at least 1 characters."
        ],
        "authorization.role": [
            "The selected authorization.role is invalid."
        ],
        "users.0.email": [
            "The users.0.email field is required."
        ],
        "users.2.email": [
            "The users.2.email must be a valid email address."
        ]
    }
}

表单请求验证

创建表单请求

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

shell
php artisan make:request StorePostRequest

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

正如你可能猜到的,authorize 方法负责确定当前经过身份验证的用户是否可以执行由请求表示的操作,而 rules 方法返回应应用于请求数据的验证规则:

php
/**
 * 获取应用于请求的验证规则。
 *
 * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
 */
public function rules(): array
{
    return [
        'title' => ['required', 'unique:posts', 'max:255'],
        'body' => ['required'],
    ];
}

NOTE

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

那么,验证规则是如何评估的呢?你只需在控制器方法中类型提示该请求即可。传入的表单请求在调用控制器方法之前被验证,这意味着你无需用任何验证逻辑混乱你的控制器:

php
/**
 * 存储一篇新博客文章。
 */
public function store(StorePostRequest $request): RedirectResponse
{
    // 传入的请求有效...

    // 检索已验证的输入数据...
    $validated = $request->validated();

    // 检索已验证输入数据的一部分...
    $validated = $request->safe()->only(['name', 'email']);
    $validated = $request->safe()->except(['name', 'email']);

    // 存储博客文章...

    return redirect('/posts');
}

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

NOTE

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

执行额外验证

有时你需要在初始验证完成后执行额外的验证。你可以使用表单请求的 after 方法来实现这一点。

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

php
use Illuminate\Validation\Validator;

/**
 * 获取请求的“after”验证可调用对象。
 */
public function after(): array
{
    return [
        function (Validator $validator) {
            if ($this->somethingElseIsInvalid()) {
                $validator->errors()->add(
                    'field',
                    '此字段有问题!'
                );
            }
        }
    ];
}

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

php
use App\Validation\ValidateShippingTime;
use App\Validation\ValidateUserStatus;
use Illuminate\Validation\Validator;

/**
 * 获取请求的“after”验证可调用对象。
 */
public function after(): array
{
    return [
        new ValidateUserStatus,
        new ValidateShippingTime,
        function (Validator $validator) {
            //
        }
    ];
}

在第一次验证规则失败后停止

通过向请求类添加 StopOnFirstFailure 属性,你可以通知验证器,一旦发生一次验证失败,就应停止验证所有字段:

php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\Attributes\StopOnFirstFailure;
use Illuminate\Foundation\Http\FormRequest;

#[StopOnFirstFailure]
class StorePostRequest extends FormRequest
{
    // ...
}

拒绝未知字段

通过在请求类中添加 FailOnUnknownFields 属性,你可以指示 Laravel 拒绝任何未在请求验证规则中定义的传入字段:

php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\Attributes\FailOnUnknownFields;
use Illuminate\Foundation\Http\FormRequest;

#[FailOnUnknownFields]
class StorePostRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'title' => ['required', 'string'],
            'body'  => ['required', 'string'],
        ];
    }
}

你也可以在 AppServiceProvider 中为所有表单请求全局启用此行为:

php
use Illuminate\Foundation\Http\FormRequest;

/**
 * 引导任何应用服务。
 */
public function boot(): void
{
    FormRequest::failOnUnknownFields();
}

如果需要,你可以通过向属性传递 false 来为特定请求禁用此行为:

php
#[FailOnUnknownFields(false)]
class PublicWebhookRequest extends FormRequest
{
    // ...
}

拒绝未知字段可以提供额外的保护,防止批量赋值风格的问题,避免意外的输入键深入应用到你的应用程序中。不过,你仍然应该配置模型的 $fillable / $guarded 属性,并且只持久化受信任、已验证的输入。

自定义重定向位置

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

php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\Attributes\RedirectTo;
use Illuminate\Foundation\Http\FormRequest;

#[RedirectTo('/dashboard')]
class StorePostRequest extends FormRequest
{
    // ...
}

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

php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\Attributes\RedirectToRoute;
use Illuminate\Foundation\Http\FormRequest;

#[RedirectToRoute('dashboard')]
class StorePostRequest extends FormRequest
{
    // ...
}

自定义错误包

当表单请求验证失败时,错误会被闪存到 default 错误包。如果你需要将错误存储在另一个 命名错误包 中,可以在表单请求上使用 ErrorBag 属性:

php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\Attributes\ErrorBag;
use Illuminate\Foundation\Http\FormRequest;

#[ErrorBag('login')]
class LoginRequest extends FormRequest
{
    // ...
}

授权表单请求

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

php
use App\Models\Comment;

/**
 * 确定用户是否有权发出此请求。
 */
public function authorize(): bool
{
    $comment = Comment::find($this->route('comment'));

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

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

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

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

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

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

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

php
/**
 * 确定用户是否有权发出此请求。
 */
public function authorize(): bool
{
    return true;
}

NOTE

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

自定义错误消息

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

php
/**
 * 获取已定义验证规则的错误消息。
 *
 * @return array<string, string>
 */
public function messages(): array
{
    return [
        'title.required' => '标题是必需的',
        'body.required' => '消息是必需的',
    ];
}

自定义验证属性

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

php
/**
 * 为验证器错误获取自定义属性。
 *
 * @return array<string, string>
 */
public function attributes(): array
{
    return [
        'email' => '电子邮件地址',
    ];
}

准备验证输入

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

php
use Illuminate\Support\Str;

/**
 * 准备验证数据。
 */
protected function prepareForValidation(): void
{
    $this->merge([
        'slug' => Str::slug($this->slug),
    ]);
}

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

php
/**
 * 处理通过验证的尝试。
 */
protected function passedValidation(): void
{
    $this->replace(['name' => 'Taylor']);
}

手动创建验证器

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

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class PostController extends Controller
{
    /**
     * 存储一篇新博客文章。
     */
    public function store(Request $request): RedirectResponse
    {
        $validator = Validator::make($request->all(), [
            'title' => ['required', 'unique:posts', 'max:255'],
            'body' => ['required'],
        ]);

        if ($validator->fails()) {
            return redirect('/post/create')
                ->withErrors($validator)
                ->withInput();
        }

        // 检索已验证的输入...
        $validated = $validator->validated();

        // 检索已验证输入的一部分...
        $validated = $validator->safe()->only(['name', 'email']);
        $validated = $validator->safe()->except(['name', 'email']);

        // 存储博客文章...

        return redirect('/posts');
    }
}

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

在确定请求验证失败后,你可以使用 withErrors 方法将错误消息闪存到会话中。使用此方法时,$errors 变量将在重定向后自动与你的视图共享,使你能够轻松地将它们显示回给用户。withErrors 方法接受一个验证器、一个 MessageBag 或一个 PHP array

在第一次验证失败后停止

stopOnFirstFailure 方法将通知验证器,一旦发生一次验证失败,就应停止验证所有属性:

php
if ($validator->stopOnFirstFailure()->fails()) {
    // ...
}

自动重定向

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

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

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

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

命名错误包

如果你在单个页面上有多个表单,你可能希望为包含验证错误的 MessageBag 命名,从而允许你检索特定表单的错误消息。为此,将名称作为第二个参数传递给 withErrors

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

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

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

自定义错误消息

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

php
$validator = Validator::make($input, $rules, $messages = [
    'required' => ':attribute 字段是必需的。',
]);

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

php
$messages = [
    'same'    => ':attribute 和 :other 必须匹配。',
    'size'    => ':attribute 必须是 :size。',
    'between' => ':attribute 值 :input 不在 :min 和 :max 之间。',
    'in'      => ':attribute 必须是以下类型之一::values',
];

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

有时你可能只想为特定属性指定自定义错误消息。你可以使用“点”符号来执行此操作。首先指定属性名称,后跟规则:

php
$messages = [
    'email.required' => '我们需要知道您的电子邮件地址!',
];

指定自定义属性值

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

php
$validator = Validator::make($input, $rules, $messages, [
    'email' => '电子邮件地址',
]);

执行额外验证

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

php
use Illuminate\Support\Facades\Validator;

$validator = Validator::make(/* ... */);

$validator->after(function ($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add(
            'field', '此字段有问题!'
        );
    }
});

if ($validator->fails()) {
    // ...
}

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

php
use App\Validation\ValidateShippingTime;
use App\Validation\ValidateUserStatus;

$validator->after([
    new ValidateUserStatus,
    new ValidateShippingTime,
    function ($validator) {
        // ...
    },
]);

处理已验证的输入

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

php
$validated = $request->validated();

$validated = $validator->validated();

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

php
$validated = $request->safe()->only(['name', 'email']);

$validated = $request->safe()->except(['name', 'email']);

$validated = $request->safe()->all();

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

php
// 已验证数据可以被迭代...
foreach ($request->safe() as $key => $value) {
    // ...
}

// 已验证数据可以作为数组访问...
$validated = $request->safe();

$email = $validated['email'];

如果你想向已验证数据添加额外字段,可以调用 merge 方法:

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

如果你想将已验证数据作为 集合 实例检索,可以调用 collect 方法:

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

处理错误消息

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

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

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

php
$errors = $validator->errors();

echo $errors->first('email');

检索字段的所有错误消息

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

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

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

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

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

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

php
foreach ($errors->all() as $message) {
    // ...
}

确定字段是否存在消息

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

php
if ($errors->has('email')) {
    // ...
}

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

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

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

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

警告

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

特定属性的自定义消息

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

php
'custom' => [
    'email' => [
        'required' => '我们需要知道您的电子邮件地址!',
        'max'      => '您的电子邮件地址太长!'
    ],
],

在语言文件中指定属性

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

php
'attributes' => [
    'email' => '电子邮件地址',
],

警告

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

在语言文件中指定值

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

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

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

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

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

php
'values' => [
    'payment_type' => [
        'cc' => '信用卡'
    ],
],

警告

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

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

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

可用验证规则

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

布尔值

字符串

数字

数组

日期

文件

数据库

工具

accepted

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

accepted_if:另一个字段,值,...

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

active_url

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

after:日期

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

php
'start_date' => ['required', 'date', 'after:tomorrow']

除了传递将由 strtotime 评估的日期字符串外,你可以指定另一个要与日期比较的字段:

php
'finish_date' => ['required', 'date', 'after:start_date']

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

php
use Illuminate\Validation\Rule;

'start_date' => [
    'required',
    Rule::date()->after(today()->addDays(7)),
],

afterTodaytodayOrAfter 方法可用于流畅地表达日期,并且分别必须是在今天之后,或今天及以后:

php
'start_date' => [
    'required',
    Rule::date()->afterToday(),
],

after_or_equal:日期

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

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

php
use Illuminate\Validation\Rule;

'start_date' => [
    'required',
    Rule::date()->afterOrEqual(today()->addDays(7)),
],

anyOf

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

php
use Illuminate\Validation\Rule;

'username' => [
    'required',
    Rule::anyOf([
        ['string', 'email'],
        ['string', 'alpha_dash', 'min:6'],
    ]),
],

alpha

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

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

php
'username' => ['alpha:ascii'],

alpha_dash

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

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

php
'username' => ['alpha_dash:ascii'],

alpha_num

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

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

php
'username' => ['alpha_num:ascii'],

array

验证中的字段必须是 PHP array

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

php
use Illuminate\Support\Facades\Validator;

$input = [
    'user' => [
        'name' => 'Taylor Otwell',
        'username' => 'taylorotwell',
        'admin' => true,
    ],
];

Validator::make($input, [
    'user' => ['array:name,username'],
]);

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

ascii

验证中的字段必须完全由 7 位 ASCII 字符组成。

bail

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

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

php
if ($validator->stopOnFirstFailure()->fails()) {
    // ...
}

before:日期

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

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

php
use Illuminate\Validation\Rule;

'start_date' => [
    'required',
    Rule::date()->before(today()->subDays(7)),
],

beforeTodaytodayOrBefore 方法可用于流畅地表达日期,并且分别必须是在今天之前,或今天及以前:

php
'start_date' => [
    'required',
    Rule::date()->beforeToday(),
],

before_or_equal:日期

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

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

php
use Illuminate\Validation\Rule;

'start_date' => [
    'required',
    Rule::date()->beforeOrEqual(today()->subDays(7)),
],

between:最小值,最大值

验证中的字段的大小必须在给定的 最小值最大值(包括)之间。字符串、数字、数组和文件的评估方式与 size 规则相同。

boolean

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

你可以使用 strict 参数,仅当其值为 truefalse 时才认为字段有效:

php
'foo' => ['boolean:strict']

confirmed

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

你也可以传递一个自定义的确认字段名称。例如,confirmed:repeat_username 将期望 repeat_username 字段与正在验证的字段匹配。

contains:foo,bar,...

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

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($data, [
    'roles' => [
        'required',
        'array',
        Rule::contains(['admin', 'editor']),
    ],
]);

doesnt_contain:foo,bar,...

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

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($data, [
    'roles' => [
        'required',
        'array',
        Rule::doesntContain(['admin', 'editor']),
    ],
]);

current_password

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

php
'password' => ['current_password:api']

date

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

date_equals:日期

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

date_format:格式,...

验证中的字段必须匹配给定的 格式 之一。验证字段时,应使用 要么 datedate_format,而不是两者都使用。此验证规则支持 PHP 的 DateTime 类支持的所有格式。

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

php
use Illuminate\Validation\Rule;

'start_date' => [
    'required',
    Rule::date()->format('Y-m-d'),
],

decimal:最小值,最大值

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

php
// 必须正好有两位小数 (9.99)...
'price' => ['decimal:2']

// 必须介于 2 到 4 位小数之间...
'price' => ['decimal:2,4']

declined

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

declined_if:另一个字段,值,...

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

different:字段

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

digits:

验证中的整数必须具有精确长度为

digits_between:最小值,最大值

验证中的整数的长度必须在给定的 最小值最大值 之间。

dimensions

验证中的文件必须是满足规则参数指定的维度约束的图像:

php
'avatar' => ['dimensions:min_width=100,min_height=200']

可用的约束有:min_widthmax_widthmin_heightmax_heightwidthheightratiomin_ratiomax_ratio

ratio 约束应表示为宽度除以高度。这可以通过像 3/2 这样的分数或像 1.5 这样的浮点数来指定:

php
'avatar' => ['dimensions:ratio=3/2']

可使用 min_ratiomax_ratio 约束来定义可接受的宽高比范围:

php
'avatar' => ['dimensions:min_ratio=1/2,max_ratio=3/2']

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

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($data, [
    'avatar' => [
        'required',
        Rule::dimensions()
            ->maxWidth(1000)
            ->maxHeight(500)
            ->ratio(3 / 2),
    ],
]);

您还可以使用 minRatiomaxRatioratioBetween 方法来流畅地定义宽高比约束:

php
Rule::dimensions()->ratioBetween(min: 1 / 2, max: 3 / 2)

distinct

验证数组时,验证中的字段不得有任何重复值:

php
'foo.*.id' => ['distinct']

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

php
'foo.*.id' => ['distinct:strict']

你可以向验证规则的参数添加 ignore_case,以使规则忽略大小写差异:

php
'foo.*.id' => ['distinct:ignore_case']

doesnt_start_with:foo,bar,...

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

doesnt_end_with:foo,bar,...

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

email

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

php
'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 字符。

为了方便起见,可以使用流畅的规则构建器来构建电子邮件验证规则:

php
use Illuminate\Validation\Rule;

$request->validate([
    'email' => [
        'required',
        Rule::email()
            ->rfcCompliant(strict: false)
            ->validateMxRecord()
            ->preventSpoofing()
    ],
]);

警告

dnsspoof 验证器需要 PHP intl 扩展。

encoding:编码类型

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

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\File;

Validator::validate($input, [
    'attachment' => [
        'required',
        File::types(['csv'])
            ->encoding('utf-8'),
    ],
]);

ends_with:foo,bar,...

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

enum

Enum 规则是一个基于类的规则,它验证验证中的字段是否包含有效的枚举值。Enum 规则将枚举的名称作为其唯一的构造函数参数。验证原始值时,应向 Enum 规则提供一个有标量值的枚举:

php
use App\Enums\ServerStatus;
use Illuminate\Validation\Rule;

$request->validate([
    'status' => [Rule::enum(ServerStatus::class)],
]);

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

php
Rule::enum(ServerStatus::class)
    ->only([ServerStatus::Pending, ServerStatus::Active]);

Rule::enum(ServerStatus::class)
    ->except([ServerStatus::Pending, ServerStatus::Active]);

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

php
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;

Rule::enum(ServerStatus::class)
    ->when(
        Auth::user()->isAdmin(),
        fn ($rule) => $rule->only(...),
        fn ($rule) => $rule->only(...),
    );

exclude

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

exclude_if:另一个字段,

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

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

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($request->all(), [
    'role_id' => [Rule::excludeIf($request->user()->is_admin)],
]);

Validator::make($request->all(), [
    'role_id' => [Rule::excludeIf(fn () => $request->user()->is_admin)],
]);

exclude_unless:另一个字段,

除非 另一个字段 字段等于 ,否则验证中的字段将从 validatevalidated 方法返回的请求数据中排除。如果 null (exclude_unless:name,null),则除非比较字段为 null 或比较字段从请求数据中缺失,否则将排除正在验证的字段。

如果需要复杂的条件排除逻辑,可以使用 Rule::excludeUnless 方法。该方法接受一个布尔值或一个闭包。当传入闭包时,闭包应返回 truefalse 以指示被验证的字段是否不应被排除:

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($request->all(), [
    'role_id' => [Rule::excludeUnless($request->user()->is_admin)],
]);

Validator::make($request->all(), [
    'role_id' => [Rule::excludeUnless(fn () => $request->user()->is_admin)],
]);

exclude_with:另一个字段

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

exclude_without:另一个字段

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

exists:,

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

Exists 规则的基本用法

php
'state' => ['exists:states']

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

指定自定义列名

你可以通过在数据库表名后放置它来显式指定验证规则应使用的数据库列名:

php
'state' => ['exists:states,abbreviation']

有时,你可能需要为 exists 查询指定特定的数据库连接。你可以通过在表名前加上连接名称来实现:

php
'email' => ['exists:connection.staff,email']

你可以指定应用于确定表名的 Eloquent 模型,而不是直接指定表名:

php
'user_id' => ['exists:App\Models\User,id']

如果你想自定义验证规则执行的查询,可以使用 Rule 类流畅地定义规则。

php
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::exists('staff')->where(function (Builder $query) {
            $query->where('account_id', 1);
        }),
    ],
]);

你可以通过将列名作为第二个参数提供给 exists 方法来显式指定 Rule::exists 方法生成的 exists 规则应使用的数据库列名:

php
'state' => [Rule::exists('states', 'abbreviation')],

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

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

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

extensions:foo,bar,...

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

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

警告

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

file

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

filled

当验证中的字段存在时,它不能为空。

gt:字段

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

gte:字段

验证中的字段必须大于或等于给定的 字段。这两个字段必须是同一类型。字符串、数字、数组和文件的评估方式与 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 方法流畅地构建规则:

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($data, [
    'zones' => [
        'required',
        Rule::in(['first-zone', 'second-zone']),
    ],
]);

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

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

$input = [
    'airports' => ['NYC', 'LAS'],
];

Validator::make($input, [
    'airports' => [
        'required',
        'array',
    ],
    'airports.*' => Rule::in(['NYC', 'LIT']),
]);

in_array:另一个字段.*

验证中的字段必须存在于 另一个字段 的值中。

in_array_keys:.*

验证中的字段必须是一个数组,该数组至少具有给定的 之一作为数组中的键:

php
'config' => ['array', 'in_array_keys:timezone']

integer

验证中的字段必须是整数。

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

php
'age' => ['integer:strict']

警告

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

ip

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

ipv4

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

ipv6

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

json

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

lt:字段

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

lte:字段

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

lowercase

验证中的字段必须是小写。

list

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

mac_address

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

max:

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

max_digits:

验证中的整数必须具有最大长度为

mimetypes:text/plain,...

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

php
'video' => ['mimetypes:video/avi,video/mpeg,video/quicktime'],

'media' => ['mimetypes:image/*,video/*'],

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

mimes:foo,bar,...

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

php
'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:

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

min_digits:

验证中的整数必须具有最小长度为

multiple_of:

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

missing

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

missing_if:另一个字段,,...

如果 另一个字段 字段等于任何 ,则验证中的字段不得出现。

missing_unless:另一个字段,

除非 另一个字段 字段等于任何 ,否则验证中的字段不得出现。

missing_with:foo,bar,...

仅当 任何其他指定字段存在时,验证中的字段不得出现。

missing_with_all:foo,bar,...

仅当 所有其他指定字段都存在时,验证中的字段不得出现。

not_in:foo,bar,...

验证中的字段不得包含在给定的值列表中。Rule::notIn 方法可用于流畅地构建规则:

php
use Illuminate\Validation\Rule;

Validator::make($data, [
    'toppings' => [
        'required',
        Rule::notIn(['sprinkles', 'cherries']),
    ],
]);

not_regex:模式

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

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

nullable

验证中的字段可以为 null

numeric

验证中的字段必须是 数字

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

php
'amount' => ['numeric:strict']

present

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

present_if:另一个字段,,...

如果 另一个字段 字段等于任何 ,则验证中的字段必须存在。

present_unless:另一个字段,

除非 另一个字段 字段等于任何 ,否则验证中的字段必须存在。

present_with:foo,bar,...

仅当 任何其他指定字段存在时,验证中的字段必须存在。

present_with_all:foo,bar,...

仅当 所有其他指定字段都存在时,验证中的字段必须存在。

prohibited

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

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

prohibited_if:另一个字段,,...

如果 另一个字段 字段等于任何 ,则验证中的字段必须缺失或为空。如果字段满足以下任一条件,则被视为“空”:

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

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

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($request->all(), [
    'role_id' => [Rule::prohibitedIf($request->user()->is_admin)],
]);

Validator::make($request->all(), [
    'role_id' => [Rule::prohibitedIf(fn () => $request->user()->is_admin)],
]);

prohibited_if_accepted:另一个字段,...

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

prohibited_if_declined:另一个字段,...

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

prohibited_unless:另一个字段,,...

除非 另一个字段 字段等于任何 ,否则验证中的字段必须缺失或为空。如果字段满足以下任一条件,则被视为“空”:

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

如果需要复杂的条件禁止逻辑,可以使用 Rule::prohibitedUnless 方法。该方法接受一个布尔值或一个闭包。当传入闭包时,闭包应返回 truefalse 以指示被验证的字段是否不应被禁止:

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($request->all(), [
    'role_id' => [Rule::prohibitedUnless($request->user()->is_admin)],
]);

Validator::make($request->all(), [
    'role_id' => [Rule::prohibitedUnless(fn () => $request->user()->is_admin)],
]);

prohibits:另一个字段,...

如果验证中的字段不缺失且不为空,则 另一个字段 中的所有字段都必须缺失或为空。如果字段满足以下任一条件,则被视为“空”:

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

regex:模式

验证中的字段必须匹配给定的正则表达式。

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

required

验证中的字段必须存在于输入数据中且不为空。如果字段满足以下任一条件,则被视为“空”:

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

required_if:另一个字段,,...

如果 另一个字段 字段等于任何 ,则验证中的字段必须存在且不为空。

如果你想为 required_if 规则构建更复杂的条件,可以使用 Rule::requiredIf 方法。此方法接受一个布尔值或一个闭包。当传递一个闭包时,闭包应返回 truefalse,以指示是否必需验证中的字段:

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($request->all(), [
    'role_id' => [Rule::requiredIf($request->user()->is_admin)],
]);

Validator::make($request->all(), [
    'role_id' => [Rule::requiredIf(fn () => $request->user()->is_admin)],
]);

required_if_accepted:另一个字段,...

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

required_if_declined:另一个字段,...

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

required_unless:另一个字段,,...

除非 另一个字段 字段等于任何 ,否则验证中的字段必须存在且不为空。这也意味着除非 null,否则 另一个字段 必须存在于请求数据中。如果 null (required_unless:name,null),则除非比较字段为 null 或比较字段从请求数据中缺失,否则将需要验证中的字段。

如果你希望为 required_unless 规则构建更复杂的条件,可以使用 Rule::requiredUnless 方法。该方法接受一个布尔值或一个闭包。当传入闭包时,闭包应返回 truefalse 以指示被验证的字段是否非必需:

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($request->all(), [
    'role_id' => [Rule::requiredUnless($request->user()->is_admin)],
]);

Validator::make($request->all(), [
    'role_id' => [Rule::requiredUnless(fn () => $request->user()->is_admin)],
]);

required_with:foo,bar,...

仅当 任何其他指定字段存在且不为空时,验证中的字段必须存在且不为空。

required_with_all:foo,bar,...

仅当 所有其他指定字段都存在且不为空时,验证中的字段必须存在且不为空。

required_without:foo,bar,...

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

required_without_all:foo,bar,...

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

required_array_keys:foo,bar,...

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

same:字段

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

size:

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

php
// 验证字符串正好为 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 规则分配给该字段。

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

php
use Illuminate\Validation\Rule;

'title' => [
    'required',
    Rule::string()
        ->min(3)
        ->max(255)
        ->alphaDash(ascii: true),
],

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

timezone

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

也可以向此验证规则提供 DateTimeZone::listIdentifiers 方法接受的参数

php
'timezone' => ['required', 'timezone:all'];

'timezone' => ['required', 'timezone:Africa'];

'timezone' => ['required', 'timezone:per_country,US'];

unique:,

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

指定自定义表/列名:

你可以指定应用于确定表名的 Eloquent 模型,而不是直接指定表名:

php
'email' => ['unique:App\Models\User,email_address']

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

php
'email' => ['unique:users,email_address']

指定自定义数据库连接

有时,你可能需要为验证器进行的数据库查询设置自定义连接。为此,你可以在表名前加上连接名称:

php
'email' => ['unique:connection.users,email_address']

强制唯一规则忽略给定 ID:

有时,你可能希望在唯一性验证期间忽略给定的 ID。例如,考虑一个包含用户姓名、电子邮件地址和位置的“更新个人资料”屏幕。你可能想验证电子邮件地址是唯一的。但是,如果用户只更改了姓名字段而没有更改电子邮件字段,你不希望引发验证错误,因为用户已经是所讨论的电子邮件地址的所有者。

为了指示验证器忽略用户的 ID,我们将使用 Rule 类流畅地定义规则。

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::unique('users')->ignore($user->id),
    ],
]);

警告

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

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

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

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

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

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

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

添加额外的 Where 子句:

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

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

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

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

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

如果你的模型对于软删除记录使用的列名不是 deleted_at,你可以在调用 withoutTrashed 方法时提供列名:

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

uppercase

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

url

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

如果你想指定应视为有效的 URL 协议,可以将协议作为验证规则参数传递:

php
'url' => ['url:http,https'],

'game' => ['url:minecraft,steam'],

ulid

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

uuid

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

你也可以通过版本来验证给定的 UUID 是否符合 UUID 规范:

php
'uuid' => ['uuid:4']

有条件地添加规则

当字段具有某些值时跳过验证

有时,如果另一个字段具有给定值,你可能希望不验证给定字段。你可以使用 exclude_if 验证规则来实现这一点。在此示例中,如果 has_appointment 字段的值为 false,则不会验证 appointment_datedoctor_name 字段:

php
use Illuminate\Support\Facades\Validator;

$validator = Validator::make($data, [
    'has_appointment' => ['required', 'boolean'],
    'appointment_date' => ['exclude_if:has_appointment,false', 'required', 'date'],
    'doctor_name' => ['exclude_if:has_appointment,false', 'required', 'string'],
]);

或者,你可以使用 exclude_unless 规则,除非另一个字段具有给定值,否则不验证给定字段:

php
$validator = Validator::make($data, [
    'has_appointment' => ['required', 'boolean'],
    'appointment_date' => ['exclude_unless:has_appointment,true', 'required', 'date'],
    'doctor_name' => ['exclude_unless:has_appointment,true', 'required', 'string'],
]);

当存在时进行验证

在某些情况下,你可能希望当某个字段存在于正在验证的数据中时,才对该字段运行验证检查。要快速实现此目的,请将 sometimes 规则添加到规则列表中:

php
$validator = Validator::make($data, [
    'email' => ['sometimes', 'required', 'email'],
]);

在上面的示例中,仅当 email 字段存在于 $data 数组中时,才会对其进行验证。

NOTE

如果你正在尝试验证一个应始终存在但可能为空的字段,请查看 关于可选字段的说明

复杂条件验证

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

php
use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'email' => ['required', 'email'],
    'games' => ['required', 'integer', 'min:0'],
]);

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

php
use Illuminate\Support\Fluent;

$validator->sometimes('reason', ['required', 'max:500'], function (Fluent $input) {
    return $input->games >= 100;
});

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

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

NOTE

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

复杂条件数组验证

有时你可能希望根据同一嵌套数组中的另一个字段来验证字段,而你不知道该字段的索引。在这些情况下,你可以让你的闭包接收第二个参数,它将是正在验证的数组中的当前单个项目:

php
$input = [
    'channels' => [
        [
            'type' => 'email',
            'address' => 'abigail@example.com',
        ],
        [
            'type' => 'url',
            'address' => 'https://example.com',
        ],
    ],
];

$validator->sometimes('channels.*.address', 'email', function (Fluent $input, Fluent $item) {
    return $item->type === 'email';
});

$validator->sometimes('channels.*.address', 'url', function (Fluent $input, Fluent $item) {
    return $item->type !== 'email';
});

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

验证数组

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

php
use Illuminate\Support\Facades\Validator;

$input = [
    'user' => [
        'name' => 'Taylor Otwell',
        'username' => 'taylorotwell',
        'admin' => true,
    ],
];

Validator::make($input, [
    'user' => ['array:name,username'],
]);

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

验证嵌套数组输入

验证基于数组的表单输入字段并不一定麻烦。你可以使用“点表示法”来验证数组中的属性。例如,如果传入的 HTTP 请求包含 photos[profile] 字段,你可以像这样验证它:

php
use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'photos.profile' => ['required', 'image'],
]);

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

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

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

php
'custom' => [
    'users.*.email' => [
        'unique' => '每个用户必须有一个唯一的电子邮件地址',
    ]
],

访问嵌套数组数据

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

php
use App\Rules\HasPermission;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

$validator = Validator::make($request->all(), [
    'companies.*.id' => Rule::forEach(function (string|null $value, string $attribute) {
        return [
            Rule::exists(Company::class, 'id'),
            new HasPermission('manage-company', $value),
        ];
    }),
]);

错误消息索引和位置

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

php
use Illuminate\Support\Facades\Validator;

$input = [
    'photos' => [
        [
            'name' => 'BeachVacation.jpg',
            'description' => '我的海滩度假照片!',
        ],
        [
            'name' => 'GrandCanyon.jpg',
            'description' => '',
        ],
    ],
];

Validator::validate($input, [
    'photos.*.description' => ['required'],
], [
    'photos.*.description.required' => '请描述照片 #:position。',
]);

根据上面的示例,验证将失败,并向用户显示错误“请描述照片 #2。”。

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

php
'photos.*.attributes.*.string' => '照片 #:second-position 的属性无效。',

验证文件

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

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\File;

Validator::validate($input, [
    'attachment' => [
        'required',
        File::types(['mp3', 'wav'])
            ->min(1024)
            ->max(12 * 1024),
    ],
]);

验证文件类型

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

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

验证文件大小

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

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

验证图像文件

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

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

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\File;

Validator::validate($input, [
    'photo' => [
        'required',
        File::image()
            ->min(1024)
            ->max(12 * 1024)
            ->dimensions(Rule::dimensions()->maxWidth(1000)->maxHeight(500)),
    ],
]);

NOTE

有关验证图像尺寸的更多信息,请参阅 尺寸规则文档

警告

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

验证图像尺寸

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

php
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\File;

File::image()->dimensions(
    Rule::dimensions()
        ->maxWidth(1000)
        ->maxHeight(500)
)

NOTE

有关验证图像尺寸的更多信息,请参阅 尺寸规则文档

验证密码

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

php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\Password;

$validator = Validator::make($request->all(), [
    'password' => ['required', 'confirmed', Password::min(8)],
]);

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

php
// 至少需要 8 个字符...
Password::min(8)

// 至少需要一个字母...
Password::min(8)->letters()

// 至少需要一个大写和一个小写字母...
Password::min(8)->mixedCase()

// 至少需要一个数字...
Password::min(8)->numbers()

// 至少需要一个符号...
Password::min(8)->symbols()

此外,你可以使用 uncompromised 方法确保密码未在公开的密码数据泄露中泄露:

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

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

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

php
// 确保密码在相同的数据泄露中出现次数少于 3 次...
Password::min(8)->uncompromised(3);

当然,你可以链接上面示例中的所有方法:

php
Password::min(8)
    ->letters()
    ->mixedCase()
    ->numbers()
    ->symbols()
    ->uncompromised()

你可以使用 toPasswordRulesString 方法将 Password 规则对象转换为适合 HTML passwordrules 属性的字符串:

blade
<input
    type="password"
    name="password"
    autocomplete="new-password"
    passwordrules="{{ Password::defaults()->toPasswordRulesString() }}"
/>

定义默认密码规则

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

php
use Illuminate\Validation\Rules\Password;

/**
 * 引导任何应用服务。
 */
public function boot(): void
{
    Password::defaults(function () {
        $rule = Password::min(8);

        return $this->app->isProduction()
            ? $rule->mixedCase()->uncompromised()
            : $rule;
    });
}

然后,当你希望将默认规则应用于正在验证的特定密码时,你可以不带参数调用 defaults 方法:

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

偶尔,你可能想将额外的验证规则附加到你的默认密码验证规则。你可以使用 rules 方法来实现:

php
use App\Rules\ZxcvbnRule;

Password::defaults(function () {
    $rule = Password::min(8)->rules([new ZxcvbnRule]);

    // ...
});

自定义验证规则

使用规则对象

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

shell
php artisan make:rule Uppercase

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

php
<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class Uppercase implements ValidationRule
{
    /**
     * 运行验证规则。
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (strtoupper($value) !== $value) {
            $fail(':attribute 必须为大写。');
        }
    }
}

定义规则后,你可以通过将规则对象的实例与其他验证规则一起传递给验证器来将其附加到验证器:

php
use App\Rules\Uppercase;

$request->validate([
    'name' => ['required', 'string', new Uppercase],
]);

翻译验证消息

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

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

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

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

访问其他数据

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

php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ValidationRule;

class Uppercase implements DataAwareRule, ValidationRule
{
    /**
     * 正在验证的所有数据。
     *
     * @var array<string, mixed>
     */
    protected $data = [];

    // ...

    /**
     * 设置正在验证的数据。
     *
     * @param  array<string, mixed>  $data
     */
    public function setData(array $data): static
    {
        $this->data = $data;

        return $this;
    }
}

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

php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Validation\Validator;

class Uppercase implements ValidationRule, ValidatorAwareRule
{
    /**
     * 验证器实例。
     *
     * @var \Illuminate\Validation\Validator
     */
    protected $validator;

    // ...

    /**
     * 设置当前验证器。
     */
    public function setValidator(Validator $validator): static
    {
        $this->validator = $validator;

        return $this;
    }
}

使用闭包

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

php
use Illuminate\Support\Facades\Validator;
use Closure;

$validator = Validator::make($request->all(), [
    'title' => [
        'required',
        'max:255',
        function (string $attribute, mixed $value, Closure $fail) {
            if ($value === 'foo') {
                $fail("{$attribute} 无效。");
            }
        },
    ],
]);

隐式规则

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

php
use Illuminate\Support\Facades\Validator;

$rules = ['name' => ['unique:users,name']];

$input = ['name' => ''];

Validator::make($input, $rules)->passes(); // true

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

shell
php artisan make:rule Uppercase --implicit

警告

“隐式”规则仅 暗示 该属性是必需的。它实际上是否会使缺失或空的属性失效,由你决定。