* * * * *
[TOC]
## 簡介
Laravel 提供了幾種不同的方法來驗證傳入應用程序的數據。默認情況下,Laravel 的控制器基類使用?`ValidatesRequests`?Trait,它提供了一種方便的方法使用各種強大的驗證規則來驗證傳入的 HTTP 請求。
## 快速驗證
要了解 Laravel 強大的驗證功能,讓我們看一個驗證表單并將錯誤消息顯示回給用戶的完整示例。
### 定義路由
首先,假設我們在?`routes/web.php`?文件中定義了以下路由:
~~~
Route::get('post/create', 'PostController@create');
Route::post('post', 'PostController@store');
~~~
當然,`GET`?路由會顯示一個供用戶創建一個新的博客帖子的表單,而?`POST`?路由會將新的博客文章存儲在數據庫中。
### 創建控制器
接下來,讓我們看看處理這些路由的簡單控制器。 現在我們將?`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)
{
// 驗證并存儲博客文章...
}
}
~~~
### 編寫驗證邏輯
現在我們準備開始在?`store`?方法中編寫邏輯來驗證新的博客文章。為此,我們將使用?`Illuminate\Http\Request`?對象提供的?`validate`?方法 。如果驗證通過,你的代碼就可以正常的運行。但是如果驗證失敗,就會拋出異常,并自動將對應的錯誤響應返回給用戶。在典型的 HTTP 請求的情況下,會生成一個重定向響應,而對于 AJAX 請求則會發送 JSON 響應。
讓我們接著回到?`store`?方法來深入理解?`validate`?方法:
~~~
/**
* 保存一篇新的博客文章。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// 文章內容是符合規則的,存入數據庫...
}
~~~
如你所見,我們將所需的驗證規則傳遞至?`validate`?方法中。另外再提醒一次,如果驗證失敗,會自動生成一個對應的響應。如果驗證通過,那我們的控制器將會繼續正常運行。
#### 首次驗證失敗后停止
有時,你希望在某個屬性第一次驗證失敗后停止運行驗證規則。為了達到這個目的,附加?`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',
]);
~~~
### 顯示驗證錯誤信息
如果傳入的請求參數未通過給定的驗證規則呢?正如前面所提到的,Laravel 會自動把用戶重定向到之前的位置。另外,所有的驗證錯誤信息會被自動?[閃存到 session](http://www.hmoore.net/tonyyu/laravel_5_6/786180#_164).
重申一次,我們不必在?`GET`?路由中將錯誤消息顯式綁定到視圖。因為 Lavarel 會檢查在 Session 數據中的錯誤信息,并自動將其綁定到視圖(如果這個視圖文件存在)。而其中的變量?`$errors`?是?`Illuminate\Support\MessageBag`?的一個實例。要獲取關于這個對象的更多信息,請?[查閱這個文檔](http://www.hmoore.net/tonyyu/laravel_5_6/786181#_367).
> {tip}?`$errors`?變量被 Web 中間件組提供的?`Illuminate\View\Middleware\ShareErrorsFromSession`?中間件綁定到視圖。?**當這個中間件被應用后,在你的視圖中就可以獲取到?`$error`?變量**, 可以使一直假定?`$errors`?變量存在并且可以安全地使用。
所以,在我們的例子中,當驗證失敗的時候,用戶將會被重定向到控制器的?`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 在你應用的全局中間件堆棧中包含在?`App\Http\Kernel`?類中的?`TrimStrings`?和?`ConvertEmptyStringsToNull`?中間件。因此,如果你不希望驗證程序將?`null`?值視為無效的,那就將「可選」的請求字段標記為?`nullable`。
~~~
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
~~~
在這個例子里,我們指定?`publish_at`?字段可以為?`null`?或者一個有效的日期格式。如果?`nullable`?的修飾詞沒有被添加到規則定義中,驗證器會認為?`null`?是一個無效的日期格式。
#### AJAX 請求 & 驗證
在這個例子中,我們使用傳統的表單將數據發送到應用程序。但實際情況中,很多程序都會使用 AJAX 來發送請求。當我們對 AJAX 的請求中使用?`validate`?方法時,Laravel 并不會生成一個重定向響應,而是會生成一個包含所有驗證錯誤信息的 JSON 響應。這個 JSON 響應會包含一個 HTTP 狀態碼 422 被發送出去。
## 表單驗證請求
### 創建表單請求
面對更復雜的驗證情境中,你可以創建一個「表單請求」來處理更為復雜的邏輯。表單請求是包含驗證邏輯的自定義請求類。可使用 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)
{
// 傳入請求有效...
}
~~~
如果驗證失敗,就會生成一個讓用戶返回到先前的位置的重定向響應。這些錯誤也會被閃存到 Session 中,以便這些錯誤都可以在頁面中顯示出來。如果傳入的請求是 AJAX,會向用戶返回具有 422 狀態代碼和驗證錯誤信息的 JSON 數據的 HTTP 響應。
#### 添加表單請求后鉤子
如果你想在表單請求「之后」添加鉤子,可以使用?`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!');
}
});
}
~~~
### 授權表單請求
表單請求類內也包含了?`authorize`?方法。在這個方法中,你可以檢查經過身份驗證的用戶確定其是否具有更新給定資源的權限。比方說,你可以判斷用戶是否擁有更新文章評論的權限:
~~~
/**
* 判斷用戶是否有權限做出此請求。
*
* @return bool
*/
public function authorize()
{
$comment = Comment::find($this->route('comment'));
return $comment && $this->user()->can('update', $comment);
}
~~~
由于所有的表單請求都是繼承了 Laravel 中的請求基類,所以我們可以使用?`user`?方法去獲取當前認證登錄的用戶。同時請注意上述例子中對?`route`?方法的調用。這個方法允許你在被調用的路由上獲取其定義的 URI 參數,譬如下面例子中的?`{comment}`?參數:
~~~
Route::post('comment/{comment}');
~~~
如果?`authorize`?方法返回?`false`,則會自動返回一個包含 403 狀態碼的 HTTP 響應,也不會運行控制器的方法。
如果你打算在應用程序的其它部分也能處理授權邏輯,只需從?`authorize`?方法返回?`true`?:
~~~
/**
* 判斷用戶是否有權限進行此請求。
*
* @return bool
*/
public function authorize()
{
return true;
}
~~~
### 自定義錯誤信息
你可以通過重寫表單請求的?`messages`?方法來自定義錯誤消息。此方法應該如下所示返回屬性/規則對數組及其對應錯誤消息:
~~~
/**
* 獲取已定義的驗證規則的錯誤消息。
*
* @return array
*/
public function messages()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
~~~
## 手動創建驗證器
如果你不想要使用請求上使用?`validate`?方法,你可以通過 validator?`Validator`?[facade](http://www.hmoore.net/tonyyu/laravel_5_6/786058)?手動創建一個驗證器實例。用 Facade 上的?`make`?方法生成一個新的驗證器實例:
~~~
<?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`?方法接收驗證器、`MessageBag`?或 PHP?`array`。
### 自動重定向
如果你想手動創建驗證器實例,又想利用請求中?`validates`?方法提供的自動重定向,那么你可以在現有的驗證器實例上調用?`validate`?方法。如果驗證失敗,用戶會自動重定向,如果是 AJAX 請求,將會返回 JSON 格式的響應:
~~~
Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
])->validate();
~~~
### 命名錯誤包
如果你一個頁面中有多個表單,你可以命名錯誤信息的?`MessageBag`?來檢索特定表單的錯誤消息。只需給?`withErrors`?方法傳遞一個名字作為第二個參數:
~~~
return redirect('register')
->withErrors($validator, 'login');
~~~
然后你能從?`$errors`?變量中獲取命名的?`MessageBag`?實例:
~~~
{{ $errors->login->first('email') }}
~~~
### 驗證后鉤子
驗證器還允許你添加在驗證完成之后運行的回調函數。以便你進行進一步的驗證,甚至是在消息集合中添加更多的錯誤消息。使用它只需在驗證實例上使用?`after`?方法:
~~~
$validator = Validator::make(...);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
if ($validator->fails()) {
//
}
~~~
## 處理錯誤消息
在 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')) {
//
}
~~~
### 自定義錯誤消息
如果有需要的話,你也可以自定義錯誤消息取代默認值進行驗證。有幾種方法可以指定自定義消息。首先,你可以將自定義消息作為第三個參數傳遞給?`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 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 e-mail address!',
];
~~~
#### 在語言文件中指定自定義消息
現實中大多數情況下,我們可能不僅僅只是將自定義消息傳遞給?`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',
],
~~~
## 可用驗證規則
以下是所有可用的驗證規則及其功能的清單:
[Accepted](http://www.hmoore.net/tonyyu/laravel_5_6/786181#accepted_532)
[Active URL](http://www.hmoore.net/tonyyu/laravel_5_6/786181#active_url_536)
[After (Date)](http://www.hmoore.net/tonyyu/laravel_5_6/786181#afterdate_540)
[After Or Equal (Date)](http://www.hmoore.net/tonyyu/laravel_5_6/786181#after_or_equaldate_554)
[Alpha](http://www.hmoore.net/tonyyu/laravel_5_6/786181#alpha_558)
[Alpha Dash](http://www.hmoore.net/tonyyu/laravel_5_6/786181#alpha_dash_562)
[Alpha Numeric](http://www.hmoore.net/tonyyu/laravel_5_6/786181#alpha_num_566)
[Array](http://www.hmoore.net/tonyyu/laravel_5_6/786181#array_570)
[Before (Date)](http://www.hmoore.net/tonyyu/laravel_5_6/786181#beforedate_574)
[Before Or Equal (Date)](http://www.hmoore.net/tonyyu/laravel_5_6/786181#before_or_equaldate_578)
[Between](http://www.hmoore.net/tonyyu/laravel_5_6/786181#betweenminmax_582)
[Boolean](http://www.hmoore.net/tonyyu/laravel_5_6/786181#boolean_586)
[Confirmed](http://www.hmoore.net/tonyyu/laravel_5_6/786181#confirmed_590)
[Date](http://www.hmoore.net/tonyyu/laravel_5_6/786181#date_594)
[Date Equals](http://www.hmoore.net/tonyyu/laravel_5_6/786181#date_equalsdate_598)
[Date Format](http://www.hmoore.net/tonyyu/laravel_5_6/786181#date_formatformat_602)
[Different](http://www.hmoore.net/tonyyu/laravel_5_6/786181#differentfield_606)
[Digits](http://www.hmoore.net/tonyyu/laravel_5_6/786181#digitsvalue_610)
[Digits Between](http://www.hmoore.net/tonyyu/laravel_5_6/786181#digits_betweenminmax_614)
[Dimensions (Image Files)](http://www.hmoore.net/tonyyu/laravel_5_6/786181#dimensions_618)
[Distinct](http://www.hmoore.net/tonyyu/laravel_5_6/786181#distinct_647)
[E-Mail](http://www.hmoore.net/tonyyu/laravel_5_6/786181#email_655)
[Exists (Database)](http://www.hmoore.net/tonyyu/laravel_5_6/786181#existstablecolumn_659)
[File](http://www.hmoore.net/tonyyu/laravel_5_6/786181#file_696)
[Filled](http://www.hmoore.net/tonyyu/laravel_5_6/786181#filled_700)
[Image (File)](http://www.hmoore.net/tonyyu/laravel_5_6/786181#image_704)
[In](http://www.hmoore.net/tonyyu/laravel_5_6/786181#infoobar_708)
[In Array](http://www.hmoore.net/tonyyu/laravel_5_6/786181#in_arrayanotherfield_723)
[Integer](http://www.hmoore.net/tonyyu/laravel_5_6/786181#integer_727)
[IP Address](http://www.hmoore.net/tonyyu/laravel_5_6/786181#ip_731)
[JSON](http://www.hmoore.net/tonyyu/laravel_5_6/786181#json_743)
[Max](http://www.hmoore.net/tonyyu/laravel_5_6/786181#maxvalue_747)
[MIME Types](http://www.hmoore.net/tonyyu/laravel_5_6/786181#mimetypestextplain_751)
[MIME Type By File Extension](http://www.hmoore.net/tonyyu/laravel_5_6/786181#mimesfoobar_761)
[Min](http://www.hmoore.net/tonyyu/laravel_5_6/786181#minvalue_776)
[Nullable](http://www.hmoore.net/tonyyu/laravel_5_6/786181#nullable_780)
[Not In](http://www.hmoore.net/tonyyu/laravel_5_6/786181#not_infoobar_784)
[Numeric](http://www.hmoore.net/tonyyu/laravel_5_6/786181#numeric_799)
[Present](http://www.hmoore.net/tonyyu/laravel_5_6/786181#present_803)
[Regular Expression](http://www.hmoore.net/tonyyu/laravel_5_6/786181#regexpattern_807)
[Required](http://www.hmoore.net/tonyyu/laravel_5_6/786181#required_813)
[Required If](http://www.hmoore.net/tonyyu/laravel_5_6/786181#required_ifanotherfieldvalue_822)
[Required Unless](http://www.hmoore.net/tonyyu/laravel_5_6/786181#required_unlessanotherfieldvalue_826)
[Required With](http://www.hmoore.net/tonyyu/laravel_5_6/786181#required_withfoobar_830)
[Required With All](http://www.hmoore.net/tonyyu/laravel_5_6/786181#required_with_allfoobar_834)
[Required Without](http://www.hmoore.net/tonyyu/laravel_5_6/786181#required_withoutfoobar_838)
[Required Without All](http://www.hmoore.net/tonyyu/laravel_5_6/786181#required_without_allfoobar_842)
[Same](http://www.hmoore.net/tonyyu/laravel_5_6/786181#samefield_846)
[Size](http://www.hmoore.net/tonyyu/laravel_5_6/786181#sizevalue_850)
[String](http://www.hmoore.net/tonyyu/laravel_5_6/786181#string_854)
[Timezone](http://www.hmoore.net/tonyyu/laravel_5_6/786181#timezone_858)
[Unique (Database)](http://www.hmoore.net/tonyyu/laravel_5_6/786181#uniquetablecolumnexceptidColumn_862)
[URL](http://www.hmoore.net/tonyyu/laravel_5_6/786181#url_915)
#### accepted
驗證的字段必須為?*yes*,?*on*,?*1*, or?*true*。這在確認「服務條款」是否同意時相當有用。
#### active_url
相當于使用了 PHP 函數?`dns_get_record`?[dns_get_record 函數詳解](http://php.net/manual/zh/function.dns-get-record.php),驗證的字段必須具有有效的 A 或 AAAA 記錄。
#### after:*date*
驗證的字段必須是給定日期后的值。這個日期將會通過 PHP 函數?`strtotime`?來驗證。
~~~
'start_date' => 'required|date|after:tomorrow'
~~~
您可以指定另一個字段與日期進行比較,而不是傳遞一個日期字符串用?`strtotime`?進行比較:
~~~
'finish_date' => 'required|date|after:start_date'
~~~
#### after_or_equal:*date*
驗證的字段的值必須等于給定日期或在其之后。更多信息請參見?[after](http://www.hmoore.net/tonyyu/laravel_5_6/786181#afterdate_540)?規則。
#### alpha
驗證的字段必須完全由字母構成。
#### alpha_dash
驗證的字段可能具有字母、數字、破折號( - )以及下劃線( _ )。
#### alpha_num
驗證的字段必須完全是字母、數字。
#### array
驗證的字段必須是一個 PHP 數組。
#### before:*date*
驗證的字段必須是給定日期之前的值。這個日期將會通過 PHP?`strtotime`?函數來驗證。
#### before_or_equal:*date*
驗證的字段的值必須等于給定日期或在其之前。這個日期將會使用 PHP?`strtotime`?函數來驗證。
#### between:*min*,*max*
驗證的字段的大小必須在給定的?*min*?和?*max*?之間。字符串、數字、數組或是文件大小的計算方式都用 size?[`size`](http://www.hmoore.net/tonyyu/laravel_5_6/786181#sizevalue_850)?方法。
#### boolean
驗證的字段必須能夠被轉換為布爾值。可接受的參數為?`true`,?`false`,?`1`,?`0`,?`"1"`, 以及?`"0"`。
#### confirmed
驗證的字段必須和?`foo_confirmation`?的字段值一致。例如,如果要驗證的字段是?`password`,輸入中必須存在匹配的?`password_confirmation`?字段。
#### date
驗證的字段值必須是通過 PHP 函數?`strtotime`?校驗的有效日期。
#### date_equals:*date*
驗證的字段必須等于給定的日期。該日期會被傳遞到 PHP?`strtotime`?函數。
#### date_format:*format*
驗證的字段必須與給定的格式相匹配。你應該只使用?`date`?或?`date_format`?中的?**其中一個**?用于驗證,而不應該同時使用兩者。
#### different:*field*
驗證的字段值必須與字段 (?*field*) 的值不同。
#### digits:*value*
驗證的字段必須是?*數字*?,并且必須具有確切的?*值*。
#### digits_between:*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`?這樣的 float 來指定:
~~~
'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),
],
]);
~~~
#### distinct
驗證數組時,指定的字段不能有任何重復值。
~~~
'foo.*.id' => 'distinct'
~~~
#### email
驗證的字段必須符合 e-mail 地址格式。
#### 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);
}),
],
]);
~~~
#### file
驗證的字段必須是成功上傳的文件。
#### filled
驗證的字段在存在時不能為空。
#### image
驗證的文件必須是一個圖像( jpeg、png、bmp、gif、或 svg )。
#### in:*foo*,*bar*,...
驗證的字段必須包含在給定的值列表中。因為這個規則通常需要你?`implode`?一個數組,`Rule::in`?方法可以用來構造規則:
~~~
use Illuminate\Validation\Rule;
Validator::make($data, [
'zones' => [
'required',
Rule::in(['first-zone', 'second-zone']),
],
]);
~~~
#### in_array:*anotherfield*
驗證的字段必須存在于另一個字段?*anotherfield*?的值中。
#### integer
驗證的字段必須是整數。
#### ip
驗證的字段必須是 IP 地址。
#### ipv4
驗證的字段必須是 IPv4 地址。
#### ipv6
驗證的字段必須是 IPv6 地址。
#### json
驗證的字段必須是有效的 JSON 字符串。
#### max:*value*
驗證中的字段必須小于或等于?*value*。字符串、數字、數組或是文件大小的計算方式都用?[`size`](http://www.hmoore.net/tonyyu/laravel_5_6/786181#sizevalue_850)?方法進行評估。
#### mimetypes:*text/plain*,...
驗證的文件必須與給定 MIME 類型之一匹配:
~~~
'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime'
~~~
要確定上傳文件的 MIME 類型,會讀取文件的內容來判斷 MIME 類型,這可能與客戶端提供的 MIME 類型不同。
#### 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)
#### min:*value*
驗證中的字段必須具有最小值。字符串、數字、數組或是文件大小的計算方式都用?[`size`](http://www.hmoore.net/tonyyu/laravel_5_6/786181#sizevalue_850)?方法進行評估。
#### nullable
驗證的字段可以為?`null`。這在驗證基本數據類型時特別有用,例如可以包含空值的字符串和整數。
#### not_in:*foo*,*bar*,...
驗證的字段不能包含在給定的值列表中。`Rule::notIn`?方法可以用來構建規則:
~~~
use Illuminate\Validation\Rule;
Validator::make($data, [
'toppings' => [
'required',
Rule::notIn(['sprinkles', 'cherries']),
],
]);
~~~
#### numeric
驗證的字段必須是數字。
#### present
驗證的字段必須存在于輸入數據中,但可以為空。
#### regex:*pattern*
驗證的字段必須與給定的正則表達式匹配。
**注意:**?當使用?`regex`?規則時,你必須使用數組,而不是使用?`|`?分隔符,特別是如果正則表達式包含?`|`?字符。
#### required
驗證的字段必須存在于輸入數據中,而不是空。如果滿足以下條件之一,則字段被視為「空」:
* 值為?`null`。
* 值為空字符串。
* 值為空數組或空?`Countable`?對象。
* 值為無路徑的上傳文件。
#### required_if:*anotherfield*,*value*,...
如果?*anotherfield*?字段等于任一?*value*,驗證的字段必須出現且不為空 。
#### required_unless:*anotherfield*,*value*,...
如果?*anotherfield*?字段不等于任一?*value*,驗證的字段必須出現且不為空。
#### required_with:*foo*,*bar*,...
只有在其他任一指定字段出現時,驗證的字段才必須出現且不為空。
#### required_with_all:*foo*,*bar*,...
只有在其他指定字段全部出現時,驗證的字段才必須出現且不為空。
#### required_without:*foo*,*bar*,...
只在其他指定任一字段不出現時,驗證的字段才必須出現且不為空。
#### required_without_all:*foo*,*bar*,...
只有在其他指定字段全部不出現時,驗證的字段才必須出現且不為空。
#### same:*field*
驗證的字段必須與給定字段匹配。
#### size:*value*
驗證的字段必須具有與給定值匹配的大小。對于字符串,*value*?對應字符數。對于數字,*value*?對應給定的整數值。對于數組,*size*?對應數組的?`count`?值。對于文件,*size*?對應文件大小(單位kb)。
#### string
驗證的字段必須是一個字符串。如果允許這個字段為?`null`,需要給這個字段分配?`nullable`?規則。
#### timezone
驗證的字段必須是一個基于 PHP 函數?`timezone_identifiers_list`?的有效時區標識。
#### 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 的擁有者了。
使用?`Rule`?類定義規則來指示驗證器忽略用戶的 ID。這個例子中通過數組來指定驗證規則,而不是使用?`|`?字符來分隔:
~~~
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) {
return $query->where('account_id', 1);
})
~~~
#### url
驗證的字段必須是有效的 URL。
## 按條件增加規則
#### 存在才驗證
在某些情況下,**只有**在該字段存在于數組中時, 才可以對字段執行驗證檢查。可通過增加?`sometimes`?到規則列表來實現:
~~~
$v = Validator::make($data, [
'email' => 'sometimes|required|email',
]);
~~~
在上面的例子中,?`email`?字段只有在?`$data`?數組中存在才會被驗證。
> {tip} 如果你嘗試驗證應該始終存在但可能為空的字段,請查閱?[可選字段的注意事項](http://www.hmoore.net/tonyyu/laravel_5_6/786181#_138)
#### 復雜的條件驗證
有時候你可能需要增加基于更復雜的條件邏輯的驗證規則。例如,你可以希望某個指定字段在另一個字段的值超過 100 時才為必填。或者當某個指定字段存在時,另外兩個字段才能具有給定的值。增加這樣的驗證條件并不難。首先,使用?*靜態規則*?創建一個?`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`?的一個實例,可用來訪問你的輸入或文件對象。
## 驗證數組
驗證表單的輸入為數組的字段也不難。你可以使用 「點」方法來驗證數組中的屬性。例如,如果傳入的 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',
]
],
~~~
## 自定義驗證規則
### 使用規則對象
Laravel 提供了許多有用的驗證規則,同時也支持自定義規則。注冊自定義驗證規則的方法之一,就是使用規則對象。可以使用 Artisan 命令?`make:rule`?來生成新的規則對象。接下來,讓我們用這個命令生成一個驗證字符串是大寫的規則。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],
]);
~~~
### 使用閉包
如果你在應用程序中只需要一次自定義規則的功能,則可以使用閉包而不是規則對象。閉包接收屬性的名稱,屬性的值以及如果驗證失敗應該調用的?`$fail`?回調:
~~~
$validator = Validator::make($request->all(), [
'title' => [
'required',
'max:255',
function($attribute, $value, $fail) {
if ($value === 'foo') {
return $fail($attribute.' is invalid.');
}
},
],
]);
~~~
### 使用擴展
另外一個注冊自定義驗證規則的方法,就是使用?`Validator`?[facade](http://www.hmoore.net/tonyyu/laravel_5_6/786058)?中的 extend 方法。讓我們在?[服務容器](http://www.hmoore.net/tonyyu/laravel_5_6/786056)?中使用這個方法來注冊自定義驗證規則:
~~~
<?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" => "Your input was invalid!",
"accepted" => "The :attribute must be accepted.",
// 其余的驗證錯誤消息...
~~~
當創建一個自定義驗證規則時,你可能有時候需要為錯誤信息定義自定義占位符。可以通過創建自定義驗證器然后調用?`Validator`?門面上的`replacer`?方法.。你可以在?[服務提供者](http://www.hmoore.net/tonyyu/laravel_5_6/786057)?的?`boot`?方法中執行如下操作:
~~~
/**
* 啟動應用服務.
*
* @return void
*/
public function boot()
{
Validator::extend(...);
Validator::replacer('foo', function ($message, $attribute, $rule, $parameters) {
return str_replace(...);
});
}
~~~
#### 隱式擴展
默認情況下, 當所要驗證的屬性不存在或包含由?[`required`](http://www.hmoore.net/tonyyu/laravel_5_6/786181#required_813)?規則定義的空值時,那么正常的驗證規則,包括自定義擴展將不會執行。 例如,?[`unique`](http://www.hmoore.net/tonyyu/laravel_5_6/786181#uniquetablecolumnexceptidColumn_862)?規則將不會檢驗?`null`?值:
~~~
$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} 「隱式」擴展只?*暗示*?該屬性是必需的。至于它到底是缺失的還是空值這取決于你。
- 前言
- 翻譯說明
- 發行說明
- 升級指南
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- Homestead
- Valet
- 部署
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- Facades
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- URL
- Session
- 表單驗證
- 錯誤
- 日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全相關
- 用戶認證
- Passport OAuth 認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試相關
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Scout 全文搜索
- Socialite 社會化登錄