表單驗(yàn)證
表單驗(yàn)證
表單驗(yàn)證
- 簡介
- 快速驗(yàn)證
- 驗(yàn)證表單請求
- 手動(dòng)創(chuàng)建驗(yàn)證器
- 處理錯(cuò)誤信息
- 可用驗(yàn)證規(guī)則
- 按條件添加驗(yàn)證規(guī)則
- 驗(yàn)證數(shù)組
- 自定義驗(yàn)證規(guī)則
簡介
Laravel 提供了幾種不同的方法來驗(yàn)證傳入應(yīng)用程序的數(shù)據(jù)。默認(rèn)情況下,Laravel 的控制器基類使用 ValidatesRequests
Trait,它提供了一種方便的方法去使用各種強(qiáng)大的驗(yàn)證規(guī)則來驗(yàn)證傳入的 HTTP 請求。
快速驗(yàn)證
要了解 Laravel 強(qiáng)大的驗(yàn)證功能,讓我們看一個(gè)驗(yàn)證表單并將錯(cuò)誤消息顯示回給用戶的完整示例。
定義路由
首先,讓我們假設(shè)在 routes/web.php
文件中定義了下面這些路由:
Route::get('post/create', 'PostController@create'); Route::post('post', 'PostController@store');
顯然,GET
路由會(huì)顯示一個(gè)供用戶創(chuàng)建一個(gè)新的博客帖子的表單,而 POST 路由會(huì)將新的博客文章存儲在數(shù)據(jù)庫中。
創(chuàng)建路由器
下面讓我們一起來看看處理這些路由的控制器, store
方法暫時(shí)留空。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Controllers\Controller; class PostController extends Controller{ /** * 顯示創(chuàng)建博客文章的表單。 * * @return Response */ public function create() { return view('post.create'); } /** * 保存一篇新的博客文章。 * * @param Request $request * @return Response */ public function store(Request $request) { // 驗(yàn)證并存儲博客文章... } }
編寫驗(yàn)證器邏輯
現(xiàn)在我們開始在 store
方法中編寫邏輯來驗(yàn)證新的博客文章。為此,我們將使用 Illuminate\Http\Request
對象提供的 validate
方法 。如果驗(yàn)證通過,代碼就可以正常的運(yùn)行。如果驗(yàn)證失敗,則會(huì)拋出異常,并自動(dòng)將對應(yīng)的錯(cuò)誤響應(yīng)返回給用戶。在典型的 HTTP 請求的情況下,會(huì)生成一個(gè)重定向響應(yīng),而對于 AJAX 請求則會(huì)發(fā)送 JSON 響應(yīng)。
讓我們接著回到 store
方法來深入理解 validate
方法:
/** * 保存一篇新的博客文章。 * * @param Request $request * @return Response */ public function store(Request $request){ $validatedData = $request->validate([ 'title' => 'required|unique:posts|max:255', 'body' => 'required', ]); // 博客文章驗(yàn)證通過 }
如你所見,我們將所需的驗(yàn)證規(guī)則傳遞至 validate
方法中。另外再提醒一次,如果驗(yàn)證失敗,會(huì)自動(dòng)生成一個(gè)對應(yīng)的響應(yīng)。如果驗(yàn)證通過,那我們的控制器將會(huì)繼續(xù)正常運(yùn)行。
首次驗(yàn)證失敗后停止運(yùn)行
如果你希望在某個(gè)屬性第一次驗(yàn)證失敗后停止運(yùn)行驗(yàn)證規(guī)則,你需要附加 bail
規(guī)則到該屬性:
$request->validate([ 'title' => 'bail|required|unique:posts|max:255', 'body' => 'required', ]);
在這個(gè)例子中,如果 title
字段沒有通過 unique
規(guī)則,那么程序就不會(huì)繼續(xù)檢查 max
規(guī)則。規(guī)則會(huì)按照分配的順序來驗(yàn)證。
關(guān)于數(shù)組數(shù)據(jù)的注意實(shí)現(xiàn)
如果你的 HTTP 請求包含一個(gè) 「嵌套」 參數(shù)(即數(shù)組),那你可以在驗(yàn)證規(guī)則中通過 「點(diǎn)」 語法來指定這些參數(shù)。
$request->validate([ 'title' => 'required|unique:posts|max:255', 'author.name' => 'required', 'author.description' => 'required', ]);
顯示驗(yàn)證錯(cuò)誤信息
如果傳入的請求參數(shù)未通過給定的驗(yàn)證規(guī)則呢?正如前面所提到的,Laravel 會(huì)自動(dòng)把用戶重定向到之前的位置。另外,所有的驗(yàn)證錯(cuò)誤信息會(huì)被自動(dòng) 存儲到 session
中。
重申一次,我們不必在 GET
路由中將錯(cuò)誤消息顯式綁定到視圖。因?yàn)?Lavarel 會(huì)檢查在 Session 數(shù)據(jù)中的錯(cuò)誤信息,并自動(dòng)將其綁定到視圖(如果這個(gè)視圖文件存在)。而其中的變量 $errors
是 Illuminate\Support\MessageBag
的一個(gè)實(shí)例。要獲取關(guān)于這個(gè)對象的更多信息,請 查閱這個(gè)文檔 。
{tip}
$errors
變量被Web
中間件組提供的Illuminate\View\Middleware\ShareErrorsFromSession
中間件綁定到視圖中。 當(dāng)這個(gè)中間件被應(yīng)用后,在你的視圖中就可以獲取到$error
變量 , 可以使一直假定$errors
變量存在并且可以安全地使用。
在上面的例子中,當(dāng)驗(yàn)證失敗的時(shí)候,用戶將會(huì)被重定向到控制器的 create
方法,使我們能在視圖中顯示錯(cuò)誤信息:
<!-- /resources/views/post/create.blade.php --> <h1>創(chuàng)建文章</h1> @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <!-- 創(chuàng)建文章表單 -->
關(guān)于可選字段的注意事項(xiàng)
默認(rèn)情況下,在 Laravel 應(yīng)用的全局中間件堆棧 App\Http\Kernel
類中包含了 TrimStrings
和 ConvertEmptyStringsToNull
中間件。因此,如果你不希望驗(yàn)證程序?qū)?null
值視為無效的話,那就需要將「可選」的請求字段標(biāo)記為 nullable
,舉個(gè)例子:
$request->validate([ 'title' => 'required|unique:posts|max:255', 'body' => 'required', 'publish_at' => 'nullable|date', ]);
在這個(gè)例子里,我們指定 publish_at
字段可以為 null
或者一個(gè)有效的日期格式。如果 nullable
的修飾詞沒有被添加到規(guī)則定義中,驗(yàn)證器會(huì)認(rèn)為 null
是一個(gè)無效的日期格式。
AJAX 請求 & 驗(yàn)證
在這個(gè)例子中,我們使用傳統(tǒng)的表單將數(shù)據(jù)發(fā)送到應(yīng)用程序。但實(shí)際情況中,很多程序都會(huì)使用 AJAX 來發(fā)送請求。當(dāng)我們對 AJAX 的請求中使用 validate
方法時(shí),Laravel 并不會(huì)生成一個(gè)重定向響應(yīng),而是會(huì)生成一個(gè)包含所有驗(yàn)證錯(cuò)誤信息的 JSON 響應(yīng)。這個(gè) JSON 響應(yīng)會(huì)包含一個(gè) HTTP 狀態(tài)碼 422 被發(fā)送出去。
驗(yàn)證表單請求
創(chuàng)建表單請求驗(yàn)證
面對更復(fù)雜的驗(yàn)證情境中,你可以創(chuàng)建一個(gè)「表單請求」來處理更為復(fù)雜的邏輯。表單請求是包含驗(yàn)證邏輯的自定義請求類??墒褂?Artisan 命令 make:request
來創(chuàng)建表單請求類:
php artisan make:request StoreBlogPost
新生成的類保存在 app/Http/Requests
目錄下。如果這個(gè)目錄不存在,運(yùn)行 make:request
命令時(shí)它會(huì)被創(chuàng)建出來。讓我們添加一些驗(yàn)證規(guī)則到 rules
方法中:
/** * 獲取適用于請求的驗(yàn)證規(guī)則。 * * @return array */ public function rules(){ return [ 'title' => 'required|unique:posts|max:255', 'body' => 'required', ]; }
{tip} 你可以向
rules
方法傳入所需的任何依賴項(xiàng)。他們會(huì)自動(dòng)被 Laravel 提供的 服務(wù)容器 自動(dòng)解析。
驗(yàn)證規(guī)則是如何運(yùn)行的呢?你所需要做的就是在控制器方法中類型提示傳入的請求。在調(diào)用控制器方法之前驗(yàn)證傳入的表單請求,這意味著你不需要在控制器中寫任何驗(yàn)證邏輯:
/** * 存儲傳入的博客文章。 * * @param StoreBlogPost $request * @return Response */ public function store(StoreBlogPost $request){ // 傳入的請求通過驗(yàn)證... // 獲取通過驗(yàn)證的數(shù)據(jù)... $validated = $request->validated(); }
如果驗(yàn)證失敗,就會(huì)生成一個(gè)讓用戶返回到先前的位置的重定向響應(yīng)。這些錯(cuò)誤也會(huì)被閃存到 session
中,以便這些錯(cuò)誤都可以在頁面中顯示出來。如果傳入的請求是 AJAX,會(huì)向用戶返回具有 422 狀態(tài)代碼和驗(yàn)證錯(cuò)誤信息的 JSON 數(shù)據(jù)的 HTTP 響應(yīng)。
添加表單請求后鉤子
如果你想在表單請求「之后」添加鉤子,可以使用 withValidator
方法。這個(gè)方法接收一個(gè)完整的驗(yàn)證構(gòu)造器,允許你在驗(yàn)證結(jié)果返回之前調(diào)用任何方法:
/** * 配置驗(yàn)證器實(shí)例。 * * @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!'); } }); }
表單請求授權(quán)驗(yàn)證
表單請求類內(nèi)也包含了 authorize
方法。在這個(gè)方法中,你可以檢查經(jīng)過身份驗(yàn)證的用戶確定其是否具有更新給定資源的權(quán)限。比方說,你可以判斷用戶是否擁有更新文章評論的權(quán)限:
/** * 判斷用戶是否有權(quán)限做出此請求。 * * @return bool */ public function authorize(){ $comment = Comment::find($this->route('comment')); return $comment && $this->user()->can('update', $comment); }
由于所有的表單請求都是繼承了 Laravel 中的請求基類,所以我們可以使用 user
方法去獲取當(dāng)前認(rèn)證登錄的用戶。同時(shí)請注意上述例子中對 route
方法的調(diào)用。這個(gè)方法允許你在被調(diào)用的路由上獲取其定義的 URI 參數(shù),譬如下面例子中的 {comment}
參數(shù):
Route::post('comment/{comment}');
如果 authorize
方法返回 false
,則會(huì)自動(dòng)返回一個(gè)包含 403 狀態(tài)碼的 HTTP 響應(yīng),也不會(huì)運(yùn)行控制器的方法。
如果你打算在應(yīng)用程序的其它部分處理授權(quán)邏輯,只需從 authorize
方法返回 true
:
/** * 判斷用戶是否有權(quán)限進(jìn)行此請求。 * * @return bool */ public function authorize(){ return true; }
{tip} 你可以向
authorize
方法傳入所需的任何依賴項(xiàng)。他們會(huì)自動(dòng)被 Laravel 提供的 服務(wù)容器 自動(dòng)解析。
自定義錯(cuò)誤消息
你可以通過重寫表單請求的 messages
方法來自定義錯(cuò)誤消息。此方法應(yīng)返回屬性 / 規(guī)則對數(shù)組及其對應(yīng)錯(cuò)誤消息:
/** * 獲取已定義驗(yàn)證規(guī)則的錯(cuò)誤消息。 * * @return array */ public function messages(){ return [ 'title.required' => 'A title is required', 'body.required' => 'A message is required', ]; }
自定義驗(yàn)證屬性
如果你希望將驗(yàn)證消息的 :attribute
部分替換為自定義屬性名稱,則可以重寫 attributes
方法來指定自定義名稱。此方法應(yīng)返回屬性 / 名稱對的數(shù)組:
/** * 獲取驗(yàn)證錯(cuò)誤的自定義屬性。 * * @return array */ public function attributes(){ return [ 'email' => 'email address', ]; }
手動(dòng)創(chuàng)建驗(yàn)證器
如果你不想在請求上使用 validate
方法,你可以通過 Validator
facade 手動(dòng)創(chuàng)建一個(gè)驗(yàn)證器示例。
用 Validator
facade 上的 make
方法創(chuàng)建一個(gè)驗(yàn)證器示例:
<?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(); } // Store the blog post... } }
傳給 make
方法的第一個(gè)參數(shù)是需要驗(yàn)證的數(shù)據(jù)。第二個(gè)參數(shù)則是該數(shù)據(jù)的驗(yàn)證規(guī)則。
如果驗(yàn)證失敗,則可以使用 withErrors
方法把錯(cuò)誤消息閃存到 Session 。使用這個(gè)方法進(jìn)行重定向后, $errors
變量會(huì)自動(dòng)和視圖共享,你可以把這些消息顯示給用戶。 withErrors
方法接收驗(yàn)證器、MessageBag
或 PHP Array
。
自動(dòng)重定向
如果你想手動(dòng)創(chuàng)建驗(yàn)證器實(shí)例,又想使用 validates
方法提供的自動(dòng)重定向,那么你可以在現(xiàn)有的驗(yàn)證器示例上調(diào)用 validate
方法。如果驗(yàn)證失敗,用戶將會(huì)自動(dòng)重定向。在 AJAX 請求中,則會(huì)返回 JSON 格式的響應(yīng)。
Validator::make($request->all(), [ 'title' => 'required|unique:posts|max:255', 'body' => 'required', ])->validate();
命名錯(cuò)誤包
如果你一個(gè)頁面中有多個(gè)表單,你可以通過命名錯(cuò)誤包來檢索特定表單的錯(cuò)誤消息。只需給 withErrors
方法傳遞一個(gè)名字作為第二個(gè)參數(shù)
return redirect('register') ->withErrors($validator, 'login');
然后你就可以從 $errors
變量中獲取指定表單的錯(cuò)誤消息:
{{ $errors->login->first('email') }}
驗(yàn)證后鉤子
驗(yàn)證器還允許你添加在驗(yàn)證成功之后允許的回調(diào)函數(shù),以便你進(jìn)行下一步的驗(yàn)證,甚至在消息集合中添加更多的錯(cuò)誤消息。使用它只需在驗(yàn)證實(shí)例上使用 after
方法:
$validator = Validator::make(...);$validator->after(function ($validator) { if ($this->somethingElseIsInvalid()) { $validator->errors()->add('field', 'Something is wrong with this field!'); } }); if ($validator->fails()) { // }
處理錯(cuò)誤消息
在 Validator
實(shí)例上調(diào)用 errors
方法后,你會(huì)得到一個(gè) Illuminate\Support\MessageBag
實(shí)例,它擁有各種方便的方法處理錯(cuò)誤信息。自動(dòng)提供給所有視圖的 $ errors
變量,也是 MessageBag
類的一個(gè)實(shí)例。
查看特定字段的第一個(gè)錯(cuò)誤信息
要查看特定字段的第一個(gè)錯(cuò)誤消息,可以使用 first
方法:
$errors = $validator->errors();echo $errors->first('email');
查看特定字段的所有錯(cuò)誤消息
如果你需要獲取指定字段的所有錯(cuò)誤消息的數(shù)組,則可以使用 get
方法:
foreach ($errors->get('email') as $message) { // }
如果要驗(yàn)證表單的數(shù)組字段,你可以使用 *
來獲取每個(gè)數(shù)組元素的所有錯(cuò)誤消息:
foreach ($errors->get('attachments.*') as $message) { // }
查看所有字段的所有錯(cuò)誤消息
如果你想要得到所有字段的所有錯(cuò)誤消息,可以使用 all
方法:
foreach ($errors->all() as $message) { // }
判斷特定字段是否含有錯(cuò)誤消息
has
方法可以被用來判斷給定的字段是否存在錯(cuò)誤信息:
if ($errors->has('email')) { // }
自定義錯(cuò)誤消息
如果有需要的話,你也可以使用自定義錯(cuò)誤消息取代默認(rèn)值進(jìn)行驗(yàn)證。有幾種方法可以指定自定義消息。首先,你可以將自定義消息作為第三個(gè)參數(shù)傳遞給 Validator::make
方法:
$messages = [ 'required' => 'The :attribute field is required.', ]; $validator = Validator::make($input, $rules, $messages);
在這個(gè)例子中,:attribute
占位符會(huì)被驗(yàn)證字段的實(shí)際名稱取代。除此之外,你還可以在驗(yàn)證消息中使用其它占位符。例如:
$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', ];
為給定屬性指定自定義消息
有時(shí)候你可能只想為特定的字段自定義錯(cuò)誤消息。只需在屬性名稱后使用「點(diǎn)」語法來指定驗(yàn)證的規(guī)則即可:
$messages = [ 'email.required' => 'We need to know your e-mail address!', ];
在語言文件中指定自定義消息
在大多數(shù)情況下,您可能會(huì)在語言文件中指定自定義消息,而不是直接將它們傳遞給 Validator
。為此,需要把你的消息放置于 resources/lang/xx/validation.php
語言文件內(nèi)的 custom
數(shù)組中。
'custom' => [ 'email' => [ 'required' => 'We need to know your e-mail address!', ], ],
在語言文件中指定自定義屬性
如果你希望將驗(yàn)證消息的 :attribute
占位符替換為自定義屬性名稱,你可以在 resources/lang/xx/validation.php
語言文件的 attributes
數(shù)組中指定自定義名稱:
'attributes' => [ 'email' => 'email address', ],
在語言文件中指定自定義值
有時(shí)可能需要將驗(yàn)證消息的 :value
占位符替換為值的自定義文字。例如,如果 payment_type
的值為 cc
,使用以下驗(yàn)證規(guī)則,該規(guī)則指定需要信用卡號:
$request->validate([ 'credit_card_number' => 'required_if:payment_type,cc' ]);
如果此驗(yàn)證規(guī)則失敗,則會(huì)產(chǎn)生以下錯(cuò)誤消息:
當(dāng)payment type為cc時(shí),credit card number 不能為空。
您可以通過定義 values
數(shù)組,在 validation
語言文件中指定自定義值表示,而不是顯示 cc
作為支付類型值:
'values' => [ 'payment_type' => [ 'cc' => '信用卡' ], ],
現(xiàn)在,如果驗(yàn)證規(guī)則失敗,它將產(chǎn)生以下消息:
當(dāng)payment type 為信用卡時(shí),credit card number不能為空。
可用驗(yàn)證規(guī)則
以下是所有可用驗(yàn)證規(guī)則及其功能的列表:
Accepted
Active URL
After (Date)
After Or Equal (Date)
Alpha
Alpha Dash
Alpha Numeric
Array
Bail
Before (Date)
Before Or Equal (Date)
Between
Boolean
Confirmed
Date
Date Equals
Date Format
Different
Digits
Digits Between
Dimensions (Image Files)
Distinct
E-Mail
Exists (Database)
File
Filled
Greater Than
Greater Than Or Equal
Image (File)
In
In Array
Integer
IP Address
JSON
Less Than
Less Than Or Equal
Max
MIME Types
MIME Type By File Extension
Min
Not In
Not Regex
Nullable
Numeric
Present
Regular Expression
Required
Required If
Required Unless
Required With
Required With All
Required Without
Required Without All
Same
Size
Starts With
String
Timezone
Unique (Database)
URL
UUID
accepted
驗(yàn)證字段必須是 yes, on, 1,或 true。這在確認(rèn)「服務(wù)條款」是否同意時(shí)相當(dāng)有用。
active_url
根據(jù) PHP 函數(shù) dns_get_record
,驗(yàn)證字段必須具有有效的 A 或 AAAA 記錄。
after:date
驗(yàn)證字段必須是給定日期之后的值。日期值將傳遞到 PHP 函數(shù) strtotime
:
'start_date' => 'required|date|after:tomorrow'
您可以指定另一個(gè)要與日期進(jìn)行比較的字段,而不是傳遞要由 strtotime
處理的日期字符串:
'finish_date' => 'required|date|after:start_date'
after_or_equal:date
驗(yàn)證字段必須是在給定日期之后或與此日期相同的值。更多信息,請參閱 after 規(guī)則。
alpha
驗(yàn)證字段必須完全由字母構(gòu)成。
alpha_dash
驗(yàn)證字段可能包含字母、數(shù)字,以及破折號 (-) 和下劃線 ( _ )。
alpha_num
驗(yàn)證字段必須是完全是字母、數(shù)字。
array
驗(yàn)證的字段必須是一個(gè) PHP 數(shù)組。
bail
在第一次驗(yàn)證失敗后停止運(yùn)行驗(yàn)證規(guī)則。
before:date
驗(yàn)證字段必須是在給定日期之前。這個(gè)日期值將會(huì)被傳遞給 PHP 的 strtotime
函數(shù)來計(jì)算。
before_or_equal:date
驗(yàn)證字段必須是在給定日期之前或與之相同的日期。這個(gè)日期值將會(huì)被傳遞給 PHP 的 strtotime
函數(shù)來計(jì)算。
between:min,max
驗(yàn)證字段的大小必須在給定的 min 和 max 之間。字符串、數(shù)字、數(shù)組和文件的計(jì)算方式都使用 size
方法。
boolean
驗(yàn)證的字段必須可以轉(zhuǎn)換為 Boolean 類型。 可接受的輸入為 true
, false
, 1
, 0
, "1"
, 和 "0"
。
confirmed
驗(yàn)證字段必須具有匹配字段 foo_confirmation
。例如,驗(yàn)證字段為 password
,輸入中必須存在與之匹配的 password_confirmation
字段。
date
根據(jù) PHP 函數(shù) strtotime
,驗(yàn)證字段必須是有效的日期。
date_equals:date
驗(yàn)證字段必須等于給定日期。日期將傳遞到 PHP 函數(shù) strtotime
。
date_format:format
驗(yàn)證字段必須匹配給定的日期格式。當(dāng)驗(yàn)證某個(gè)字段的時(shí)候,你應(yīng)該 只使用 date
或者 date_format
,而不是同時(shí)使用。
different:field
驗(yàn)證字段必須具有與 field 不同的值。
digits:value
驗(yàn)證字段必須為 numeric ,且必須具有_value_的確切長度。
digits_between:min,max
驗(yàn)證的字段的長度必須在給定的 min 和 max 之間。
dimensions
驗(yàn)證中的文件必須是圖片,并且符合指定的規(guī)則約束:
'avatar' => 'dimensions:min_width=100,min_height=200'
可用的約束為: min_width, max_width, min_height, max_height, width, height, ratio。
ratio 限制應(yīng)該表示為寬度除以高度。 這可以通過使用像 3/2
的表達(dá)式 或者一個(gè)浮點(diǎn)數(shù),像 1.5
來指定:
'avatar' => 'dimensions:ratio=3/2'
由于此規(guī)則需要多個(gè)參數(shù),你可以使用 Rule::dimensions
方法流暢地構(gòu)造規(guī)則:
use Illuminate\Validation\Rule; Validator::make($data, [ 'avatar' => [ 'required', Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2), ], ]);
distinct
當(dāng)驗(yàn)證數(shù)組時(shí),驗(yàn)證字段不得包含任何重復(fù)值。
'foo.*.id' => 'distinct'
驗(yàn)證字段必須為正確格式的電子郵件地址。
exists:table,column
驗(yàn)證字段必須存在于給定的數(shù)據(jù)庫表中。
Exists 規(guī)則基本用法
'state' => 'exists:states'
如果未指定 column
選項(xiàng),則將使用字段名稱。
指定自定義的表字段
'state' => 'exists:states,abbreviation'
有時(shí),你可能需要指定要用于「exists」查詢的特定數(shù)據(jù)庫連接。你可以使用「點(diǎn)」語法將連接名稱添加到表名稱前來完成此操作:
'email' => 'exists:connection.staff,email'
如果您想自定義驗(yàn)證規(guī)則執(zhí)行的查詢,您可以使用 Rule
類來流暢地定義規(guī)則。在下面的例子中,我們還以數(shù)組的形式指定驗(yàn)證規(guī)則,而不是使用 |
字符來分隔它們:
use Illuminate\Validation\Rule; Validator::make($data, [ 'email' => [ 'required', Rule::exists('staff')->where(function ($query) { $query->where('account_id', 1); }), ], ]);
file
驗(yàn)證的字段必須是成功上傳的文件。
filled
驗(yàn)證字段存在時(shí)不得為空。
gt:field
驗(yàn)證字段必須大于給定的 field。兩個(gè)字段必須是相同的類型。字符串、數(shù)字、數(shù)組和文件都使用 size
進(jìn)行相同的評估。
gte:field
驗(yàn)證字段必須大于或等于給定的 field。兩個(gè)字段必須是相同的類型。字符串、數(shù)字、數(shù)組和文件都使用 size
進(jìn)行相同的評估。
image
驗(yàn)證的文件必須是圖片 (jpeg, png, bmp, gif, 或 svg)
in:foo,bar,...
驗(yàn)證字段必須包含在給定的值列表中。由于此規(guī)則通常要求您 implode
數(shù)組,因此可以使用 Rule :: in
方法流暢地構(gòu)造規(guī)則:
use Illuminate\Validation\Rule; Validator::make($data, [ 'zones' => [ 'required', Rule::in(['first-zone', 'second-zone']), ], ]);
in_array:anotherfield
驗(yàn)證的字段必須存在于另一個(gè)字段 anotherfield 的值中。
integer
驗(yàn)證的字段必須是整數(shù)。
ip
驗(yàn)證的字段必須是 IP 地址。
ipv4
驗(yàn)證的字段必須是 IPv4 地址。
ipv6
驗(yàn)證的字段必須是 IPv6 地址。
json
驗(yàn)證的字段必須是有效的 JSON 字符串。
lt:field
驗(yàn)證中的字段必須小于給定的字段。這兩個(gè)字段必須是相同的類型。字符串、數(shù)值、數(shù)組和文件大小的計(jì)算方式與 size
方法進(jìn)行評估。
lte:field
驗(yàn)證中的字段必須小于或等于給定的字段。這兩個(gè)字段必須是相同的類型。字符串、數(shù)值、數(shù)組和文件大小的計(jì)算方式與 size
方法進(jìn)行評估。
max:value
驗(yàn)證中的字段必須小于或等于 value。字符串、數(shù)字、數(shù)組或是文件大小的計(jì)算方式都用 size
方法進(jìn)行評估。
mimetypes:text/plain,...
驗(yàn)證的文件必須與給定 MIME 類型之一匹配:
'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime'
要確定上傳文件的 MIME 類型,會(huì)讀取文件的內(nèi)容來判斷 MIME 類型,這可能與客戶端提供的 MIME 類型不同。
mimes:foo,bar,...
驗(yàn)證的文件必須具有與列出的其中一個(gè)擴(kuò)展名相對應(yīng)的 MIME 類型。
MIME 規(guī)則基本用法
'photo' => 'mimes:jpeg,bmp,png'
即使你可能只需要驗(yàn)證指定擴(kuò)展名,但此規(guī)則實(shí)際上會(huì)驗(yàn)證文件的 MIME 類型,其通過讀取文件的內(nèi)容以猜測它的 MIME 類型。
可以在以下鏈接中找到完整的 MIME 類型列表及其相應(yīng)的擴(kuò)展名:
https://svn.apache.org/repos/asf/httpd/htt...
min:value
驗(yàn)證中的字段必須具有最小值。字符串、數(shù)字、數(shù)組或是文件大小的計(jì)算方式都用 size
方法進(jìn)行評估。
not_in:foo,bar,...
驗(yàn)證的字段不能包含在給定的值列表中。Rule::notIn
方法可以用來構(gòu)建規(guī)則:
use Illuminate\Validation\Rule; Validator::make($data, [ 'toppings' => [ 'required', Rule::notIn(['sprinkles', 'cherries']), ], ]);
not_regex:pattern
驗(yàn)證中的字段必須與給定的正則表達(dá)式不匹配。
在內(nèi)部,此規(guī)則使用 PHP preg_match
函數(shù)。輸入的值應(yīng)遵循 preg_match
函數(shù)所需的相同格式,因此也包括有效的分隔符。例如:'email' => 'not_regex:/^.+$/i'
。
注意: 當(dāng)使用 regex
/not_regex
模式時(shí),可能需要在數(shù)組中指定規(guī)則,而不是使用管道分隔符,尤其是在正則表達(dá)式包含管道字符的情況下。
nullable
驗(yàn)證的字段可以為 null
。這在驗(yàn)證基本數(shù)據(jù)類型時(shí)特別有用,例如可以包含空值的字符串和整數(shù)。
numeric
驗(yàn)證的字段必須是數(shù)字。
present
驗(yàn)證的字段必須存在于輸入數(shù)據(jù)中,但可以為空。
regex:pattern
驗(yàn)證的字段必須與給定的正則表達(dá)式匹配。
在內(nèi)部,此規(guī)則使用 PHP preg_match
函數(shù)。輸入的值應(yīng)遵循 preg_match
函數(shù)所需的相同格式,因此也包括有效的分隔符。例如:'email' => 'regex:/^.+@.+$/i'
。
注意: 當(dāng)使用 regex
規(guī)則時(shí),你必須使用數(shù)組,而不是使用 |
分隔符,特別是如果正則表達(dá)式包含 |
字符。
required
驗(yàn)證的字段必須存在于輸入數(shù)據(jù)中,而不是空。如果滿足以下條件之一,則字段被視為「空」:
- 值為
null
。 - 值為空字符串。
- 值為空數(shù)組或空
Countable
對象。 - 值為無路徑的上傳文件。
required_if:anotherfield,value,...
如果 anotherfield 字段等于任一 value,驗(yàn)證的字段必須出現(xiàn)且不為空 。
如果你想為 required_if
規(guī)則構(gòu)造一個(gè)更復(fù)雜的條件,你可以使用 Rule::requiredIf
方法。此方法接受布爾值或閉包。當(dāng)傳遞一個(gè)閉包時(shí),應(yīng)返回 true
或 false
以確認(rèn)是否需要驗(yàn)證字段:
use Illuminate\Validation\Rule; Validator::make($request->all(), [ 'role_id' => Rule::requiredIf($request->user()->is_admin),]); Validator::make($request->all(), [ 'role_id' => Rule::requiredIf(function () use ($request) { return $request->user()->is_admin; }), ]);
required_unless:anotherfield,value,...
如果 anotherfield 字段不等于任一 value,驗(yàn)證的字段必須出現(xiàn)且不為空。
required_with:foo,bar,...
只有在其他任一指定字段出現(xiàn)時(shí),驗(yàn)證的字段才必須出現(xiàn)且不為空。
required_with_all:foo,bar,...
只有在其他指定字段全部出現(xiàn)時(shí),驗(yàn)證的字段才必須出現(xiàn)且不為空。
required_without:foo,bar,...
只在其他指定任一字段不出現(xiàn)時(shí),驗(yàn)證的字段才必須出現(xiàn)且不為空。
required_without_all:foo,bar,...
只有在其他指定字段全部不出現(xiàn)時(shí),驗(yàn)證的字段才必須出現(xiàn)且不為空。
same:field
驗(yàn)證的字段必須與給定字段匹配。
size:value
驗(yàn)證的字段必須具有與給定值匹配的大小。對于字符串,value 對應(yīng)字符數(shù)。對于數(shù)字,value 對應(yīng)給定的整數(shù)值。對于數(shù)組,size 對應(yīng)數(shù)組的 count
值。對于文件,size 對應(yīng)文件大?。▎挝?kb)。
starts_with:foo,bar,...
驗(yàn)證的字段必須以給定值之一開頭。
string
驗(yàn)證的字段必須是一個(gè)字符串。如果允許這個(gè)字段為 null
,需要給這個(gè)字段分配 nullable
規(guī)則。
timezone
驗(yàn)證的字段必須是一個(gè)基于 PHP 函數(shù) timezone_identifiers_list
的有效時(shí)區(qū)標(biāo)識。
unique:table,column,except,idColumn
驗(yàn)證的字段在給定的數(shù)據(jù)庫表中必須是唯一的。如果沒有指定 column
,將會(huì)使用字段本身的名稱。
指定自定義字段
'email' => 'unique:users,email_address'
自定義數(shù)據(jù)庫連接
有時(shí),你可能需要為驗(yàn)證程序創(chuàng)建的數(shù)據(jù)庫查詢設(shè)置自定義連接。上面的例子中,將 unique:users
設(shè)置為驗(yàn)證規(guī)則,等于使用默認(rèn)數(shù)據(jù)庫連接來查詢數(shù)據(jù)庫。如果要對其進(jìn)行修改,請使用「點(diǎn)」方法指定連接和表名:
'email' => 'unique:connection.users,email_address'
強(qiáng)迫 Unique 規(guī)則忽略指定 ID :
有時(shí),你可能希望在進(jìn)行字段唯一性驗(yàn)證時(shí)忽略指定 ID 。例如, 在「更新個(gè)人資料」頁面會(huì)包含用戶名、郵箱和地點(diǎn)。這時(shí)你會(huì)想要驗(yàn)證更新的 E-mail 值是否唯一。如果用戶僅更改了用戶名字段而沒有改 E-mail 字段,就不需要拋出驗(yàn)證錯(cuò)誤,因?yàn)榇擞脩粢呀?jīng)是這個(gè) E-mail 的擁有者了。
使用 Rule
類定義規(guī)則來指示驗(yàn)證器忽略用戶的 ID。這個(gè)例子中通過數(shù)組來指定驗(yàn)證規(guī)則,而不是使用 | 字符來分隔:
use Illuminate\Validation\Rule; Validator::make($data, [ 'email' => [ 'required', Rule::unique('users')->ignore($user->id), ], ]);
{tip} 您永遠(yuǎn)不應(yīng)將任何用戶控制的請求輸入傳遞給
ignore
方法。相反,您應(yīng)該只從 Eloquent 模型實(shí)例傳遞系統(tǒng)生成的唯一 ID,例如自增 ID 或 UUID。否則,您的應(yīng)用程序?qū)⑷菀资艿?SQL 注入攻擊。
你可以傳遞整個(gè)模型實(shí)例,而不是將模型鍵的值傳遞給 ignore
方法。Laravel 將自動(dòng)從模型中提取主鍵:
Rule::unique('users')->ignore($user)
如果你的數(shù)據(jù)表使用的主鍵名稱不是 id
,那就在調(diào)用 ignore
方法時(shí)指定字段的名稱:
Rule::unique('users')->ignore($user->id, 'user_id')
默認(rèn)情況下,unique
規(guī)則將檢查與要驗(yàn)證的屬性的名稱匹配的列是否唯一。但是你可以將不同的列名稱作為第二個(gè)參數(shù)傳遞給 unique
方法:
Rule::unique('users', 'email_address')->ignore($user->id),
增加額外的 Where 語句:
你也可以通過 where
方法指定額外的查詢條件。例如, 我們添加 account_id
為 1
的約束:
'email' => Rule::unique('users')->where(function ($query) { return $query->where('account_id', 1); })
url
驗(yàn)證的字段必須是有效的 URL。
uuid
驗(yàn)證字段必須是有效的 RFC 4122(版本 1,3,4 或 5)通用唯一標(biāo)識符(UUID)。
按條件增加規(guī)則
存在時(shí)則驗(yàn)證
在某些情況下,只有在該字段存在于數(shù)組中時(shí), 才可以對字段執(zhí)行驗(yàn)證檢查??赏ㄟ^增加 sometimes
到規(guī)則列表來實(shí)現(xiàn):
$v = Validator::make($data, [ 'email' => 'sometimes|required|email',]);
在上面的例子中, email
字段只有在 $data
數(shù)組中存在才會(huì)被驗(yàn)證。
{tip} 如果你嘗試驗(yàn)證應(yīng)該始終存在但可能為空的字段,請查閱 可選字段的注意事項(xiàng)
復(fù)雜的條件驗(yàn)證
有時(shí)候你可能需要增加基于更復(fù)雜的條件邏輯的驗(yàn)證規(guī)則。例如,你可以希望某個(gè)指定字段在另一個(gè)字段的值超過 100 時(shí)才為必填。或者當(dāng)某個(gè)指定字段存在時(shí),另外兩個(gè)字段才能具有給定的值。增加這樣的驗(yàn)證條件并不難。首先,使用 靜態(tài)規(guī)則 創(chuàng)建一個(gè) Validator
實(shí)例:
$v = Validator::make($data, [ 'email' => 'required|email', 'games' => 'required|numeric', ]);
假設(shè)我們有一個(gè)專為游戲收藏家所設(shè)計(jì)的網(wǎng)頁應(yīng)用程序。如果游戲收藏家收藏超過一百款游戲,我們會(huì)希望他們來說明下為什么他們會(huì)擁有這么多游戲。比如說他們有可能經(jīng)營了一家游戲分銷商店,或者只是為了享受收集的樂趣。為了在特定條件下加入此驗(yàn)證需求,可以在 Validator
實(shí)例中使用 sometimes
方法。
$v->sometimes('reason', 'required|max:500', function ($input) { return $input->games >= 100; });
傳入 sometimes
方法的第一個(gè)參數(shù)是要用來驗(yàn)證的字段名稱。第二個(gè)參數(shù)是我們想使用的驗(yàn)證規(guī)則。 閉包
作為第三個(gè)參數(shù)傳入,如果其返回 true
, 則額外的規(guī)則就會(huì)被加入。這個(gè)方法可以輕松地創(chuàng)建復(fù)雜的條件驗(yàn)證。你甚至可以一次對多個(gè)字段增加條件驗(yàn)證:
$v->sometimes(['reason', 'cost'], 'required', function ($input) { return $input->games >= 100; });
{tip} 傳入
閉包
的$input
參數(shù)是Illuminate\Support\Fluent
的一個(gè)實(shí)例,可用來訪問你的輸入或文件對象。
驗(yàn)證數(shù)組
驗(yàn)證表單的輸入為數(shù)組的字段也不難。你可以使用 「點(diǎn)」方法來驗(yàn)證數(shù)組中的屬性。例如,如果傳入的 HTTP 請求中包含 photos[profile]
字段, 可以如下驗(yàn)證:
$validator = Validator::make($request->all(), [ 'photos.profile' => 'required|image', ]);
你也可以驗(yàn)證數(shù)組中的每個(gè)元素。例如,要驗(yàn)證指定數(shù)組輸入字段中的每一個(gè) email 是唯一的,可以這么做:
$validator = Validator::make($request->all(), [ 'person.*.email' => 'email|unique:users', 'person.*.first_name' => 'required_with:person.*.last_name', ]);
同理,你可以在語言文件定義驗(yàn)證信息時(shí)使用 *
字符,為基于數(shù)組的字段使用單個(gè)驗(yàn)證消息:
'custom' => [ 'person.*.email' => [ 'unique' => 'Each person must have a unique e-mail address', ] ],
自定義驗(yàn)證規(guī)則
使用規(guī)則對象
Laravel 提供了許多有用的驗(yàn)證規(guī)則;同時(shí)也支持自定義規(guī)則。注冊自定義驗(yàn)證規(guī)則的方法之一,就是使用規(guī)則對象。可以使用 Artisan 命令 make:rule
來生成新的規(guī)則對象。接下來,讓我們用這個(gè)命令生成一個(gè)驗(yàn)證字符串是大寫的規(guī)則。Laravel 會(huì)將新的規(guī)則存放在 app/Rules
目錄中:
php artisan make:rule Uppercase
一旦創(chuàng)建了規(guī)則,我們就可以定義它的行為。規(guī)則對象包含兩個(gè)方法: passes
和 message
。passes
方法接收屬性值和名稱,并根據(jù)屬性值是否符合規(guī)則而返回 true
或 false
。 message
方法應(yīng)返回驗(yàn)證失敗時(shí)應(yīng)使用的驗(yàn)證錯(cuò)誤消息:
<?php namespace App\Rules; use Illuminate\Contracts\Validation\Rule; class Uppercase implements Rule{ /** * 判斷驗(yàn)證規(guī)則是否通過。 * * @param string $attribute * @param mixed $value * @return bool */ public function passes($attribute, $value) { return strtoupper($value) === $value; } /** * 獲取驗(yàn)證錯(cuò)誤消息。 * * @return string */ public function message() { return 'The :attribute must be uppercase.'; } }
當(dāng)然, 如果你希望從翻譯文件中返回一個(gè)錯(cuò)誤消息,你可以從 message
方法中調(diào)用輔助函數(shù) trans
:
/** * 獲取驗(yàn)證錯(cuò)誤消息。 * * @return string */ public function message(){ return trans('validation.uppercase'); }
一旦規(guī)則對象被定義好后,你可以通過將規(guī)則對象的實(shí)例和其他驗(yàn)證規(guī)則一起來傳遞給驗(yàn)證器:
use App\Rules\Uppercase;$request->validate([ 'name' => ['required', 'string', new Uppercase], ]);
使用閉包
如果你在應(yīng)用程序中只需要一次自定義規(guī)則的功能,則可以使用閉包而不是規(guī)則對象。閉包接收屬性的名稱,屬性的值如果驗(yàn)證失敗則應(yīng)該使用回調(diào)中的 $fail
:
$validator = Validator::make($request->all(), [ 'title' => [ 'required', 'max:255', function ($attribute, $value, $fail) { if ($value === 'foo') { $fail($attribute.' is invalid.'); } }, ], ]);
使用擴(kuò)展
注冊自定義的驗(yàn)證規(guī)則的另一種方法是使用 Validator
facade 中的 extend
方法。讓我們在 服務(wù)容器 中使用這個(gè)方法來注冊自定義驗(yàn)證規(guī)則:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Validator; class AppServiceProvider extends ServiceProvider{ /** * 引導(dǎo)任何應(yīng)用程序。 * * @return void */ public function boot() { Validator::extend('foo', function ($attribute, $value, $parameters, $validator) { return $value == 'foo'; }); } /** * 注冊服務(wù)提供器。 * * @return void */ public function register() { // } }
自定義的驗(yàn)證閉包接收四個(gè)參數(shù):要被驗(yàn)證的屬性名稱 $attribute
、屬性的值 $value
、傳入驗(yàn)證規(guī)則的參數(shù)數(shù)組 $parameters
、以及 Validator
實(shí)列。
除了使用閉包,你也可以傳入類和方法到 extend
方法中:
Validator::extend('foo', 'FooValidator@validate');
定義錯(cuò)誤消息
你還需要為自定義規(guī)則定義錯(cuò)誤信息。你可以使用內(nèi)聯(lián)自定義消息數(shù)組或者在驗(yàn)證語言文件中添加條目來實(shí)現(xiàn)這一功能。 消息應(yīng)該被放到數(shù)組的第一位, 而不是在只用于存放屬性指定錯(cuò)誤信息的 custom
數(shù)組內(nèi):
"foo" => "Your input was invalid!", "accepted" => "The :attribute must be accepted.", // 其余的驗(yàn)證錯(cuò)誤消息...
當(dāng)創(chuàng)建一個(gè)自定義驗(yàn)證規(guī)則時(shí),你可能有時(shí)候需要為錯(cuò)誤信息定義自定義占位符??梢酝ㄟ^創(chuàng)建自定義驗(yàn)證器然后調(diào)用 Validator
門面上的 replacer
方法。你可以在 服務(wù)容器 的 boot
方法中執(zhí)行如下操作:
/** * 啟動(dòng)應(yīng)用程序。 * * @return void */ public function boot(){ Validator::extend(...); Validator::replacer('foo', function ($message, $attribute, $rule, $parameters) { return str_replace(...); }); }
隱式擴(kuò)展
默認(rèn)情況下, 當(dāng)所要驗(yàn)證的屬性不存在或包含由 required
規(guī)則定義的空值時(shí),那么正常的驗(yàn)證規(guī)則,包括自定義擴(kuò)展將不會(huì)執(zhí)行。 例如,unique
規(guī)則將不會(huì)檢驗(yàn) null
值:
$rules = ['name' => 'unique']; $input = ['name' => null]; Validator::make($input, $rules)->passes(); // true
如果要求即使為空時(shí)也要驗(yàn)證屬性,則必須要暗示屬性是必須的。要?jiǎng)?chuàng)建這樣一個(gè)「隱式」擴(kuò)展, 可以使用 Validator::extendImplicit()
方法:
Validator::extendImplicit('foo', function ($attribute, $value, $parameters, $validator) { return $value == 'foo'; });
{note} 「隱式」擴(kuò)展只暗示該屬性是必需的。至于它到底是缺失的還是空值這取決于你。