表单验证

未匹配的标注
本文档最新版为 10.x,旧版本可能放弃维护,推荐阅读最新版!

表单验证

简介

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');
    }

    /**
     * 存储博客的 Action
     */
    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 会自动将用户重定向到之前的位置。此外,所有的验证错误和 请求输入 都会自动存入到 闪存 session 中。

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

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

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

<h1>Create Post</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 目录,你可以指示 Laravel 使用 lang:publish Artisan命令创建它。

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

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

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

XHR 请求和验证

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

@error 指令

你可以使用 @error Blade 指令快速确定某个属性是否存在验证错误消息。 在 @error 指令内部,你可以回显 $message 变量来显示错误消息

<!-- /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 由于验证错误而生成重定向响应时,框架将自动 闪存所有请求的输入到 session 中。这样做是为了在下一个请求期间方便地访问输入,并重新填充用户尝试提交的表单。

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

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

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

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

关于可选字段的注意事项

默认情况下,Laravel 在应用程序的全局中间件堆栈中包含 TrimStringsConvertEmptyStringsToNull 中间件。因此,如果您不希望 null 值被验证器标识为非法的话,您需要将「可选」字段标记为 nullable。例如:

$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": "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 命令:

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');
}

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

技巧
需要为您的 Inertia 驱动的 Laravel 前端添加实时表单请求验证吗? 请查看 Laravel 实时服务器端表单验证扩展.

执行附加验证

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

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

use Illuminate\Validation\Validator;

/**
 * 获取请求的 after 验证可调用项。
 */
public function after(): array
{
    return [
        function (Validator $validator) {
            if ($this->somethingElseIsInvalid()) {
                $validator->errors()->add(
                    'field',
                    'Something is wrong with this field!'
                );
            }
        }
    ];
}

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

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 属性添加到请求类,你可以通知验证器,一旦发生单个验证失败,它就应该停止验证所有属性:

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

自定义重定向位置

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

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

执行额外的验证

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

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

use Illuminate\Validation\Validator;

/**
 * 获取请求的「after」验证可调用对象。
 */
public function after(): array
{
    return [
        function (Validator $validator) {
            if ($this->somethingElseIsInvalid()) {
                $validator->errors()->add(
                    'field',
                    'Something is wrong with this field!'
                );
            }
        }
    ];
}

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

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 属性,您可以告知验证器在出现单个验证失败后应停止验证所有属性:

/**
 * 指示验证器是否应该在第一个规则失败时停止。
 *
 * @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,将自动返回一个 HTTP 403 状态码的响应,并且您的控制器方法不会被执行。

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

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

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

自定义错误消息

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

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

自定义验证属性

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

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

准备验证输入

如果您需要在应用验证规则之前准备或清理请求中的任何数据,可以使用 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 门面手动创建一个验证器实例。门面上的 make 方法生成一个新的验证器实例:

<?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', 'Something is wrong with this 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 的实例。此对象仅公开 only, exceptall 方法,用于检索已验证数据的子集或全部已验证数据数组:

$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' => 'We need to know your email address!',
        'max' => 'Your email address is too long!'
    ],
],

在语言文件中指定属性

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

'attributes' => [
    'email' => 'email address',
],

警告
默认情况下,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' => 'credit card'
    ],
],

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

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

当支付类型为信用卡时,信用卡号码字段是必填的。

可用的验证规则

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

accepted

待验证的字段必须是 「yes」「on」1「1」true「true」。这对于验证「服务条款」接受或类似字段非常有用。

accepted_if:anotherfield,value,…

如果另一个验证中的字段等于指定值,则验证字段必须为 「yes」「on」1「1」true「true」。这对于验证「服务条款」接受或类似字段非常有用。

active_url

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

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

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

为了将此验证规则限制在 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}, and \p{N}.

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

'username' => 'alpha_num:ascii',

array

待验证字段必须是有效的 PHP 数组

当向 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

待验证字段值的大小必须介于给定的最小值和最大值(含)之间。字符串、数字、数组和文件的计算方式都使用 size 方法。

boolean

验证的字段必须能够被转换为布尔值。接受的输入包括 true, false, 1, 0, 「1」, 和 「0」

confirmed

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

contains:foo,bar,…

这个验证字段必须是一个数组,其中包含了所有给定的参数数值。

current_password

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

'password' => 'current_password:api'

date

验证字段必须是 strtotime PHP 函数可识别的有效日期。

date_equals:date

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

date_format:format,…

验证字段必须匹配给定的 format 。在验证字段时,您应该只使用 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 的 5.8 版本之前是 Laravel 默认的电子邮件验证行为。

注意
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 方法返回的请求数据中排除。如果 valuenull (exclude_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);
        }),
    ],
]);

你可以通过将列名作为第二个参数提供给 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

在验证时,字段必须是整数。

注意
这个验证规则不验证输入是否是「integer」变量类型,而只是验证输入是否是 PHP 的 FILTER_VALIDATE_INT 规则接受的类型。如果您需要验证输入是否为数字,请将此规则与 numeric 验证规则 结合使用。

ip

在验证时,字段必须是 IP 地址。

ipv4

在验证时,字段必须是 IPv4 地址。

ipv6

在验证时,字段必须是 IPv6 地址。

json

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

lt:field

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

lte:field

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

lowercase

在验证时,字段必须是小写。

list

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

mac_address

在验证时,字段必须是 MAC 地址。

max:value

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

max_digits:value

在验证时,整数必须有最大长度 value

mimetypes:text/plain,…

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

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

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

mimes:foo,bar,…

在验证时,文件必须有一个与列出的扩展名对应的 MIME 类型:

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

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

svn.apache.org/repos/asf/httpd/htt...

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_if_declined:anotherfield,…

如果 anotherfield 字段等于 「no」, 「off」, 0, 「0」, false, 或 「false」,在验证时,该字段必须存在且不为空。

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,…

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

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'

指定自定义数据库连接

偶尔,你可能需要为 Validator 执行的数据库查询设置自定义连接。为此,你可以在表名前加上连接名:

'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 方法自定义查询来指定额外的查询条件。例如,让我们添加一个查询条件,将查询限定在只搜索 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',
]);

在上面的例子中,如果 email 字段存在于 $data 数组中,则只会验证该字段。

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

复杂条件验证

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

use Illuminate\Support\Facades\Validator;

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

让我们假设我们的网站应用程序是为游戏收藏家设计的。如果游戏收藏家向我们的应用程序注册并拥有超过 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' => 'Each person must have a unique email address',
    ]
],

访问嵌套数组数据

有时你可能需要在为属性分配验证规则时访问给定嵌套数组元素的值。你可以使用 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' => '我海滩度假的照片!',
        ],
        [
            'name' => 'GrandCanyon.jpg',
            'description' => '',
        ],
    ],
];

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

根据上述示例,验证将失败,用户将收到以下错误信息:「请描述第 2 张照片。.」

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

'photos.*.attributes.*.string' => 'Invalid attribute for photo #: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)),
    ],
]);

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

文件大小

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

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

文件类型

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

svn.apache.org/repos/asf/httpd/htt...

验证密码

为确保密码具有足够的复杂性,你可以使用 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 方法给出的闭包应返回密码规则的默认配置。通常,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('属性必须是大写的');
        }
    }
}

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

use App\Rules\Uppercase;

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

翻译验证消息

你可以不提供 $fail 闭包的错误消息,而是提供一个翻译字符串键,并指示 Laravel 翻译错误消息:

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

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

php artisan make:rule Uppercase --implicit

注意
「隐式」规则仅 暗示 该属性是必需的。实际上,缺少或空属性是否无效取决于你。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/laravel/11.x/va...

译文地址:https://learnku.com/docs/laravel/11.x/va...

上一篇 下一篇
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
贡献者:13
讨论数量: 0
发起讨论 只看当前版本


暂无话题~