验证
基本用法
Laravel 提供了一个简单、方便的设施来验证数据并通过 Validator
类检索验证错误信息。
基本验证示例
$validator = Validator::make(
['name' => 'Dayle'],
['name' => 'required|min:5']
);
传递给 make
方法的第一个参数是待验证的数据。第二个参数是应该应用于数据的验证规则。
使用数组指定规则
可以使用“管道”字符或数组的单独元素来分隔多个规则。
$validator = Validator::make(
['name' => 'Dayle'],
['name' => ['required', 'min:5']]
);
验证多个字段
$validator = Validator::make(
[
'name' => 'Dayle',
'password' => 'lamepassword',
'email' => 'email@example.com'
],
[
'name' => 'required',
'password' => 'required|min:8',
'email' => 'required|email|unique:users'
]
);
一旦创建了 Validator
实例,就可以使用 fails
(或 passes
)方法来执行验证。
if ($validator->fails())
{
// 给定的数据未通过验证
}
如果验证失败,您可以从验证器中检索错误信息。
$messages = $validator->messages();
您还可以访问失败的验证规则的数组,而不带消息。为此,请使用 failed
方法:
$failed = $validator->failed();
验证文件
Validator
类提供了几个用于验证文件的规则,例如 size
、mimes
等。在验证文件时,您可以将它们与其他数据一起传递给验证器。
验证后钩子
验证器还允许您附加在验证完成后运行的回调。这使您可以轻松地执行进一步的验证,甚至将更多的错误信息添加到消息集合中。要开始,请在验证器实例上使用 after
方法:
$validator = Validator::make(...);
$validator->after(function($validator)
{
if ($this->somethingElseIsInvalid())
{
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
if ($validator->fails())
{
//
}
您可以根据需要向验证器添加任意数量的 after
回调。
控制器验证
当然,每次进行验证时手动创建和检查 Validator
实例是一件麻烦事。别担心,您还有其他选择!Laravel 附带的 App\Http\Controllers\Controller
基类使用了一个 ValidatesRequests
trait。此 trait 提供了一种方便的方法来验证传入的 HTTP 请求。它看起来像这样:
/**
* 存储传入的博客文章。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$this->validate($request, [
'title' => 'required|unique|max:255',
'body' => 'required',
]);
//
}
如果验证通过,您的代码将正常执行。然而,如果验证失败,将抛出一个 Illuminate\Contracts\Validation\ValidationException
。此异常会自动被捕获,并生成一个重定向到用户的先前位置。验证错误甚至会自动闪存到会话中!
如果传入的请求是 AJAX 请求,则不会生成重定向。相反,将返回一个包含验证错误的 JSON 表示的 HTTP 响应,状态码为 422。
例如,以下是手动编写的等效代码:
/**
* 存储传入的博客文章。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$v = Validator::make($request->all(), [
'title' => 'required|unique|max:255',
'body' => 'required',
]);
if ($v->fails())
{
return redirect()->back()->withErrors($v->errors());
}
//
}
自定义闪存错误格式
如果您希望自定义验证失败时闪存到会话中的验证错误的格式,请在您的基控制器上重写 formatValidationErrors
。不要忘记在文件顶部导入 Illuminate\Validation\Validator
类:
/**
* {@inheritdoc}
*/
protected function formatValidationErrors(Validator $validator)
{
return $validator->errors()->all();
}
表单请求验证
对于更复杂的验证场景,您可能希望创建一个“表单请求”。表单请求是包含验证逻辑的自定义请求类。要创建表单请求类,请使用 make:request
Artisan CLI 命令:
php artisan make:request StoreBlogPostRequest
生成的类将放置在 app/Http/Requests
目录中。让我们在 rules
方法中添加一些验证规则:
/**
* 获取适用于请求的验证规则。
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|unique|max:255',
'body' => 'required',
];
}
那么,验证规则是如何执行的呢?您只需在控制器方法中对请求进行类型提示:
/**
* 存储传入的博客文章。
*
* @param StoreBlogPostRequest $request
* @return Response
*/
public function store(StoreBlogPostRequest $request)
{
// 传入的请求是有效的...
}
传入的表单请求在调用控制器方法之前就已验证,这意味着您不需要在控制器中添加任何验证逻辑。它已经被验证过了!
如果验证失败,将生成一个重定向响应,将用户发送回其先前的位置。错误也会闪存到会话中,以便显示。如果请求是 AJAX 请求,将返回一个状态码为 422 的 HTTP 响应,其中包含验证错误的 JSON 表示。
授权表单请求
表单请求类还包含一个 authorize
方法。在此方法中,您可以检查经过身份验证的用户是否确实有权更新给定资源。例如,如果用户试图更新博客文章评论,他们是否确实拥有该评论?例如:
/**
* 确定用户是否有权发出此请求。
*
* @return bool
*/
public function authorize()
{
$commentId = $this->route('comment');
return Comment::where('id', $commentId)
->where('user_id', Auth::id())->exists();
}
请注意上面示例中的 route
方法调用。此方法允许您访问正在调用的路由上定义的 URI 参数,例如示例中的 {comment}
参数:
Route::post('comment/{comment}');
如果 authorize
方法返回 false
,将自动返回一个状态码为 403 的 HTTP 响应,并且您的控制器方法将不会执行。
如果您计划在应用程序的其他部分进行授权逻辑,只需从 authorize
方法返回 true
:
/**
* 确定用户是否有权发出此请求。
*
* @return bool
*/
public function authorize()
{
return true;
}
自定义闪存错误格式
如果您希望自定义验证失败时闪存到会话中的验证错误的格式,请在您的基请求(App\Http\Requests\Request
)上重写 formatErrors
。不要忘记在文件顶部导入 Illuminate\Validation\Validator
类:
/**
* {@inheritdoc}
*/
protected function formatErrors(Validator $validator)
{
return $validator->errors()->all();
}
处理错误信息
在 Validator
实例上调用 messages
方法后,您将收到一个 MessageBag
实例,该实例具有多种方便的方法来处理错误信息。
检索字段的第一个错误信息
echo $messages->first('email');
检索字段的所有错误信息
foreach ($messages->get('email') as $message)
{
//
}
检索所有字段的所有错误信息
foreach ($messages->all() as $message)
{
//
}
确定字段是否存在消息
if ($messages->has('email'))
{
//
}
以格式检索错误信息
echo $messages->first('email', '<p>:message</p>');
默认情况下,消息使用与 Bootstrap 兼容的语法进行格式化。
以格式检索所有错误信息
foreach ($messages->all('<li>:message</li>') as $message)
{
//
}
错误信息与视图
一旦您执行了验证,您将需要一种简单的方法将错误信息返回到视图中。Laravel 方便地处理了这一点。以下是一个示例路由:
Route::get('register', function()
{
return View::make('user.register');
});
Route::post('register', function()
{
$rules = [...];
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails())
{
return redirect('register')->withErrors($validator);
}
});
请注意,当验证失败时,我们使用 withErrors
方法将 Validator
实例传递给重定向。此方法会将错误信息闪存到会话中,以便在下一个请求中可用。
然而,请注意,我们不必在 GET 路由中显式地将错误信息绑定到视图。这是因为 Laravel 总是会检查会话数据中的错误,并在可用时自动将它们绑定到视图中。因此,重要的是要注意,在每个请求中,您的所有视图中都会始终有一个 $errors
变量可用,这使您可以方便地假设 $errors
变量始终被定义并且可以安全使用。$errors
变量将是 MessageBag
的一个实例。
因此,在重定向之后,您可以在视图中利用自动绑定的 $errors
变量:
<?php echo $errors->first('email'); ?>
命名错误包
如果您在单个页面上有多个表单,您可能希望为错误的 MessageBag
命名。这将允许您检索特定表单的错误信息。只需将名称作为第二个参数传递给 withErrors
:
return redirect('register')->withErrors($validator, 'login');
然后,您可以从 $errors
变量中访问命名的 MessageBag
实例:
<?php echo $errors->login->first('email'); ?>
可用的验证规则
以下是所有可用验证规则及其功能的列表:
- Accepted
- Active URL
- After (Date)
- Alpha
- Alpha Dash
- Alpha Numeric
- Array
- Before (Date)
- Between
- Boolean
- Confirmed
- Date
- Date Format
- Different
- Digits
- Digits Between
- Exists (Database)
- Image (File)
- In
- Integer
- IP Address
- Max
- MIME Types
- Min
- Not In
- Numeric
- Regular Expression
- Required
- Required If
- Required With
- Required With All
- Required Without
- Required Without All
- Same
- Size
- String
- Timezone
- Unique (Database)
- URL
accepted
验证字段必须是 yes、on、1 或 true。这对于验证“服务条款”接受非常有用。
active_url
验证字段必须是一个有效的 URL,根据 checkdnsrr
PHP 函数。
after:date
验证字段必须是给定日期之后的值。日期将传递给 PHP 的 strtotime
函数。
alpha
验证字段必须完全是字母字符。
alpha_dash
验证字段可以包含字母数字字符,以及破折号和下划线。
alpha_num
验证字段必须完全是字母数字字符。
array
验证字段必须是数组类型。
before:date
验证字段必须是给定日期之前的值。日期将传递给 PHP 的 strtotime
函数。
between:min,max
验证字段的大小必须在给定的 min 和 max 之间。字符串、数字和文件的评估方式与 size
规则相同。
boolean
验证字段必须能够被转换为布尔值。接受的输入有 true
、false
、1
、0
、"1"
和 "0"
。
confirmed
验证字段必须有一个匹配的 foo_confirmation
字段。例如,如果验证字段是 password
,则输入中必须存在一个匹配的 password_confirmation
字段。
date
验证字段必须是一个有效日期,根据 PHP 的 strtotime
函数。
date_format:format
验证字段必须与根据 PHP 的 date_parse_from_format
函数定义的 format 匹配。
different:field
给定的 field 必须与验证字段不同。
digits:value
验证字段必须是 numeric,并且必须具有 value 的确切长度。
digits_between:min,max
验证字段的长度必须在给定的 min 和 max 之间。
email
验证字段必须格式化为电子邮件地址。
exists:table,column
验证字段必须存在于给定的数据库表中。
Exists 规则的基本用法
'state' => 'exists:states'
指定自定义列名
'state' => 'exists:states,abbreviation'
您还可以指定更多条件,这些条件将作为“where”子句添加到查询中:
'email' => 'exists:staff,email,account_id,1'
将 NULL
作为“where”子句值传递将添加对 NULL
数据库值的检查:
'email' => 'exists:staff,email,deleted_at,NULL'
image
验证的文件必须是图像(jpeg、png、bmp、gif 或 svg)
in:foo,bar,...
验证字段必须包含在给定的值列表中。
integer
验证字段必须具有整数值。
ip
验证字段必须格式化为 IP 地址。
max:value
验证字段必须小于或等于最大 value。字符串、数字和文件的评估方式与 size
规则相同。
mimes:foo,bar,...
验证的文件必须具有与列出的扩展名对应的 MIME 类型。
MIME 规则的基本用法
'photo' => 'mimes:jpeg,bmp,png'
min:value
验证字段必须具有最小 value。字符串、数字和文件的评估方式与 size
规则相同。
not_in:foo,bar,...
验证字段不得包含在给定的值列表中。
numeric
验证字段必须具有数值。
regex:pattern
验证字段必须与给定的正则表达式匹配。
注意: 使用 regex
模式时,可能需要在数组中指定规则,而不是使用管道分隔符,特别是当正则表达式包含管道字符时。
required
验证字段必须存在于输入数据中。
required_if:field,value,...
如果 field 等于任何 value,则验证字段必须存在。
required_with:foo,bar,...
验证字段必须仅在其他指定字段中的任何一个存在时存在。
required_with_all:foo,bar,...
验证字段必须仅在所有其他指定字段存在时存在。
required_without:foo,bar,...
验证字段必须仅在其他指定字段中的任何一个不存在时存在。
required_without_all:foo,bar,...
验证字段必须仅在所有其他指定字段不存在时存在。
same:field
给定的 field 必须与验证字段匹配。
size:value
验证字段的大小必须与给定的 value 匹配。对于字符串数据,value 对应于字符数。对于数值数据,value 对应于给定的整数值。对于文件,size 对应于文件大小(以千字节为单位)。
string
验证字段必须是字符串类型。
timezone
验证字段必须是根据 PHP 的 timezone_identifiers_list
函数的有效时区标识符。
unique:table,column,except,idColumn
验证字段在给定的数据库表中必须是唯一的。如果未指定 column
选项,将使用字段名称。
有时,您可能需要为验证器进行的数据库查询设置自定义连接。如上所示,将 unique:users
设置为验证规则将使用默认数据库连接查询数据库。要覆盖此设置,请执行以下操作:
$verifier = App::make('validation.presence');
$verifier->setConnection('connectionName');
$validator = Validator::make($input, [
'name' => 'required',
'password' => 'required|min:8',
'email' => 'required|email|unique:users',
]);
$validator->setPresenceVerifier($verifier);
Unique 规则的基本用法
'email' => 'unique:users'
指定自定义列名
'email' => 'unique:users,email_address'
强制 Unique 规则忽略给定 ID
'email' => 'unique:users,email_address,10'
添加额外的 Where 子句
您还可以指定更多条件,这些条件将作为“where”子句添加到查询中:
'email' => 'unique:users,email_address,NULL,id,account_id,1'
在上面的规则中,只有 account_id
为 1
的行才会包含在唯一性检查中。
url
验证字段必须格式化为 URL。
此函数使用 PHP 的 filter_var
方法。
有条件地添加规则
在某些情况下,您可能希望仅在输入数组中存在某个字段时对其运行验证检查。要快速实现此目的,请将 sometimes
规则添加到您的规则列表中:
$v = Validator::make($data, [
'email' => 'sometimes|required|email',
]);
在上面的示例中,只有在 $data
数组中存在 email
字段时才会对其进行验证。
复杂的条件验证
有时,您可能希望仅在另一个字段的值大于 100 时才要求给定字段。或者您可能需要两个字段仅在另一个字段存在时才具有给定值。添加这些验证规则不必是一件痛苦的事情。首先,使用您的 static rules 创建一个 Validator
实例,这些规则永远不会改变:
$v = Validator::make($data, [
'email' => 'required|email',
'games' => 'required|numeric',
]);
假设我们的 Web 应用程序是为游戏收藏家设计的。如果游戏收藏家注册我们的应用程序并且他们拥有超过 100 个游戏,我们希望他们解释为什么他们拥有这么多游戏。例如,也许他们经营一个游戏转售商店,或者他们只是喜欢收藏。要有条件地添加此要求,我们可以在 Validator
实例上使用 sometimes
方法。
$v->sometimes('reason', 'required|max:500', function($input)
{
return $input->games >= 100;
});
传递给 sometimes
方法的第一个参数是我们有条件验证的字段名称。第二个参数是我们要添加的规则。如果传递给第三个参数的 Closure
返回 true
,则将添加规则。此方法使构建复杂的条件验证变得轻而易举。您甚至可以一次为多个字段添加条件验证:
$v->sometimes(['reason', 'cost'], 'required', function($input)
{
return $input->games >= 100;
});
传递给您的 Closure
的 $input
参数将是 Illuminate\Support\Fluent
的一个实例,可以用作对象来访问您的输入和文件。
自定义错误信息
如果需要,您可以使用自定义错误信息进行验证,而不是使用默认信息。有几种方法可以指定自定义消息。
将自定义消息传递给验证器
$messages = [
'required' => 'The :attribute field is required.',
];
$validator = Validator::make($input, $rules, $messages);
注意:
:attribute
占位符将被验证字段的实际名称替换。您还可以在验证消息中使用其他占位符。
其他验证占位符
$messages = [
'same' => 'The :attribute and :other must match.',
'size' => 'The :attribute must be exactly :size.',
'between' => 'The :attribute must be between :min - :max.',
'in' => 'The :attribute must be one of the following types: :values',
];
为给定属性指定自定义消息
有时,您可能希望仅为特定字段指定自定义错误消息:
$messages = [
'email.required' => 'We need to know your e-mail address!',
];
在语言文件中指定自定义消息
在某些情况下,您可能希望在语言文件中指定自定义消息,而不是直接将它们传递给 Validator
。为此,请将您的消息添加到 resources/lang/xx/validation.php
语言文件中的 custom
数组中。
'custom' => [
'email' => [
'required' => 'We need to know your e-mail address!',
],
],
自定义验证规则
注册自定义验证规则
Laravel 提供了多种有用的验证规则;然而,您可能希望指定一些自己的规则。注册自定义验证规则的一种方法是使用 Validator::extend
方法:
Validator::extend('foo', function($attribute, $value, $parameters)
{
return $value == 'foo';
});
自定义验证器闭包接收三个参数:正在验证的 $attribute
的名称、属性的 $value
和传递给规则的 $parameters
数组。
您还可以将类和方法传递给 extend
方法,而不是闭包:
Validator::extend('foo', 'FooValidator@validate');
请注意,您还需要为自定义规则定义错误消息。您可以使用内联自定义消息数组或通过在验证语言文件中添加条目来实现。
扩展验证器类
除了使用闭包回调扩展验证器之外,您还可以扩展验证器类本身。为此,请编写一个扩展 Illuminate\Validation\Validator
的验证器类。您可以通过在类中添加 validate
前缀的方法来添加验证方法:
<?php
class CustomValidator extends \Illuminate\Validation\Validator {
public function validateFoo($attribute, $value, $parameters)
{
return $value == 'foo';
}
}
注册自定义验证器解析器
接下来,您需要注册自定义验证器扩展:
Validator::resolver(function($translator, $data, $rules, $messages)
{
return new CustomValidator($translator, $data, $rules, $messages);
});
在创建自定义验证规则时,您有时需要为错误消息定义自定义占位符替换。您可以通过如上所述创建自定义验证器,并向验证器添加 replaceXXX
函数来实现。
protected function replaceFoo($message, $attribute, $rule, $parameters)
{
return str_replace(':foo', $parameters[0], $message);
}
如果您希望在不扩展 Validator
类的情况下添加自定义消息“替换器”,可以使用 Validator::replacer
方法:
Validator::replacer('rule', function($message, $attribute, $rule, $parameters)
{
//
});