验证
介绍
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 本地化的更多信息,请查看完整的 本地化文档。
WARNING
默认情况下,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 在应用程序的全局中间件堆栈中包含 TrimStrings
和 ConvertEmptyStringsToNull
中间件。这些中间件由 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 生成的表单请求都有两个方法:authorize
和 rules
。
正如您可能猜到的,authorize
方法负责确定当前认证的用户是否可以执行请求所代表的操作,而 rules
方法返回应适用于请求数据的验证规则:
/**
* 获取适用于请求的验证规则。
*
* @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
*/
public function rules(): array
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
NOTE
您可以在 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。
NOTE
需要将实时表单请求验证添加到您的 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;
}
NOTE
您可以在 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
实例。此对象公开 only
、except
和 all
方法,以检索经过验证的数据子集或整个经过验证的数据数组:
$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 本地化的更多信息,请查看完整的 本地化文档。
WARNING
默认情况下,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' => '电子邮件地址',
],
WARNING
默认情况下,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' => '信用卡'
],
],
WARNING
默认情况下,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'
afteror_equal:_date
验证的字段必须是给定日期之后或等于给定日期的值。有关更多信息,请参阅 after 规则。
alpha
验证的字段必须完全是 Unicode 字母字符,包含在 \p{L}
和 \p{M}
中。
要将此验证规则限制为 ASCII 范围内的字符(a-z
和 A-Z
),可以为验证规则提供 ascii
选项:
'username' => 'alpha:ascii',
alpha_dash
验证的字段必须完全是 Unicode 字母数字字符,包含在 \p{L}
、\p{M}
、\p{N}
中,以及 ASCII 破折号(-
)和 ASCII 下划线(_
)。
要将此验证规则限制为 ASCII 范围内的字符(a-z
和 A-Z
),可以为验证规则提供 ascii
选项:
'username' => 'alpha_dash:ascii',
alpha_num
验证的字段必须完全是 Unicode 字母数字字符,包含在 \p{L}
、\p{M}
、\p{N}
中。
要将此验证规则限制为 ASCII 范围内的字符(a-z
和 A-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
的值提供。
beforeor_equal:_date
验证的字段必须是给定日期之前或等于给定日期的值。日期将传递给 PHP strtotime
函数,以便转换为有效的 DateTime
实例。此外,像 after
规则一样,可以将另一个验证字段的名称作为 date
的值提供。
between:min,max
验证的字段必须具有在给定 min 和 max 之间(含)的大小。字符串、数字、数组和文件的评估方式与 size
规则相同。
boolean
验证的字段必须能够转换为布尔值。接受的输入是 true
、false
、1
、0
、"1"
和 "0"
。
confirmed
验证的字段必须有一个匹配的 {field}_confirmation
字段。例如,如果验证的字段是 password
,则输入中必须存在一个匹配的 password_confirmation
字段。
current_password
验证的字段必须与认证用户的密码匹配。您可以使用规则的第一个参数指定 认证守卫:
'password' => 'current_password:api'
date
验证的字段必须是一个有效的、非相对的日期,根据 strtotime
PHP 函数。
dateequals:_date
验证的字段必须等于给定日期。日期将传递给 PHP strtotime
函数,以便转换为有效的 DateTime
实例。
dateformat:_format,...
验证的字段必须匹配给定 formats 中的一个。您应该在验证字段时使用 either date
或 date_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 的确切长度。
digitsbetween:_min,max
验证的整数必须具有在给定 min 和 max 之间的长度。
dimensions
验证的文件必须是符合规则参数指定的尺寸约束的图像:
'avatar' => 'dimensions:min_width=100,min_height=200'
可用的约束是:min_width、max_width、min_height、max_height、width、height、ratio。
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'
doesntstart_with:_foo,bar,...
验证的字段不得以给定值之一开头。
doesntend_with:_foo,bar,...
验证的字段不得以给定值之一结尾。
email
验证的字段必须格式化为电子邮件地址。此验证规则利用 egulias/email-validator
包来验证电子邮件地址。默认情况下,应用 RFCValidation
验证器,但您也可以应用其他验证样式:
'email' => 'email:rfc,dns'
上面的示例将应用 RFCValidation
和 DNSCheckValidation
验证。以下是您可以应用的验证样式的完整列表:
rfc
:RFCValidation
strict
:NoRFCWarningsValidation
dns
:DNSCheckValidation
spoof
:SpoofCheckValidation
filter
:FilterEmailValidation
filter_unicode
:FilterEmailValidation::unicode()
filter
验证器使用 PHP 的 filter_var
函数,随 Laravel 一起提供,并且是 Laravel 5.8 版本之前的默认电子邮件验证行为。
WARNING
dns
和 spoof
验证器需要 PHP intl
扩展。
endswith:_foo,bar,...
验证的字段必须以给定值之一结尾。
enum
Enum
规则是一个基于类的规则,用于验证验证的字段是否包含有效的枚举值。Enum
规则接受枚举的名称作为其唯一的构造函数参数。在验证原始值时,应将支持的枚举提供给 Enum
规则:
use App\Enums\ServerStatus;
use Illuminate\Validation\Rule;
$request->validate([
'status' => [Rule::enum(ServerStatus::class)],
]);
Enum
规则的 only
和 except
方法可用于限制应视为有效的枚举案例:
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
验证的字段将从 validate
和 validated
方法返回的请求数据中排除。
excludeif:_anotherfield,value
如果 anotherfield 字段等于 value,则验证的字段将从 validate
和 validated
方法返回的请求数据中排除。
如果需要复杂的条件排除逻辑,可以使用 Rule::excludeIf
方法。此方法接受一个布尔值或一个闭包。当给定一个闭包时,闭包应返回 true
或 false
,以指示是否应排除验证的字段:
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),
]);
excludeunless:_anotherfield,value
除非 anotherfield 字段等于 value,否则验证的字段将从 validate
和 validated
方法返回的请求数据中排除。如果 value 为 null
(exclude_unless:name,null
),则验证的字段将被排除,除非比较字段为 null
或比较字段在请求数据中缺失。
excludewith:_anotherfield
如果 anotherfield 字段存在,则验证的字段将从 validate
和 validated
方法返回的请求数据中排除。
excludewithout:_anotherfield
如果 anotherfield 字段不存在,则验证的字段将从 validate
和 validated
方法返回的请求数据中排除。
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'],
file
验证的字段必须是成功上传的文件。
filled
验证的字段在存在时不得为空。
gt:field
验证的字段必须大于给定的 field 或 value。两个字段必须是相同类型的。字符串、数字、数组和文件的评估方式与 size
规则相同。
gte:field
验证的字段必须大于或等于给定的 field 或 value。两个字段必须是相同类型的。字符串、数字、数组和文件的评估方式与 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']),
]);
inarray:_anotherfield.*
验证的字段必须存在于 anotherfield 的值中。
integer
验证的字段必须是整数。
WARNING
此验证规则不验证输入是否为“整数”变量类型,仅验证输入是否为 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
规则相同。
maxdigits:_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
规则相同。
mindigits:_value
验证的整数必须具有最小长度 value。
multipleof:_value
验证的字段必须是 value 的倍数。
missing
验证的字段在输入数据中不得存在。
missingif:_anotherfield,value,...
如果 anotherfield 字段等于任何 value,则验证的字段不得存在。
missingunless:_anotherfield,value
除非 anotherfield 字段等于任何 value,否则验证的字段不得存在。
missingwith:_foo,bar,...
验证的字段仅在其他指定字段中的任何一个存在时不得存在。
missingwith_all:_foo,bar,...
验证的字段仅在所有其他指定字段存在时不得存在。
notin:_foo,bar,...
验证的字段不得包含在给定值列表中。可以使用 Rule::notIn
方法来流畅地构建规则:
use Illuminate\Validation\Rule;
Validator::make($data, [
'toppings' => [
'required',
Rule::notIn(['sprinkles', 'cherries']),
],
]);
notregex:_pattern
验证的字段不得匹配给定的正则表达式。
在内部,此规则使用 PHP preg_match
函数。指定的模式应遵循 preg_match
所需的相同格式,并因此包含有效的分隔符。例如:'email' => 'not_regex:/^.+$/i'
。
WARNING
使用 regex
/ not_regex
模式时,可能需要使用数组指定验证规则,而不是使用 |
分隔符,特别是当正则表达式包含 |
字符时。
nullable
验证的字段可以是 null
。
numeric
验证的字段必须是 数字。
present
验证的字段必须存在于输入数据中。
presentif:_anotherfield,value,...
如果 anotherfield 字段等于任何 value,则验证的字段必须存在。
presentunless:_anotherfield,value
除非 anotherfield 字段等于任何 value,否则验证的字段必须存在。
presentwith:_foo,bar,...
验证的字段仅在其他指定字段中的任何一个存在时必须存在。
presentwith_all:_foo,bar,...
验证的字段仅在所有其他指定字段存在时必须存在。
prohibited
验证的字段必须缺失或为空。如果字段满足以下条件之一,则视为“空”:
- 值为
null
。 - 值为空字符串。
- 值为空数组或空的
Countable
对象。 - 值是路径为空的上传文件。
prohibitedif:_anotherfield,value,...
如果 anotherfield 字段等于任何 value,则验证的字段必须缺失或为空。如果字段满足以下条件之一,则视为“空”:
- 值为
null
。 - 值为空字符串。
- 值为空数组或空的
Countable
对象。 - 值是路径为空的上传文件。
如果需要复杂的条件禁止逻辑,可以使用 Rule::prohibitedIf
方法。此方法接受一个布尔值或一个闭包。当给定一个闭包时,闭包应返回 true
或 false
,以指示是否应禁止验证的字段:
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),
]);
prohibitedunless:_anotherfield,value,...
除非 anotherfield 字段等于任何 value,否则验证的字段必须缺失或为空。如果字段满足以下条件之一,则视为“空”:
- 值为
null
。 - 值为空字符串。
- 值为空数组或空的
Countable
对象。 - 值是路径为空的上传文件。
prohibits:anotherfield,...
如果验证的字段不缺失或为空,则 anotherfield 中的所有字段必须缺失或为空。如果字段满足以下条件之一,则视为“空”:
- 值为
null
。 - 值为空字符串。
- 值为空数组或空的
Countable
对象。 - 值是路径为空的上传文件。
regex:pattern
验证的字段必须匹配给定的正则表达式。
在内部,此规则使用 PHP preg_match
函数。指定的模式应遵循 preg_match
所需的相同格式,并因此包含有效的分隔符。例如:'email' => 'regex:/^.+@.+$/i'
。
WARNING
使用 regex
/ not_regex
模式时,可能需要使用数组指定规则,而不是使用 |
分隔符,特别是当正则表达式包含 |
字符时。
required
验证的字段必须存在于输入数据中且不为空。如果字段满足以下条件之一,则视为“空”:
- 值为
null
。 - 值为空字符串。
- 值为空数组或空的
Countable
对象。 - 值是路径为空的上传文件。
requiredif:_anotherfield,value,...
如果 anotherfield 字段等于任何 value,则验证的字段必须存在且不为空。
如果您希望为 required_if
规则构建更复杂的条件,可以使用 Rule::requiredIf
方法。此方法接受一个布尔值或一个闭包。当传递一个闭包时,闭包应返回 true
或 false
,以指示验证的字段是必需的:
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),
]);
requiredif_accepted:_anotherfield,...
如果 anotherfield 字段等于 "yes"
、"on"
、1
、"1"
、true
或 "true"
,则验证的字段必须存在且不为空。
requiredunless:_anotherfield,value,...
除非 anotherfield 字段等于任何 value,否则验证的字段必须存在且不为空。这也意味着 anotherfield 必须存在于请求数据中,除非 value 为 null
。如果 value 为 null
(required_unless:name,null
),则验证的字段将是必需的,除非比较字段为 null
或比较字段在请求数据中缺失。
requiredwith:_foo,bar,...
验证的字段仅在其他指定字段中的任何一个存在且不为空时必须存在且不为空。
requiredwith_all:_foo,bar,...
验证的字段仅在所有其他指定字段存在且不为空时必须存在且不为空。
requiredwithout:_foo,bar,...
验证的字段仅在其他指定字段中的任何一个为空或不存在时必须存在且不为空。
requiredwithout_all:_foo,bar,...
验证的字段仅在所有其他指定字段为空或不存在时必须存在且不为空。
requiredarray_keys:_foo,bar,...
验证的字段必须是一个数组,并且必须至少包含指定的键。
same:field
给定的 field 必须与验证的字段匹配。
size:value
验证的字段必须具有与给定 value 匹配的大小。对于字符串数据,value 对应于字符数。对于数字数据,value 对应于给定的整数值(属性还必须具有 numeric
或 integer
规则)。对于数组,size 对应于数组的 count
。对于文件,size 对应于文件大小(以千字节为单位)。让我们看一些示例:
// 验证字符串是否恰好为 12 个字符长...
'title' => 'size:12';
// 验证提供的整数是否等于 10...
'seats' => 'integer|size:10';
// 验证数组是否恰好有 5 个元素...
'tags' => 'array|size:5';
// 验证上传的文件是否恰好为 512 千字节...
'image' => 'file|size:512';
startswith:_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),
],
]);
WARNING
您不应将任何用户控制的请求输入传递给 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_date
和 doctor_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
字段时才会对其进行验证。
NOTE
如果您尝试验证一个应该始终存在但可能为空的字段,请查看 关于可选字段的说明。
复杂条件验证
有时您可能希望根据更复杂的条件逻辑添加验证规则。例如,您可能希望仅在另一个字段的值大于 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;
});
NOTE
传递给闭包的 $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',
]);
通常,您应该始终指定允许在数组中存在的数组键。否则,验证器的 validate
和 validated
方法将返回所有验证的数据,包括数组及其所有键,即使这些键未通过其他嵌套数组验证规则验证。
验证嵌套数组输入
验证基于嵌套数组的表单输入字段不必是痛苦的。您可以使用“点”符号验证数组中的属性。例如,如果传入的 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-index
、second-position
、third-index
、third-position
等引用更深层次的嵌套索引和位置。
'photos.*.attributes.*.string' => '照片 #:second-position 的属性无效。',
验证文件
Laravel 提供了多种验证规则,可用于验证上传的文件,例如 mimes
、image
、min
和 max
。虽然您可以在验证文件时单独指定这些规则,但 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)),
],
]);
NOTE
有关验证图像尺寸的更多信息,请参阅 dimension 规则文档。
文件大小
为了方便起见,可以将最小和最大文件大小指定为带有后缀的字符串,以指示文件大小单位。支持的后缀包括 kb
、mb
、gb
和 tb
:
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
WARNING
“隐式”规则仅 暗示 属性是必需的。是否实际使缺失或空的属性无效取决于您。