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 App\Http\Controllers\Controller;
use Illuminate\Http\Request;

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

    /**
     * 存储新的博客文章。
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        // 验证并存储博客文章...
    }
}

编写验证逻辑

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

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

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

php
/**
 * 存储新的博客文章。
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);

    // 博客文章是有效的...
}

如您所见,验证规则被传递到 validate 方法中。别担心 - 所有可用的验证规则都在文档中记录。再次强调,如果验证失败,将自动生成适当的响应。如果验证通过,我们的控制器将继续正常执行。

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

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

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

php
$validatedData = $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 将自动将用户重定向回其先前的位置。此外,所有验证错误和请求输入将自动闪存到会话

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

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

html
<!-- /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 的内置验证规则每个都有一个错误消息,位于应用程序的 resources/lang/en/validation.php 文件中。在此文件中,您将找到每个验证规则的翻译条目。您可以根据应用程序的需要自由更改或修改这些消息。

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

XHR 请求与验证

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

@error 指令

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

html
<!-- /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 指令:

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

重新填充表单

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

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

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

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

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

关于可选字段的说明

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

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

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

表单请求验证

创建表单请求

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

php
php artisan make:request StorePostRequest

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

正如您可能猜到的那样,authorize 方法负责确定当前认证用户是否可以执行请求所代表的操作,而 rules 方法返回应应用于请求数据的验证规则:

php
/**
 * 获取适用于请求的验证规则。
 *
 * @return array
 */
public function rules()
{
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];
}
lightbulb

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

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

php
/**
 * 存储新的博客文章。
 *
 * @param  \App\Http\Requests\StorePostRequest  $request
 * @return Illuminate\Http\Response
 */
public function store(StorePostRequest $request)
{
    // 传入的请求是有效的...

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

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

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

向表单请求添加后钩子

如果您想向表单请求添加“后”验证钩子,可以使用 withValidator 方法。此方法接收完全构造的验证器,允许您在实际评估验证规则之前调用其任何方法:

php
/**
 * 配置验证器实例。
 *
 * @param  \Illuminate\Validation\Validator  $validator
 * @return void
 */
public function withValidator($validator)
{
    $validator->after(function ($validator) {
        if ($this->somethingElseIsInvalid()) {
            $validator->errors()->add('field', '此字段有问题!');
        }
    });
}

在第一次验证失败时停止属性

通过向请求类添加 stopOnFirstFailure 属性,您可以通知验证器在发生单个验证失败后应停止验证所有属性:

php
/**
 * 指示验证器是否应在第一次规则失败时停止。
 *
 * @var bool
 */
protected $stopOnFirstFailure = true;

自定义重定向位置

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

php
/**
 * 如果验证失败,用户应重定向到的 URI。
 *
 * @var string
 */
protected $redirect = '/dashboard';

或者,如果您希望将用户重定向到命名路由,可以定义一个 $redirectRoute 属性:

php
/**
 * 如果验证失败,用户应重定向到的路由。
 *
 * @var string
 */
protected $redirectRoute = 'dashboard';

授权表单请求

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

php
use App\Models\Comment;

/**
 * 确定用户是否有权发出此请求。
 *
 * @return bool
 */
public function authorize()
{
    $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
/**
 * 确定用户是否有权发出此请求。
 *
 * @return bool
 */
public function authorize()
{
    return true;
}
lightbulb

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

自定义错误消息

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

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

自定义验证属性

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

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

准备验证输入

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

php
use Illuminate\Support\Str;

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

手动创建验证器

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

php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

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

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

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

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

        // 存储博客文章...
    }
}

传递给 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 实例:

php
{{ $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 方法:

php
$validator = Validator::make(...);

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

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

处理验证后的输入

在使用表单请求或手动创建的验证器实例验证传入请求数据后,您可能希望检索实际经过验证的传入请求数据。这可以通过多种方式实现。首先,您可以在表单请求或验证器实例上调用 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 的内置验证规则每个都有一个错误消息,位于应用程序的 resources/lang/en/validation.php 文件中。在此文件中,您将找到每个验证规则的翻译条目。您可以根据应用程序的需要自由更改或修改这些消息。

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

为特定属性自定义消息

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

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

在语言文件中指定属性

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

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

在语言文件中指定值

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

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

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

php
信用卡号字段在支付类型为 cc 时是必需的。

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

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

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

php
信用卡号字段在支付类型为信用卡时是必需的。

可用的验证规则

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

accepted

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

accepted_if:anotherfield,value,...

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

active_url

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

after:date

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

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

您可以指定另一个字段来与日期进行比较,而不是传递要由 strtotime 评估的日期字符串:

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

after_or_equal:date

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

alpha

验证字段必须完全是字母字符。

alpha_dash

验证字段可以包含字母数字字符,以及破折号和下划线。

alpha_num

验证字段必须完全是字母数字字符。

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:username,locale',
]);

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

如果您愿意,可以指示 Laravel 的验证器永远不要在其返回的“验证”数据中包含未经验证的数组键,即使您使用 array 规则而不指定允许的键列表。为此,您可以在应用程序的 AppServiceProviderboot 方法中调用验证器的 excludeUnvalidatedArrayKeys 方法。这样做后,验证器将仅在这些键通过嵌套数组规则验证时才在其返回的“验证”数据中包含数组键:

php
use Illuminate\Support\Facades\Validator;

/**
 * 注册任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    Validator::excludeUnvalidatedArrayKeys();
}

bail

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

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

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

before:date

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

before_or_equal:date

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

between:min,max

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

boolean

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

confirmed

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

current_password

验证字段必须与已认证用户的密码匹配。您可以使用规则的第一个参数指定一个认证守卫

php
'password' => 'current_password:api'

date

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

date_equals:date

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

date_format:format

验证字段必须匹配给定的 format。在验证字段时,您应该使用 datedate_format 中的一个。此验证规则支持 PHP 的 DateTime 类支持的所有格式。

declined

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

declined_if:anotherfield,value,...

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

different:field

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

digits:value

验证字段必须是 numeric 并且长度必须为 value

digits_between:min,max

验证字段必须是 numeric 并且长度必须在给定的 minmax 之间。

dimensions

验证的文件必须是符合规则参数指定的尺寸约束的图像:

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

可用的约束有:min_widthmax_widthmin_heightmax_heightwidthheightratio

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

php
'avatar' => 'dimensions: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),
    ],
]);

distinct

在验证数组时,验证字段不得有重复值:

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

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

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

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

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

email

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

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

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

  • rfc: RFCValidation
  • strict: NoRFCWarningsValidation
  • dns: DNSCheckValidation
  • spoof: SpoofCheckValidation
  • filter: FilterEmailValidation

filter 验证器使用 PHP 的 filter_var 函数,随 Laravel 一起提供,并且是 Laravel 5.8 之前的默认电子邮件验证行为。

exclamation

dnsspoof 验证器需要 PHP intl 扩展。

ends_with:foo,bar,...

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

enum

Enum 规则是一个基于类的规则,用于验证字段是否包含有效的枚举值。Enum 规则接受枚举的名称作为其唯一的构造函数参数:

php
use App\Enums\ServerStatus;
use Illuminate\Validation\Rules\Enum;

$request->validate([
    'status' => [new Enum(ServerStatus::class)],
]);
exclamation

枚举仅在 PHP 8.1+ 上可用。

exclude

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

exclude_if:anotherfield,value

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

exclude_unless:anotherfield,value

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

exclude_without:anotherfield

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

exists:table,column

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

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\Support\Facades\Validator;
use Illuminate\Validation\Rule;

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

file

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

filled

验证字段在存在时不得为空。

gt:field

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

gte:field

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

image

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

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',
        Rule::in(['NYC', 'LIT']),
    ],
]);

in_array:anotherfield.*

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

integer

验证字段必须是整数。

exclamation

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

ip

验证字段必须是 IP 地址。

ipv4

验证字段必须是 IPv4 地址。

ipv6

验证字段必须是 IPv6 地址。

mac_address

验证字段必须是 MAC 地址。

json

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

lt:field

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

lte:field

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

max:value

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

mimetypes:text/plain,...

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

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

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

mimes:foo,bar,...

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

MIME 规则的基本用法

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

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

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

min:value

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

multiple_of:value

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

exclamation

使用 multiple_of 规则需要 bcmath PHP 扩展

not_in:foo,bar,...

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

php
use Illuminate\Validation\Rule;

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

not_regex:pattern

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

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

exclamation

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

nullable

验证字段可以为 null

numeric

验证字段必须是 numeric

password

验证字段必须与已认证用户的密码匹配。

exclamation

此规则在 Laravel 9 中被重命名为 current_password,并计划移除。请使用 Current Password 规则。

present

验证字段必须存在于输入数据中,但可以为空。

prohibited

验证字段必须为空或不存在。

prohibited_if:anotherfield,value,...

如果 anotherfield 字段等于任何 value,则验证字段必须为空或不存在。

prohibited_unless:anotherfield,value,...

除非 anotherfield 字段等于任何 value,否则验证字段必须为空或不存在。

prohibits:anotherfield,...

如果验证字段存在,则 anotherfield 中的任何字段都不能存在,即使为空。

regex:pattern

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

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

exclamation

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

required

验证字段必须存在于输入数据中且不能为空。字段被视为“空”如果以下条件之一为真:

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

required_if:anotherfield,value,...

如果 anotherfield 字段等于任何 value,则验证字段必须存在且不能为空。

如果您想为 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(function () use ($request) {
        return $request->user()->is_admin;
    }),
]);

required_unless:anotherfield,value,...

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

required_with:foo,bar,...

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

required_with_all:foo,bar,...

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

required_without:foo,bar,...

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

required_without_all:foo,bar,...

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

same:field

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

size:value

验证字段的大小必须与给定的 value 匹配。对于字符串数据,value 对应于字符数。对于数字数据,value 对应于给定的整数值(属性还必须具有 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 规则。

timezone

验证字段必须是根据 timezone_identifiers_list PHP 函数的有效时区标识符。

unique:table,column

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

指定自定义表/列名:

您可以指定应使用的 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),
    ],
]);
exclamation

您永远不应将任何用户控制的请求输入传递给 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(function ($query) {
    return $query->where('account_id', 1);
})

url

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

uuid

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

有条件地添加规则

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

有时您可能希望在另一个字段具有给定值时不验证给定字段。您可以使用 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
$v = Validator::make($data, [
    'email' => 'sometimes|required|email',
]);

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

lightbulb

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

复杂条件验证

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

php
use Illuminate\Support\Facades\Validator;

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

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

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

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

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

传递给闭包的 $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 ($input, $item) {
    return $item->type === 'email';
});

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

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

验证数组

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

php
use Illuminate\Support\Facades\Validator;

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

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

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

排除未验证的数组键

如果您愿意,您可以指示 Laravel 的验证器永远不要在其返回的“验证”数据中包含未验证的数组键,即使您使用 array 规则而未指定允许的键列表。为此,您可以在应用程序的 AppServiceProviderboot 方法中调用验证器的 excludeUnvalidatedArrayKeys 方法。这样做之后,验证器将仅在这些键通过 嵌套数组规则 进行验证时才在其返回的“验证”数据中包含数组键:

php
use Illuminate\Support\Facades\Validator;

/**
 * 注册任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    Validator::excludeUnvalidatedArrayKeys();
}

验证嵌套数组输入

验证基于嵌套数组的表单输入字段不必是痛苦的。您可以使用“点表示法”来验证数组中的属性。例如,如果传入的 HTTP 请求包含一个 photos[profile] 字段,您可以这样验证它:

php
use Illuminate\Support\Facades\Validator;

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

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

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

同样,您可以在指定 自定义验证消息 时使用 * 字符,使得为基于数组的字段使用单个验证消息变得轻而易举:

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

验证密码

为了确保密码具有足够的复杂性,您可以使用 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()

定义默认密码规则

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

php
use Illuminate\Validation\Rules\Password;

/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    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 命令创建规则时创建它:

php
php artisan make:rule Uppercase

一旦创建了规则,我们就可以定义其行为。规则对象包含两个方法:passesmessagepasses 方法接收属性值和名称,并应返回 truefalse,具体取决于属性值是否有效。message 方法应返回验证失败时应使用的验证错误消息:

php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Uppercase implements Rule
{
    /**
     * 确定验证规则是否通过。
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        return strtoupper($value) === $value;
    }

    /**
     * 获取验证错误消息。
     *
     * @return string
     */
    public function message()
    {
        return 'The :attribute must be uppercase.';
    }
}

如果您希望从翻译文件中返回错误消息,可以从 message 方法中调用 trans 助手:

php
/**
 * 获取验证错误消息。
 *
 * @return string
 */
public function message()
{
    return trans('validation.uppercase');
}

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

php
use App\Rules\Uppercase;

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

访问额外数据

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

php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\DataAwareRule;

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

    // ...

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

        return $this;
    }
}

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

php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;

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

    // ...

    /**
     * 设置当前验证器。
     *
     * @param  \Illuminate\Validation\Validator  $validator
     * @return $this
     */
    public function setValidator($validator)
    {
        $this->validator = $validator;

        return $this;
    }
}

使用闭包

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

php
use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'title' => [
        'required',
        'max:255',
        function ($attribute, $value, $fail) {
            if ($value === 'foo') {
                $fail('The '.$attribute.' is invalid.');
            }
        },
    ],
]);

隐式规则

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

php
use Illuminate\Support\Facades\Validator;

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

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

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

要使自定义规则即使在属性为空时也能运行,规则必须暗示该属性是必需的。要创建“隐式”规则,请实现 Illuminate\Contracts\Validation\ImplicitRule 接口。此接口作为验证器的“标记接口”;因此,除了典型的 Rule 接口所需的方法外,您无需实现任何其他方法。

要生成新的隐式规则对象,您可以使用 make:rule Artisan 命令和 --implicit 选项:

php
php artisan make:rule Uppercase --implicit
exclamation

“隐式”规则仅_暗示_该属性是必需的。是否实际使缺失或空的属性无效取决于您。