# Laravel 的表單驗證機制詳解
- [簡介](#introduction)
- [快速上手](#validation-quickstart)
- [定義路由](#quick-defining-the-routes)
- [創建控制器](#quick-creating-the-controller)
- [編寫驗證邏輯](#quick-writing-the-validation-logic)
- [顯示驗證錯誤](#quick-displaying-the-validation-errors)
- [有關可選字段的注意事項](#a-note-on-optional-fields)
- [表單請求驗證](#form-request-validation)
- [創建表單請求](#creating-form-requests)
- [授權表單請求](#authorizing-form-requests)
- [自定義錯誤消息](#customizing-the-error-messages)
- [手動創建表單驗證](#manually-creating-validators)
- [自動重定向](#automatic-redirection)
- [命名錯誤包](#named-error-bags)
- [驗證后鉤子](#after-validation-hook)
- [處理錯誤消息](#working-with-error-messages)
- [自定義錯誤消息](#custom-error-messages)
- [可用的驗證規則](#available-validation-rules)
- [按條件增加規則](#conditionally-adding-rules)
- [驗證數組](#validating-arrays)
- [自定義驗證規則](#custom-validation-rules)
- [使用規則對象](#using-rule-objects)
- [使用擴展](#using-extensions)
<a name="introduction"></a>
## Introduction
Laravel 提供了多種不同的驗證方法來對應用程序傳入的數據進行驗證。默認情況下,Laravel 的基類控制器使用 `ValidatesRequests` Trait,它提供了方便的方法使用各種強大的驗證規則來驗證傳入的 HTTP 請求數據。
<a name="validation-quickstart"></a>
## 快速上手
為了了解 Laravel 強大驗證特性,我們先來看看一個完整的表單驗證并返回錯誤消息的示例。
<a name="quick-defining-the-routes"></a>
### 定義路由
首先,我們假定在 `routes/web.php` 文件中定義了以下路由:
Route::get('post/create', 'PostController@create');
Route::post('post', 'PostController@store');
`GET` 路由會顯示一個用于創建新博客文章的表單,`POST` 路由則會將新的博客文章保存到數據庫。
<a name="quick-creating-the-controller"></a>
### 創建控制器
下一步,我們來看一個處理這些路由的簡單的控制器。我們將 `store` 方法置空:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* 顯示創建博客文章的表單。
*
* @return Response
*/
public function create()
{
return view('post.create');
}
/**
* 保存一個新的博客文章。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
// 驗證以及保存博客發表文章...
}
}
<a name="quick-writing-the-validation-logic"></a>
### 編寫驗證邏輯
現在我們準備開始編寫 `store` 邏輯方法來驗證我們博客發布的新文章。我們將使用 `Illuminate\Http\Request` 對象提供的 `validate` 方法 。如果驗證通過,你的代碼就可以正常的運行。若驗證失敗,則會拋出異常錯誤消息并自動將一個對應的錯誤響應返回給用戶。在一般的 HTTP 請求下,都會生成一個重定向響應,而對于 AJAX 請求則會發送 JSON 響應。
讓我們接著回到 `store` 方法來深入理解 `validate` 方法:
/**
* 保存一篇新的博客文章。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// 文章內容是符合規則的,存入數據庫
}
如你所見,我們將所需的驗證規則傳遞至 `validate` 方法中。另外再提醒一次,如果驗證失敗,將會自動生成一個對應的響應。如果驗證通過,那我們的控制器將會繼續正常運行。
#### 在第一次驗證失敗后停止
有時,你希望在某個屬性第一次驗證失敗后停止運行驗證規則。為了達到這個目的,附加 `bail` 規則到該屬性:
$this->validate($request, [
'title' => 'bail|required|unique:posts|max:255',
'body' => 'required',
]);
在這個例子里,如果 `title` 字段沒有通過 `required` 的驗證規則,那么 `unique` 這個規則將不會被檢測了。將按規則被分配的順序來驗證規則。
#### 嵌套屬性的注解
如果你的 HTTP 請求包含一個 「嵌套的」 參數,你可以在驗證規則中通過 「點」 語法來指定這些參數。
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);
<a name="quick-displaying-the-validation-errors"></a>
### 顯示驗證錯誤
如果本次請求的參數未通過我們指定的驗證規則呢?正如前面所提到的,Laravel 會自動把用戶重定向到先前的位置。另外,所有的驗證錯誤會被自動 [閃存至 session](/docs/{{version}}/session#flash-data)。
再者,請注意在 `GET` 路由中,我們無需顯式的將錯誤信息和視圖綁定起來。這是因為 Lavarel 會檢查在 Session 數據中的錯誤信息,然后如果錯誤信息存在的話,則自動將它們與視圖綁定起來。變量 `$errors` 會成為 `Illuminate\Support\MessageBag` 的一個實例對象。要獲取關于這個對象的更多信息,請[查閱這個文檔](#working-with-error-messages)。
> {tip} `$errors` 變量被 `Illuminate\View\Middleware\ShareErrorsFromSession` 中間件綁定到視圖,該中間件由 `web` 中間件組提供。**當這個中間件被應用后,在你的視圖中就可以獲取到 `$error` 變量**,可以使你方便的假定 `$errors` 變量總是已經被定義好并且可以安全的使用。
所以,在我們的例子中,當驗證失敗的時候,用戶將會被重定向到 `create` 方法,讓我們在視圖中顯示錯誤信息:
<!-- /resources/views/post/create.blade.php -->
<h1>創建文章</h1>
@if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- 創建文章表單 -->
<a name="a-note-on-optional-fields"></a>
### 有關可選字段的注意事項
默認情況下,Laravel 會在你的應用中的全局中間件棧中包含 `TrimStrings` 和 `ConvertEmptyStringsToNull` 中間件。這些中間件在 `App\Http\Kernel` 類中。因此,如果您不希望驗證程序將「null」值視為無效的,您通常需要將「可選」的請求字段標記為 `nullable`。
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
在這個例子里,我們指定 `publish_at` 字段可以為 `null` 或者一個有效的日期格式。如果 `nullable` 的修飾詞沒有添加到規則定義中,驗證器會認為 `null` 是一個無效的日期格式。
<a name="quick-ajax-requests-and-validation"></a>
#### AJAX 請求驗證
在這個例子中,我們使用一種傳統的方式來將數據發送到應用程序上,然而很多程序使用AJAX發送請求。當我們在 AJAX 的請求中使用 `validate` 方法時,Laravel 并不會生成一個重定向響應,而是會生成一個包含所有錯誤驗證的 JSON 響應。這個 JSON 響應會包含一個 422 HTTP 狀態碼被發送出去。
<a name="form-request-validation"></a>
## 表單請求驗證
<a name="creating-form-requests"></a>
### 創建表單請求
在更復雜的驗證情境中,你可能會想要創建一個「表單請求( form request )」。表單請求是一個自定義的請求類,里面包含著驗證邏輯。要創建一個表單請求類,可使用 Artisan 命令行命令 `make:request` :
php artisan make:request StoreBlogPost
新生成的類保存在 `app/Http/Requests` 目錄下。如果這個目錄不存在,那么將會在你運行 `make:request` 命令時創建出來。讓我們添加一些驗證規則到 `rules` 方法中:
/**
* 獲取適用于請求的驗證規則。
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
驗證規則是如何運行的呢?你所需要做的就是在控制器方法中利用類型提示傳入請求。傳入的請求會在控制器方法被調用前進行驗證,意思就是說你不會因為驗證邏輯而把控制器弄得一團糟:
/**
* 保存傳入的博客文章。
*
* @param StoreBlogPost $request
* @return Response
*/
public function store(StoreBlogPost $request)
{
// The incoming request is valid...
}
如果驗證失敗,就會生成一個重定向響應把用戶返回到先前的位置。這些錯誤會被閃存到 Session,所以這些錯誤都可以顯示出來。如果進來的是 AJAX 請求的話,則會傳回一個 HTTP 響應,其中包含了 422 狀態碼和驗證錯誤的 JSON 數據。
#### 添加表單請求后鉤子
如果你想在表單請求「之后」添加鉤子,你可以使用 `withValidator` 方法。這個方法接收一個完整的驗證類,允許你在實際判斷驗證規則調之前調用驗證類的所有方法:
/**
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
}
<a name="authorizing-form-requests"></a>
### 授權表單請求
表單的請求類內包含了 `authorize` 方法。在這個方法中,你可以確認用戶是否真的通過了授權,以便更新指定數據。比方說,你可以判斷,當一個用戶試圖去更新一篇文章的評論時,他是否具備對應的權限:
/**
* 判斷用戶是否有權限做出此請求。
*
* @return bool
*/
public function authorize()
{
$comment = Comment::find($this->route('comment'));
return $comment && $this->user()->can('update', $comment);
}
由于所有的表單請求都是擴展于基礎的 Laravel 中的 request 類,所以我們可以使用 `user` 方法去獲取當前認證登錄的用戶。同時請注意上述例子中對 `route` 方法的調用。這個方法授權你獲取調用的路由規則中的 URI 參數,譬如下面例子中的`{comment}`參數:
Route::post('comment/{comment}');
如果 `authorize` 方法返回 `false`,則會自動返回一個 HTTP 響應,其中包含 403 狀態碼,而你的控制器方法也將不會被運行。
如果你打算在應用程序的其它部分處理授權邏輯,只需從 `authorize` 方法返回 `true` :
/**
* 判斷用戶是否有權限做出此請求。
*
* @return bool
*/
public function authorize()
{
return true;
}
<a name="customizing-the-error-messages"></a>
### 自定義錯誤消息
你可以通過重寫表單請求的 `messages` 方法來自定義錯誤消息。此方法必須返回一個數組,其中含有成對的屬性或規則以及對應的錯誤消息:
/**
* 獲取已定義驗證規則的錯誤消息。
*
* @return array
*/
public function messages()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
<a name="manually-creating-validators"></a>
## 手動創建驗證請求
如果你不想要使用 request 對象中的 `validate` 方法,你可以手動通過`validator` [Facade](/docs/{{version}}/facades) 創建一個 validator 實例。Facade 中的 `make` 方法生成一個新的 `validator` 實例:
<?php
namespace App\Http\Controllers;
use Validator;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* 保存一篇新的博客文章。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
return redirect('post/create')
->withErrors($validator)
->withInput();
}
// 保存文章
}
}
第一個傳給 `make` 方法的參數是驗證數據。第二個參數則是數據的驗證規則。
如果請求沒有通過驗證,則可以使用 `withErrors` 方法把錯誤消息閃存到 Session。在進行重定向之后,`$errors` 變量可以在視圖中自動共用,讓你可以輕松地顯示這些消息并返回給用戶。`withErrors` 方法接收 validator、`MessageBag`,或 PHP `array`。
<a name="automatic-redirection"></a>
### 自動重定向
如果你想手動創建一個驗證器實例,但希望繼續享用 request 對象中 `validates` 方法提供的自動跳轉功能,那么你可以調用一個現存的驗證器實例中的 `validate` 方法。如果驗證失敗了,用戶會被自動重定向,或者在 AJAX 請求中,一個 JSON 格式的響應將會被返回:
Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
])->validate();
<a name="named-error-bags"></a>
### 命名錯誤包
如果你在一個頁面中有多個表單,你也許會希望命名錯誤信息包 `MessageBag` ,錯誤信息包允許你從指定的表單中接收錯誤信息。簡單的給 `withErrors` 方法傳遞第二個參數作為一個名字:
return redirect('register')
->withErrors($validator, 'login');
然后你能從 `$errors` 變量中獲取到 `MessageBag` 實例:
{{ $errors->login->first('email') }}
<a name="after-validation-hook"></a>
### 驗證后鉤子
驗證器允許你在驗證完成之后附加回調函數。這使得你可以容易的執行進一步驗證,甚至可以在消息集合中添加更多的錯誤信息。使用它只需在驗證實例中使用 `after` 方法:
$validator = Validator::make(...);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
if ($validator->fails()) {
//
}
<a name="working-with-error-messages"></a>
## 處理錯誤消息
調用 `Validator` 實例的 `errors` 方法,會得到一個 `Illuminate\Support\MessageBag` 的實例,里面有許多可讓你操作錯誤消息的便利方法。`$errors` 變量可以自動的被所有的視圖獲取,并且它是一個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')) {
//
}
<a name="custom-error-messages"></a>
### 自定義錯誤消息
如果有需要的話,你也可以自定義錯誤的驗證消息來取代默認的驗證消息。有幾種方法可以指定自定義消息。首先,你需要先通過傳遞三個參數到 `Validator::make` 方法來自定義驗證消息:
$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!',
];
<a name="localization"></a>
#### 在語言文件中指定自定義的消息提示
多數情況下,你會在語言文件中指定自定義的消息提示,而不是將定制的消息傳遞給 `Validator` 。實現它需要在語言文件 `resources/lang/xx/validation.php` 中,將定制的消息添加到 `custom` 數組。
'custom' => [
'email' => [
'required' => 'We need to know your e-mail address!',
],
],
#### 在語言文件中自定義屬性
如果希望將驗證消息的`:attribute` 部分替換為自定義屬性名稱,則可以在 `resources/lang/xx/validation.php` 語言文件的 `attributes` 數組中指定自定義名稱:
'attributes' => [
'email' => 'email address',
],
<a name="available-validation-rules"></a>
## 可用的驗證規則
以下是所有可用的驗證規則清單與功能:
<style>
.collection-method-list > p {
column-count: 3; -moz-column-count: 3; -webkit-column-count: 3;
column-gap: 2em; -moz-column-gap: 2em; -webkit-column-gap: 2em;
}
.collection-method-list a {
display: block;
}
</style>
<div class="collection-method-list" markdown="1">
[Accepted](#rule-accepted)
[Active URL](#rule-active-url)
[After (Date)](#rule-after)
[After Or Equal (Date)](#rule-after-or-equal)
[Alpha](#rule-alpha)
[Alpha Dash](#rule-alpha-dash)
[Alpha Numeric](#rule-alpha-num)
[Array](#rule-array)
[Before (Date)](#rule-before)
[Before Or Equal (Date)](#rule-before-or-equal)
[Between](#rule-between)
[Boolean](#rule-boolean)
[Confirmed](#rule-confirmed)
[Date](#rule-date)
[Date Format](#rule-date-format)
[Different](#rule-different)
[Digits](#rule-digits)
[Digits Between](#rule-digits-between)
[Dimensions (Image Files)](#rule-dimensions)
[Distinct](#rule-distinct)
[E-Mail](#rule-email)
[Exists (Database)](#rule-exists)
[File](#rule-file)
[Filled](#rule-filled)
[Image (File)](#rule-image)
[In](#rule-in)
[In Array](#rule-in-array)
[Integer](#rule-integer)
[IP Address](#rule-ip)
[JSON](#rule-json)
[Max](#rule-max)
[MIME Types](#rule-mimetypes)
[MIME Type By File Extension](#rule-mimes)
[Min](#rule-min)
[Nullable](#rule-nullable)
[Not In](#rule-not-in)
[Numeric](#rule-numeric)
[Present](#rule-present)
[Regular Expression](#rule-regex)
[Required](#rule-required)
[Required If](#rule-required-if)
[Required Unless](#rule-required-unless)
[Required With](#rule-required-with)
[Required With All](#rule-required-with-all)
[Required Without](#rule-required-without)
[Required Without All](#rule-required-without-all)
[Same](#rule-same)
[Size](#rule-size)
[String](#rule-string)
[Timezone](#rule-timezone)
[Unique (Database)](#rule-unique)
[URL](#rule-url)
</div>
<a name="rule-accepted"></a>
#### accepted
驗證字段值是否為 _yes_、 _on_、 _1_、或 _true_。這在確認「服務條款」是否同意時相當有用。
<a name="rule-active-url"></a>
#### active_url
根據 PHP 函數 `dns_get_record`,判斷要驗證的字段必須具有有效的 A 或 AAAA 記錄。
<a name="rule-after"></a>
#### after:_date_
驗證字段是否是在指定日期之后。這個日期將會通過 `strtotime` 函數來驗證。
'start_date' => 'required|date|after:tomorrow'
作為替換 `strtotime` 傳遞的日期字符串,你可以指定其它的字段來比較日期:
'finish_date' => 'required|date|after:start_date'
<a name="rule-after-or-equal"></a>
#### after\_or\_equal:_date_
驗證字段必需是等于指定日期或在指定日期之后。更多信息請參見 [after](#rule-after) 規則。
<a name="rule-alpha"></a>
#### alpha
驗證字段值是否僅包含字母字符。
<a name="rule-alpha-dash"></a>
#### alpha_dash
驗證字段值是否僅包含字母、數字、破折號( - )以及下劃線( _ )。
<a name="rule-alpha-num"></a>
#### alpha_num
驗證字段值是否僅包含字母、數字。
<a name="rule-array"></a>
#### array
驗證字段必須是一個 PHP 數組。
<a name="rule-before"></a>
#### before:_date_
驗證字段是否是在指定日期之前。這個日期將會通過 `strtotime` 函數來驗證。
<a name="rule-before-or-equal"></a>
#### before\_or\_equal:_date_
驗證字段是否是在指定日期之前。這個日期將會使用 PHP `strtotime` 函數來驗證。
<a name="rule-between"></a>
#### between:_min_,_max_
驗證字段值的大小是否介于指定的 _min_ 和 _max_ 之間。字符串、數字、數組或是文件大小的計算方式和 [`size`](#rule-size) 規則相同。
<a name="rule-boolean"></a>
#### boolean
驗證字段值是否能夠轉換為布爾值。可接受的參數為 `true`、`false`、`1`、`0`、`"1"` 以及 `"0"`。
<a name="rule-confirmed"></a>
#### confirmed
驗證字段值必須和 `foo_confirmation` 的字段值一致。例如,如果要驗證的字段是 `password`,就必須和輸入數據里的 `password_confirmation` 的值保持一致。
<a name="rule-date"></a>
#### date
驗證字段值是否為有效日期,會根據 PHP 的 `strtotime` 函數來做驗證。
<a name="rule-date-format"></a>
#### date_format:_format_
驗證字段值符合指定的日期格式 (_format_)。你應該只使用 `date` 或 `date_format` 當中的 **其中一個** 用于驗證,而不應該同時使用兩者。
<a name="rule-different"></a>
#### different:_field_
驗證字段值是否和指定的字段 (_field_) 有所不同。
<a name="rule-digits"></a>
#### digits:_value_
驗證字段值是否為 _numeric_ 且長度為 _value_。
<a name="rule-digits-between"></a>
#### digits_between:_min_,_max_
驗證字段值的長度是否在 _min_ 和 _max_ 之間。
<a name="rule-dimensions"></a>
#### 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\Validation\Rule;
Validator::make($data, [
'avatar' => [
'required',
Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2),
],
]);
<a name="rule-distinct"></a>
#### distinct
當你在驗證數組的時候,你可以指定某個值必須是唯一的:
'foo.*.id' => 'distinct'
<a name="rule-email"></a>
#### email
驗證字段值是否符合 e-mail 格式。
<a name="rule-exists"></a>
#### exists:_table_,_column_
驗證字段值是否存在指定的數據表中。
#### Exists 規則的基本使用方法
'state' => 'exists:states'
#### 指定一個特定的字段名稱
'state' => 'exists:states,abbreviation'
有時,您可能需要指定要用于 `exists` 查詢的特定數據庫連接。你可以使用點「.」語法將數據庫連接名稱添加到數據表前面來實現這個目的:
'email' => 'exists:connection.staff,email'
如果您想自定義由驗證規則執行的查詢,您可以使用 `Rule` 類流暢地定義規則。在這個例子中,我們還將使用數組指定驗證規則,而不是使用 `|` 字符來分隔它們:
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::exists('staff')->where(function ($query) {
$query->where('account_id', 1);
}),
],
]);
<a name="rule-file"></a>
#### file
必須是成功上傳的文件。
<a name="rule-filled"></a>
#### filled
驗證的字段必須帶有內容。
<a name="rule-image"></a>
#### image
驗證字段文件必須為圖片格式( jpeg、png、bmp、gif、或 svg )。
<a name="rule-in"></a>
#### in:_foo_,_bar_,...
驗證字段值是否有在指定的列表里面。因為這個規則通常需要你 `implode` 一個數組,`Rule::in` 方法可以用來流利地構造規則:
use Illuminate\Validation\Rule;
Validator::make($data, [
'zones' => [
'required',
Rule::in(['first-zone', 'second-zone']),
],
]);
<a name="rule-in-array"></a>
#### in_array:_anotherfield_
驗證的字段必須存在于 _anotherfield_ 的值中。
<a name="rule-integer"></a>
#### integer
驗證字段值是否是整數。
<a name="rule-ip"></a>
#### ip
驗證字段值是否符合 IP address 的格式。
#### ipv4
驗證字段值是否符合 IPv4 的格式。
#### ipv6
驗證字段值是否符合 IPv6 的格式。
<a name="rule-json"></a>
#### json
驗證字段是否是一個有效的 JSON 字符串。
<a name="rule-max"></a>
#### max:_value_
字段值必須小于或等于 _value_。字符串、數字、數組或是文件大小的計算方式和 [`size`](#rule-size) 規則相同。
<a name="rule-mimetypes"></a>
#### mimetypes:_text/plain_,...
驗證的文件必須是這些 MIME 類型中的一個:
'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime'
要確定上傳文件的MIME類型,會讀取文件的內容,并且框架將嘗試猜測 MIME 類型,這可能與客戶端提供的 MIME 類型不同。
<a name="rule-mimes"></a>
#### mimes:_foo_,_bar_,...
驗證字段文件的 MIME 類型是否符合列表中指定的格式。
#### MIME 規則基本用法
'photo' => 'mimes:jpeg,bmp,png'
即使你可能只需要驗證指定擴展名,但此規則實際上會驗證文件的 MIME 類型,其通過讀取文件的內容以猜測它的 MIME 類型。
完整的 MIME 類型及對應的擴展名列表可以在下方鏈接找到:[https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types](https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types)
<a name="rule-min"></a>
#### min:_value_
字段值必須大于或等于 _value_。字符串、數字、數組或是文件大小的計算方式和 [`size`](#rule-size) 規則相同。
<a name="rule-nullable"></a>
#### nullable
驗證的字段可以為 `null`。這在驗證基本數據類型,如字符串和整型這些能包含 `null` 值的數據類型中特別有用。
<a name="rule-not-in"></a>
#### not_in:_foo_,_bar_,...
驗證字段值必須不在給定的值列表中出現。`Rule::notIn`方法在構建規則的時候也許有用:
use Illuminate\Validation\Rule;
Validator::make($data, [
'toppings' => [
'required',
Rule::notIn(['sprinkles', 'cherries']),
],
]);
<a name="rule-numeric"></a>
#### numeric
驗證字段值是否為數字。
<a name="rule-present"></a>
#### present
驗證的字段必須出現,但數據可以為空。
<a name="rule-regex"></a>
#### regex:_pattern_
驗證字段值是否符合指定的正則表達式。
**Note:** 當使用 `regex` 規則時,你必須使用數組,而不是使用管道分隔符,特別是當正則表達式含有管道符號時。
<a name="rule-required"></a>
#### required
驗證字段必須存在輸入數據,且不為空。字段符合下方任一條件時即為「空」:
<div class="content-list" markdown="1">
- 該值為 `null`.
- 該值為空字符串。
- 該值為空數組或空的 `可數` 對象。
- 該值為沒有路徑的上傳文件。
</div>
<a name="rule-required-if"></a>
#### required_if:_anotherfield_,_value_,...
如果指定的其它字段( _anotherfield_ )等于任何一個 _value_ 時,此字段為必填。
<a name="rule-required-unless"></a>
#### required_unless:_anotherfield_,_value_,...
如果指定的其它字段( _anotherfield_ )等于任何一個 _value_ 時,此字段為不必填。
<a name="rule-required-with"></a>
#### required_with:_foo_,_bar_,...
如果指定的字段中的 _任意一個_ 有值且不為空,則此字段為必填。
<a name="rule-required-with-all"></a>
#### required_with_all:_foo_,_bar_,...
如果指定的 _所有_ 字段都有值,則此字段為必填。
<a name="rule-required-without"></a>
#### required_without:_foo_,_bar_,...
如果缺少 _任意一個_ 指定的字段,則此字段為必填。
<a name="rule-required-without-all"></a>
#### required_without_all:_foo_,_bar_,...
如果所有指定的字段 _都沒有_ 值,則此字段為必填。
<a name="rule-same"></a>
#### same:_field_
驗證字段值和指定的 字段( _field_ ) 值是否相同。
<a name="rule-size"></a>
#### size:_value_
驗證字段值的大小是否符合指定的 _value_ 值。對于字符串來說,_value_ 為字符數。對于數字來說,_value_ 為某個整數值。對于數組來說, _size_ 對應的是數組的 `count` 函數值。對文件來說,_size_ 對應的是文件大小(單位 kb )。
<a name="rule-string"></a>
#### string
驗證字段值的類型是否為字符串。如果你允許字段的值為 `null` ,那么你應該將 `nullable` 規則附加到字段中。
<a name="rule-timezone"></a>
#### timezone
驗證字段值是否是有效的時區,會根據 PHP 的 `timezone_identifiers_list` 函數來判斷。
<a name="rule-unique"></a>
#### unique:_table_,_column_,_except_,_idColumn_
在指定的數據表中,驗證字段必須是唯一的。如果沒有指定 `column`,將會使用字段本身的名稱。
**指定一個特定的字段名稱:**
'email' => 'unique:users,email_address'
**自定義數據庫連接**
有時,您可能需要為驗證程序所做的數據庫查詢設置自定義連接。如上面所示,如上所示,將 `unique:users` 設置為驗證規則將使用默認數據庫連接來查詢數據庫。如果要修改數據庫連接,請使用「點」語法指定連接和表名:
'email' => 'unique:connection.users,email_address'
**強迫 Unique 規則忽略指定 ID:**
有時候,你希望在進行字段唯一性驗證時對指定 ID 進行忽略。例如,在「更新個人資料」頁面會包含用戶名、郵箱和地點。這時你會想要驗證更新的 E-mail 值是否為唯一的。如果用戶僅更改了用戶名字段而沒有改 E-mail 字段,就不需要拋出驗證錯誤,因為此用戶已經是這個 E-mail 的擁有者了。
為了指示驗證器忽略用戶的ID,我們將使用 `Rule` 類流暢地定義規則。 在這個例子中,我們還將通過數組來指定驗證規則,而不是使用 `|` 字符來分隔:
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
]);
如果你的數據表使用的主鍵名稱不是 `id`,則可以在調用 `ignore` 方法時指定列的名稱:
'email' => Rule::unique('users')->ignore($user->id, 'user_id')
**增加額外的 Where 語句:**
你也可以通過 `where` 方法指定額外的查詢約束條件。例如,我們添加 `account_id` 為 `1` 約束條件:
'email' => Rule::unique('users')->where(function ($query) {
$query->where('account_id', 1);
})
<a name="rule-url"></a>
#### url
驗證字段必需是有效的 URL 格式。
<a name="conditionally-adding-rules"></a>
## 按條件增加規則
#### 當字段存在的時候進行驗證
在某些情況下,你可能 **只想** 在輸入數據中有此字段時才進行驗證。可通過增加 `sometimes` 規則到規則列表來實現:
$v = Validator::make($data, [
'email' => 'sometimes|required|email',
]);
在上面的例子中,`email` 字段的驗證只會在 `$data` 數組有此字段時才會進行。
> {tip} 如果你嘗試驗證一個總是存在但是可能為空的字段,請查閱 [可選字段的說明](#a-note-on-optional-fields)。
#### 復雜的條件驗證
有時候你可能希望增加更復雜的驗證條件,例如,你可以希望某個指定字段在另一個字段的值超過 100 時才為必填。或者當某個指定字段有值時,另外兩個字段要擁有符合的特定值。增加這樣的驗證條件并不難。首先,利用你熟悉的 _static rules_ 來創建一個 `Validator` 實例:
$v = Validator::make($data, [
'email' => 'required|email',
'games' => 'required|numeric',
]);
假設我們有一個專為游戲收藏家所設計的網頁應用程序。如果游戲收藏家收藏超過一百款游戲,我們會希望他們來說明下為什么他們會擁有這么多游戲。比如說他們有可能經營了一家游戲分銷商店,或者只是為了享受收集的樂趣。為了在特定條件下加入此驗證需求,可以在 `Validator` 實例中使用 `sometimes` 方法。
$v->sometimes('reason', 'required|max:500', function ($input) {
return $input->games >= 100;
});
傳入 `sometimes` 方法的第一個參數是我們要用條件認證的字段名稱。第二個參數是我們想使用的驗證規則。`閉包` 作為第三個參數傳入,如果其返回 `true`,則額外的規則就會被加入。這個方法可以輕松的創建復雜的條件式驗證。你甚至可以一次對多個字段增加條件式驗證:
$v->sometimes(['reason', 'cost'], 'required', function ($input) {
return $input->games >= 100;
});
> {tip} 傳入 `閉包` 的 `$input` 參數是 `Illuminate\Support\Fluent` 實例,可用來訪問你的輸入或文件對象。
<a name="validating-arrays"></a>
## 驗證數組
驗證基于數組的表單輸入字段并不一定是一件痛苦的事情。你可以使用「.」來驗證一個數組中的屬性。例如,如果 HTTP 請求中包含一個 `photos[profile]` 字段,你可以使用下面的方法:
$validator = Validator::make($request->all(), [
'photos.profile' => 'required|image',
]);
你也可以驗證數組中的每一個元素。要驗證指定數組輸入字段中的每一個 email 是否唯一,可以這么做:
$validator = Validator::make($request->all(), [
'person.*.email' => 'email|unique:users',
'person.*.first_name' => 'required_with:person.*.last_name',
]);
同理,你在語言文件定義驗證信息的時候可以使用星號 `*` 字符,可以更加容易的在基于數組格式的字段中使用相同的驗證信息:
'custom' => [
'person.*.email' => [
'unique' => 'Each person must have a unique e-mail address',
]
],
<a name="custom-validation-rules"></a>
## 自定義驗證規則
<a name="using-rule-objects"></a>
### 使用規則對象
Laravel 提供了許多有用的驗證規則。但你可能想自定義一些規則。注冊自定義驗證規則的方法之一,就是使用規則對象。要生成一個新的規則對象,可以使用 `make:rule` Artisan 命令。接下來,我們使用這個命令來生成一個驗證字符串是否是大寫的驗證對象。Laravel 會將新的規則對象存放在 `app/Rules` 目錄:
php artisan make:rule Uppercase
一旦規則對象生成了,我們就可以定義它的行為。一個規則對象包含兩個方法: `passes` 和 `message` 。 `passes`方法接收屬性值和名稱,以及根據屬性值是否符合規則而返回 `true` 或者 `false` 。 `message` 方法返回驗證不通過時應該使用的錯誤信息。
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class Uppercase implements Rule
{
/**
* 判斷驗證規則是否通過。
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
return strtoupper($value) === $value;
}
/**
* 獲取驗證錯誤信息。
*
* @return string
*/
public function message()
{
return 'The :attribute must be uppercase.';
}
}
當然,如果你希望從翻譯文件中返回驗證錯誤信息,你可以從 `message` 方法中調用 `trans` 輔助函數。
/**
* 獲取驗證錯誤信息。
*
* @return string
*/
public function message()
{
return trans('validation.uppercase');
}
一旦規則對象被定義好后,你可以通過傳遞一個規則實例的方式,將其和其他驗證規則附加到一個驗證器:
use App\Rules\Uppercase;
$request->validate([
'name' => ['required', new Uppercase],
]);
<a name="using-extensions"></a>
### 使用擴展
另外一個注冊自定義驗證規則的方法,就是使用 `Validator` [Facade](/docs/{{version}}/facades) 中的 `extend` 方法。讓我們在 [服務提供者](/docs/{{version}}/providers) 中使用這個方法來注冊自定義的驗證規則:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;
class AppServiceProvider extends ServiceProvider
{
/**
* 啟動任意應用程序服務。
*
* @return void
*/
public function boot()
{
Validator::extend('foo', function ($attribute, $value, $parameters, $validator) {
return $value == 'foo';
});
}
/**
* 注冊服務容器。
*
* @return void
*/
public function register()
{
//
}
}
自定義的驗證閉包接收四個參數:要被驗證的屬性名稱 `$attribute`,屬性的值 `$value`,傳入驗證規則的參數數組 `$parameters`,及 `Validator` 實例。
除了使用閉包,你也可以傳入類和方法到 `extend` 方法中:
Validator::extend('foo', 'FooValidator@validate');
#### 自定義錯誤消息
另外你可能還需要為自定義規則來定義一個錯誤消息。這可以通過使用自定義內聯消息數組或是在驗證語言包中加入新的規則來實現。此消息應該被放在數組的第一級,而不是被放在 `custom` 數組內,這是僅針對特定屬性的錯誤消息:
"foo" => "你的輸入是無效的!",
"accepted" => ":attribute 必須被接受。",
// 其余的驗證錯誤消息...
當你在創建自定義驗證規則時,你可能需要定義占位符來取代錯誤消息。你可以像上面所描述的那樣通過 `Validator` Facade 來使用 `replacer` 方法創建一個自定義驗證器。通過 [服務提供者](/docs/{{version}}/providers) 中的 `boot` 方法可以實現:
/**
* 啟動任意應用程序服務。
*
* @return void
*/
public function boot()
{
Validator::extend(...);
Validator::replacer('foo', function ($message, $attribute, $rule, $parameters) {
return str_replace(...);
});
}
#### 隱式擴展功能
默認情況下,若有一個類似 [`required`](#rule-required) 這樣的規則,當此規則被驗證的屬性不存在或包含空值時,其一般的驗證規則(包括自定擴展功能)都將不會被運行。例如,當 integer 規則的值為 null 時 [`unique`](#rule-unique) 將不會被運行:
$rules = ['name' => 'unique'];
$input = ['name' => null];
Validator::make($input, $rules)->passes(); // true
如果要在屬性為空時依然運行此規則,則此規則必須暗示該屬性為必填。要創建一個「隱式」擴展功能,可以使用 `Validator::extendImplicit()` 方法:
Validator::extendImplicit('foo', function ($attribute, $value, $parameters, $validator) {
return $value == 'foo';
});
> {note} 一個「隱式」擴展功能只會 _暗示_ 該屬性為必填。它的實際屬性是否為無效屬性或空屬性主要取決于你。
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| Cloes | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/6187_1477389867.jpg?imageView2/1/w/100/h/100"> | 翻譯 | 我的[github](https://github.com/cloes) |
---
> {note} 歡迎任何形式的轉載,但請務必注明出處,尊重他人勞動共創開源社區。
>
> 轉載請注明:本文檔由 Laravel China 社區 [laravel-china.org](https://laravel-china.org) 組織翻譯,詳見 [翻譯召集帖](https://laravel-china.org/topics/5756/laravel-55-document-translation-call-come-and-join-the-translation)。
>
> 文檔永久地址: https://d.laravel-china.org
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- HomeStead
- Valet
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- 門面(Facades)
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- 重定向
- Session
- 表單驗證
- 錯誤與日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全
- 用戶認證
- API認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 交流說明