Skip to content

验证

介绍

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

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

验证快速入门

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

定义路由

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

use App\Http\Controllers\PostController;

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

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

创建控制器

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

<?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 方法:

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

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

    return redirect('/posts');
}

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

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

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

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

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

在第一次验证失败时停止

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

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

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

关于嵌套属性的说明

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

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

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

$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 方法,允许我们在视图中显示错误消息:

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

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

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

重新填充表单

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

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

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

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

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

关于可选字段的说明

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

$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 响应格式示例。请注意,嵌套错误键被展平为“点”符号格式:

{
  "message": "团队名称必须是字符串。(还有 4 个错误)",
  "errors": {
    "team_name": ["团队名称必须是字符串。", "团队名称必须至少 1 个字符。"],
    "authorization.role": ["所选的 authorization.role 无效。"],
    "users.0.email": ["users.0.email 字段是必需的。"],
    "users.2.email": ["users.2.email 必须是有效的电子邮件地址。"]
  }
}

表单请求验证

创建表单请求

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

php
artisan make:request StorePostRequest

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

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

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

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

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

/**
 * 存储新的博客文章。
 */
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 请求,将返回一个包含 验证错误的 JSON 表示 的 HTTP 响应,状态码为 422。

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

执行额外验证

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

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

use Illuminate\Validation\Validator;

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

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

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

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

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

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

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

自定义重定向位置

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

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

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

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

授权表单请求

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

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} 参数:

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

因此,如果您的应用程序利用了 路由模型绑定,您的代码可以通过访问请求的解析模型作为属性变得更加简洁:

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

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

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

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

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

自定义错误消息

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

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

自定义验证属性

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

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

准备验证输入

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

use Illuminate\Support\Str;

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

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

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

手动创建验证器

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

<?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 方法将通知验证器在发生单个验证失败后应停止验证所有属性:

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

自动重定向

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

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

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

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

命名错误包

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

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

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

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

自定义错误消息

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

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

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

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

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

有时您可能希望仅为特定属性指定自定义错误消息。您可以使用“点”符号来实现。首先指定属性的名称,然后是规则:

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

指定自定义属性值

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

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

执行额外验证

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

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 实例:

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

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

处理验证后的输入

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

$validated = $request->validated();

$validated = $validator->validated();

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

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

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

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

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

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

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

$email = $validated['email'];

如果您希望将其他字段添加到验证后的数据中,可以调用 merge 方法:

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

如果您希望将验证后的数据作为 集合 实例检索,可以调用 collect 方法:

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

处理错误消息

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

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

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

$errors = $validator->errors();

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

检索字段的所有错误消息

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

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

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

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

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

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

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

确定字段是否存在消息

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

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

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

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 数组中:

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

在语言文件中指定属性

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

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

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

在语言文件中指定值

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

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

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

当付款类型为 cc 时,信用卡号字段是必需的。

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

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

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

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

当付款类型为信用卡时,信用卡号字段是必需的。

可用的验证规则

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

AcceptedAccepted IfActive URLAfter (Date)After Or Equal (Date)AlphaAlpha DashAlpha NumericArrayAsciiBailBefore (Date)Before Or Equal (Date)BetweenBooleanConfirmedCurrent PasswordDateDate EqualsDate FormatDecimalDeclinedDeclined IfDifferentDigitsDigits BetweenDimensions (Image Files)DistinctDoesnt Start WithDoesnt End WithEmailEnds WithEnumExcludeExclude IfExclude UnlessExclude WithExclude WithoutExists (Database)ExtensionsFileFilledGreater ThanGreater Than Or EqualHex ColorImage (File)InIn ArrayIntegerIP AddressJSONLess ThanLess Than Or EqualLowercaseMAC AddressMaxMax DigitsMIME TypesMIME Type By File ExtensionMinMin DigitsMissingMissing IfMissing UnlessMissing WithMissing With AllMultiple OfNot InNot RegexNullableNumericPresentPresent IfPresent UnlessPresent WithPresent With AllProhibitedProhibited IfProhibited UnlessProhibitsRegular ExpressionRequiredRequired IfRequired If AcceptedRequired UnlessRequired WithRequired With AllRequired WithoutRequired Without AllRequired Array KeysSameSizeSometimesStarts WithStringTimezoneUnique (Database)UppercaseURLULIDUUID

accepted

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

accepted_if:anotherfield,value,...

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

active_url

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

after:date

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

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

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

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

after_or_equal:date

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

alpha

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

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

'username' => 'alpha:ascii',

alpha_dash

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

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

'username' => 'alpha_dash:ascii',

alpha_num

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

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

'username' => 'alpha_num:ascii',

array

验证的字段必须是 PHP array

array 规则提供了额外的值时,输入数组中的每个键必须存在于规则提供的值列表中。在以下示例中,输入数组中的 admin 键无效,因为它不包含在 array 规则提供的值列表中:

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 方法将通知验证器在发生单个验证失败后应停止验证所有属性:

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

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

'password' => 'current_password:api'

date

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

date_equals:date

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

date_format:format,...

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

decimal:min,max

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

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

// 必须有 2 到 4 位小数...
'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

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

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

可用的约束是:min_widthmax_widthmin_heightmax_heightwidthheightratio

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

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

由于此规则需要多个参数,您可以使用 Rule::dimensions 方法来流畅地构建规则:

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

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

distinct

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

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

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

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

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

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

doesnt_start_with:foo,bar,...

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

doesnt_end_with:foo,bar,...

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

email

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

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

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

  • rfc: RFCValidation
  • strict: NoRFCWarningsValidation
  • dns: DNSCheckValidation
  • spoof: SpoofCheckValidation
  • filter: FilterEmailValidation
  • filter_unicode: FilterEmailValidation::unicode()

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

dnsspoof 验证器需要 PHP intl 扩展。

ends_with:foo,bar,...

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

enum

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

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

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

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

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

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

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

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:anotherfield,value

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

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

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:anotherfield,value

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

exclude_with:anotherfield

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

exclude_without:anotherfield

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

exists:table,column

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

Exists 规则的基本用法

'state' => 'exists:states'

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

指定自定义列名

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

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

有时,您可能需要指定用于 exists 查询的特定数据库连接。您可以通过在表名之前添加连接名称来实现这一点:

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

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

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

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

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) {
            return $query->where('account_id', 1);
        }),
    ],
]);

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

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

extensions:foo,bar,...

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

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

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

file

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

filled

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

gt:field

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

gte:field

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

hex_color

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

image

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

in:foo,bar,...

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

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 规则的机场列表中:

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:anotherfield.*

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

integer

验证的字段必须是整数。

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

ip

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

ipv4

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

ipv6

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

json

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

lt:field

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

lte:field

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

lowercase

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

mac_address

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

max:value

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

max_digits:value

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

mimetypes:text/plain,...

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

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

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

mimes:foo,bar,...

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

'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 方法来流畅地构建规则:

use Illuminate\Validation\Rule;

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

not_regex:pattern

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

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

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

nullable

验证的字段可以是 null

numeric

验证的字段必须是 数字

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,以指示是否应禁止验证的字段:

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_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,以指示验证的字段是必需的:

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:anotherfield,...

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

required_unless:anotherfield,value,...

除非 anotherfield 字段等于任何 value,否则验证的字段必须存在且不为空。这也意味着 anotherfield 必须存在于请求数据中,除非 valuenull。如果 valuenullrequired_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 对应于文件大小(以千字节为单位)。让我们看一些示例:

// 验证字符串是否恰好为 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

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

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

'timezone' => 'required|timezone:all';

'timezone' => 'required|timezone:Africa';

'timezone' => 'required|timezone:per_country,US';

unique:table,column

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

指定自定义表/列名:

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

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

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

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

指定自定义数据库连接

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

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

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

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

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

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 将自动从模型中提取键:

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

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

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

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

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

添加额外的 Where 子句:

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

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

uppercase

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

url

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

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

'url' => 'url:http,https',

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

ulid

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

uuid

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

有条件地添加规则

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

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

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 规则,除非另一个字段具有给定值,否则不验证给定字段:

$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 规则添加到您的规则列表中:

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

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

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

复杂条件验证

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

use Illuminate\Support\Facades\Validator;

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

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

use Illuminate\Support\Fluent;

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

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

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

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

复杂条件数组验证

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

$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 验证规则文档 中所述,array 规则接受允许的数组键列表。如果数组中存在任何其他键,验证将失败:

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] 字段,您可以这样验证它:

use Illuminate\Support\Facades\Validator;

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

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

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

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

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

访问嵌套数组数据

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

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 开始)占位符:

use Illuminate\Support\Facades\Validator;

$input = [
    'photos' => [
        [
            'name' => 'BeachVacation.jpg',
            'description' => 'A photo of my beach vacation!',
        ],
        [
            'name' => 'GrandCanyon.jpg',
            'description' => '',
        ],
    ],
];

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

根据上面的示例,验证将失败,用户将看到以下错误:“请描述照片 #2。”

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

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

验证文件

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

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

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

如果您的应用程序接受用户上传的图像,可以使用 File 规则的 image 构造方法来指示上传的文件应为图像。此外,可以使用 dimensions 规则限制图像的尺寸:

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)),
    ],
]);

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

文件大小

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

File::image()
    ->min('1kb')
    ->max('10mb')

文件类型

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

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

验证密码

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

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

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

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

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

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

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

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

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

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

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

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

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

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

当然,您可以将上述示例中的所有方法链接在一起:

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

定义默认密码规则

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

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 方法而不带参数:

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

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

use App\Rules\ZxcvbnRule;

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

    // ...
});

自定义验证规则

使用规则对象

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

php
artisan make:rule Uppercase

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

<?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('The :attribute must be uppercase.');
        }
    }
}

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

use App\Rules\Uppercase;

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

翻译验证消息

您可以提供 翻译字符串键 并指示 Laravel 翻译错误消息,而不是将文字错误消息提供给 $fail 闭包:

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

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

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

访问额外数据

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

<?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

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 回调:

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("The {$attribute} is invalid.");
            }
        },
    ],
]);

隐式规则

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

use Illuminate\Support\Facades\Validator;

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

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

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

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

php
artisan make:rule Uppercase --implicit

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