验证
介绍
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 在应用程序的全局中间件堆栈中包含 TrimStrings
和 ConvertEmptyStringsToNull
中间件。因此,如果您不希望验证器将 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": "团队名称必须是字符串。(还有 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 命令:
artisan make:request StorePostRequest
生成的表单请求类将放置在 app/Http/Requests
目录中。如果此目录不存在,当您运行 make:request
命令时将创建它。Laravel 生成的每个表单请求都有两个方法:authorize
和 rules
。
正如您可能猜到的那样,authorize
方法负责确定当前认证的用户是否可以执行请求所代表的操作,而 rules
方法返回应适用于请求数据的验证规则:
/**
* 获取适用于请求的验证规则。
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|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 手动创建验证器实例。facade 上的 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', '此字段有问题!'
);
}
});
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 本地化的更多信息,请查看完整的 本地化文档。
默认情况下,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 命令发布它们。
定义此值后,验证规则将生成以下错误消息:
当支付类型为信用卡时,信用卡号字段是必需的。
可用的验证规则
以下是所有可用验证规则及其功能的列表:
接受如果接受活动 URL在日期之后在日期之后或等于字母字母破折号字母数字数组Ascii保释在日期之前在日期之前或等于之间布尔确认包含当前密码日期日期等于日期格式小数拒绝如果拒绝不同数字数字之间图像文件的尺寸不同不以...开头不以...结尾电子邮件以...结尾枚举排除如果排除除非排除排除与排除无存在(数据库)扩展文件已填充大于大于或等于十六进制颜色图像(文件)在在数组中整数IP 地址JSON小于小于或等于列表小写MAC 地址最大最大数字MIME 类型按文件扩展名的 MIME 类型最小最小数字缺失如果缺失除非缺失缺失与缺失与所有的倍数不在不正则可为空数字存在如果存在除非存在存在与存在与所有禁止如果禁止除非禁止禁止正则表达式必需如果必需如果接受则必需如果拒绝则必需除非必需与必需与所有必需无必需无所有必需必需的数组键相同大小有时以...开头字符串时区唯一(数据库)大写URLULIDUUID
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 的主机名在传递给 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
验证字段必须完全由 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
的值提供。
before_or_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
字段。
您还可以传递自定义确认字段名称。例如,confirmed:repeat_username
将期望字段 repeat_username
与验证字段匹配。
contains:foo,bar,...
验证字段必须是一个数组,包含所有给定的参数值。
current_password
验证字段必须与经过身份验证的用户的密码匹配。您可以使用规则的第一个参数指定一个 身份验证守卫:
'password' => 'current_password:api'
date
验证字段必须是有效的、非相对的日期,依据 strtotime
PHP 函数。
date_equals:date
验证字段必须等于给定日期。日期将传递给 PHP strtotime
函数,以便转换为有效的 DateTime
实例。
date_format:format,...
验证字段必须匹配给定的 formats 之一。您应该使用 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 的确切长度。
digits_between:min,max
整数验证必须具有在给定的 min 和 max 之间的长度。
dimensions
验证的文件必须是满足规则参数所指定的尺寸约束的图像:
'avatar' => 'dimensions:min_width=100,min_height=200'
可用的约束有:min_width、max_width、min_height、max_height、width、height、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'
上面的示例将应用 RFCValidation
和 DNSCheckValidation
验证。以下是您可以应用的验证样式的完整列表:
rfc
:RFCValidation
strict
:NoRFCWarningsValidation
dns
:DNSCheckValidation
spoof
:SpoofCheckValidation
filter
:FilterEmailValidation
filter_unicode
:FilterEmailValidation::unicode()
filter
验证器使用 PHP 的 filter_var
函数,随 Laravel 一起提供,并且是 Laravel 版本 5.8 之前的默认电子邮件验证行为。
dns
和 spoof
验证器需要 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
规则的 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
方法返回的请求数据中排除。
exclude_if: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),
]);
exclude_unless:anotherfield,value
验证字段将从 validate
和 validated
方法返回的请求数据中排除,除非 anotherfield 字段等于任何 value。如果 value 为 null
(exclude_unless:name,null
),则验证字段将被排除,除非比较字段为 null
或比较字段在请求数据中缺失。
exclude_with:anotherfield
如果 anotherfield 字段存在,则验证字段将从 validate
和 validated
方法返回的请求数据中排除。
exclude_without:anotherfield
如果 anotherfield 字段不存在,则验证字段将从 validate
和 validated
方法返回的请求数据中排除。
exists:table,column
验证字段必须存在于给定的数据库表中。
Exists 规则的基本用法
'state' => 'exists:states'
如果未指定 column
选项,则字段名称将被使用。因此,在这种情况下,规则将验证 states
数据库表中是否包含与请求的 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) {
$query->where('account_id', 1);
}),
],
]);
您可以通过将列名作为第二个参数传递给 Rule::exists
方法,显式指定应使用的验证规则生成的 exists
规则的数据库列名:
'state' => Rule::exists('states', 'abbreviation'),
extensions:foo,bar,...
验证的文件必须具有与列出的扩展名相对应的用户分配扩展名:
'photo' => ['required', 'extensions:jpg,png'],
您不应仅依赖用户分配的扩展名来验证文件。此规则通常应始终与 mimes
或 mimetypes
规则结合使用。
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']),
]);
in_array:anotherfield.*
验证字段必须存在于 anotherfield 的值中。
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 类型及其对应扩展名的完整列表,请参见以下位置:
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
验证字段必须是 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
方法。此方法接受布尔值或闭包。当给定闭包时,闭包应返回 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),
]);
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
方法。此方法接受布尔值或闭包。当传递闭包时,闭包应返回 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),
]);
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 必须在请求数据中存在,除非 value 为 null
。如果 value 为 null
(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 对应于给定的整数值(属性还必须具有 numeric
或 integer
规则)。对于数组,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,例如自增 ID 或 Eloquent 模型实例的 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 9562(版本 1、3、4 、5、6、7 或 8)通用唯一标识符(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
规则添加到规则列表中:
$validator = Validator::make($data, [
'email' => 'sometimes|required|email',
]);
在上面的示例中,只有在 $data
数组中存在 email
字段时,才会对其进行验证。
如果您尝试验证一个应该始终存在但可能为空的字段,请查看 关于可选字段的说明。
复杂条件验证
有时,您可能希望根据更复杂的条件逻辑添加验证规则。例如,您可能希望仅在另一个字段的值大于 100 时才要求给定字段。或者,您可能需要两个字段在另一个字段存在时具有给定值。添加这些验证规则并不麻烦。首先,使用您的 static rules 创建一个 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',
]);
通常,您应该始终指定允许在数组中存在的数组键。否则,验证器的 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' => '我海滩度假的照片!',
],
[
'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)),
],
]);
有关验证图像尺寸的更多信息,请参见 尺寸规则文档。
文件大小
为了方便起见,可以将最小和最大文件大小指定为带有后缀的字符串,指示文件大小单位。支持 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-匿名性 模型来确定密码是否通过 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
目录中。如果该目录不存在,Laravel 在您执行 Artisan 命令以创建规则时会创建它:
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],
]);
翻译验证消息
您可以选择提供一个翻译字符串键,而不是向 $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
要使自定义规则即使在属性为空时也能运行,规则必须暗示该属性是必需的。要快速生成一个新的隐式规则对象,您可以使用 make:rule
Artisan 命令,并使用 --implicit
选项:
artisan make:rule Uppercase --implicit
“隐式”规则仅 暗示 属性是必需的。它是否实际使缺失或空属性无效取决于您。