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