驗(yàn)證
簡(jiǎn)介
Laravel 對(duì)驗(yàn)證應(yīng)用的輸入數(shù)據(jù)提供了多中途徑的實(shí)現(xiàn)。默認(rèn)的,Laravel 的基礎(chǔ)控制器類使用了 ValidatesRequests
trait,該性狀允許使用各種強(qiáng)大的驗(yàn)證約束來(lái)驗(yàn)證 HTTP 的輸入請(qǐng)求。
快速入門
要了解 Laravel 強(qiáng)大的驗(yàn)證功能,我們需要一個(gè)完整的示例來(lái)描述表單的驗(yàn)證,和將表單驗(yàn)證的錯(cuò)誤信息顯示給用戶。
定義路由
首先,讓我們假定我們?cè)?app/Http/routes.php
文件中擁有下述的路由:
// Display a form to create a blog post...
Route::get('post/create', 'PostController@create');
// Store a new blog post...
Route::post('post', 'PostController@store');
當(dāng)然, GET
路由會(huì)為用戶創(chuàng)建一個(gè)新的博客文章時(shí)提供一個(gè)表單,而 POST
路由會(huì)存儲(chǔ)新的博客文章到數(shù)據(jù)庫(kù)。
創(chuàng)建控制器
接著,我們需要一個(gè)控制器來(lái)處理這些路由,目前,我們先不在 store
方法里放任何的邏輯:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* Show the form to create a new blog post.
*
* @return Response
*/
public function create()
{
return view('post.create');
}
/**
* Store a new blog post.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
// Validate and store the blog post...
}
}
編寫驗(yàn)證邏輯
現(xiàn)在我們準(zhǔn)備好了在 store
方法中進(jìn)行博客文章的驗(yàn)證邏輯。如果你檢查應(yīng)用的基礎(chǔ)控制器(App\Http\Controllers\Controller
) 類,你會(huì)發(fā)現(xiàn)該類使用了 ValidatesRequests
trait。這個(gè)性狀為所有的控制器提供了方便的 validate
方法。
validate
方法接收 HTTP 輸入請(qǐng)求,并設(shè)置驗(yàn)證約束。如果驗(yàn)證約束通過(guò),那么后續(xù)的代碼將會(huì)正常的執(zhí)行。如果驗(yàn)證失敗,那么將會(huì)拋出一個(gè)恰當(dāng)?shù)漠惓m憫?yīng)返回給用戶。對(duì)于傳統(tǒng)的 HTTP 請(qǐng)求,驗(yàn)證器會(huì)自動(dòng)生成一個(gè)重定向響應(yīng),而 AJAX 請(qǐng)求,則會(huì)返回 JSON 響應(yīng)。
為了能夠更好的理解 validate
方法,讓我們繼續(xù)回到 store
方法:
/**
* Store a new blog post.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// The blog post is valid, store in database...
}
就如你所看到的,我們簡(jiǎn)單的傳遞了一個(gè) HTTP 輸入請(qǐng)求,并且在 validate
方法中設(shè)置了預(yù)期的驗(yàn)證約束。而這次,如果驗(yàn)證失敗,那么相應(yīng)的響應(yīng)會(huì)被自動(dòng)的生成并且被返回給請(qǐng)求用戶。如果驗(yàn)證通過(guò),那么我們的控制器會(huì)繼續(xù)執(zhí)行之后的業(yè)務(wù)。
在初次驗(yàn)證失敗時(shí)停止
有時(shí)候你希望在獲取首個(gè)驗(yàn)證約束失敗時(shí)停止當(dāng)前屬性其余約束的驗(yàn)證。你可以在屬性中加入 bail
約束:
$this->validate($request, [
'title' => 'bail|required|unique:posts|max:255',
'body' => 'required',
]);
在這個(gè)例子中,如果 title
屬性中的 required
約束驗(yàn)證失敗,那么 unique
約束就不會(huì)再被驗(yàn)證。約束是按照其被分配的順序來(lái)進(jìn)行驗(yàn)證的。
嵌套的屬性
如果你的 HTTP 請(qǐng)求包含了嵌套的參數(shù),你可以使用 .
語(yǔ)法來(lái)為其指定約束:
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);
顯示驗(yàn)證錯(cuò)誤
那么,假如傳入的請(qǐng)求參數(shù)并沒(méi)有通過(guò)給定約束的驗(yàn)證怎么辦?就如前面所提到的,Laravel 會(huì)自動(dòng)的重定向用戶到之前的位置。另外,所有的驗(yàn)證錯(cuò)誤信息都會(huì)被自動(dòng)的閃存到 session 中。
你需要注意到我們并沒(méi)有明確的綁定錯(cuò)誤信息到 GET
路由的響應(yīng)視圖里。這是因?yàn)?laravel 會(huì)檢查閃存 seesion 里的錯(cuò)誤數(shù)據(jù),并且會(huì)自動(dòng)的在其可用時(shí)注入到視圖中。你可以在視圖中使用 $errors
變量,它是一個(gè) Illuminate\Support\MessageBag
實(shí)例。如果需要了解更多這個(gè)實(shí)例對(duì)象,請(qǐng)參考其 文檔。
注意:
$errors
變量是通過(guò)Illuminate\View\Middleware\ShareErrorsFromSession
中間件來(lái)綁定到視圖中的。這個(gè)中間件已經(jīng)被提供到了web
中間件組中。這個(gè)中間件被應(yīng)用時(shí)會(huì)自主的在你的視圖中注入$errors
變量,這允許你方便的假定$errors
變量總是已經(jīng)被定義且可以安全的使用。
所以,在我們的例子中,當(dāng)驗(yàn)證失敗是,用戶將會(huì)被重定向到控制器的 create
方法中,這允許你在視圖中展示錯(cuò)誤信息:
<!-- /resources/views/post/create.blade.php -->
<h1>Create Post</h1>
@if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- Create Post Form -->
自定義閃存錯(cuò)誤格式
如果你希望在驗(yàn)證失敗時(shí)可以自定義閃存進(jìn) session 中的錯(cuò)誤消息的格式,你需要在你的基礎(chǔ)控制器中復(fù)寫 formatValidationErrors
方法。不要忘記在頂部引入 Illuminate\Contracts\Validation\Validator
類:
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
abstract class Controller extends BaseController
{
use DispatchesJobs, ValidatesRequests;
/**
* {@inheritdoc}
*/
protected function formatValidationErrors(Validator $validator)
{
return $validator->errors()->all();
}
}
AJAX 請(qǐng)求 & 驗(yàn)證
在上面的示例中,我們使用傳統(tǒng)的表單來(lái)發(fā)送數(shù)據(jù)到應(yīng)用,事實(shí)上,如今很多應(yīng)用都使用 AJAX 請(qǐng)求,當(dāng)通過(guò) AJAX 請(qǐng)求來(lái)使用 validate
方法時(shí),laravel 并不會(huì)自動(dòng)生成重定向的響應(yīng),相反的,laravel 會(huì)生成一個(gè)包含了驗(yàn)證錯(cuò)誤消息的 JSON 響應(yīng)。并且該響應(yīng)會(huì)伴隨 422 HTTP 狀態(tài)碼。
驗(yàn)證數(shù)組
驗(yàn)證數(shù)組形式的輸入并不是一件痛苦的事情。比如,去驗(yàn)證給定的輸入數(shù)組中所有的郵件都應(yīng)該是唯一的,你可以參照如下做法:
$validator = Validator::make($request->all(), [
'person.*.email' => 'email|unique:users',
'person.*.first_name' => 'required_with:person.*.last_name',
]);
同樣的,你也可以在使用語(yǔ)言文件來(lái)指定特定的驗(yàn)證消息時(shí)使用 *
通配符。這可以輕而易舉的使用單條驗(yàn)證消息提供給基于數(shù)組的輸入:
'custom' => [
'person.*.email' => [
'unique' => 'Each person must have a unique e-mail address',
]
]
其它驗(yàn)證途徑
手動(dòng)的創(chuàng)建 Validators
如果你不喜歡使用 ValidatesRequests
trait 的 validator
方法,你也可以通過(guò)使用 Validator
假面來(lái)創(chuàng)建一個(gè) validator 實(shí)例。Validator
假面的 make
方法就可以生成一個(gè)新的 validator 實(shí)例:
<?php
namespace App\Http\Controllers;
use Validator;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* Store a new blog post.
*
* @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ù)則是應(yīng)該施加到數(shù)據(jù)的驗(yàn)證約束。
如果請(qǐng)求的驗(yàn)證失敗,那么你需要使用 withErrors
方法來(lái)講錯(cuò)誤消息存放到 session 中。當(dāng)使用該方法時(shí),$errors
變量會(huì)在重定向之后被自動(dòng)的共享到你的視圖中,這使你可以輕松的將錯(cuò)誤信息展示給用戶。withErrors
方法可以接收 validator 實(shí)例,或者 MessageBag
實(shí)例,又或者原生的 PHP array
。
被命名的錯(cuò)誤袋
如果你在一個(gè)獨(dú)立頁(yè)面中包含了多個(gè)表單。那么你可能會(huì)希望能對(duì) MessageBag
進(jìn)行命名以展示相應(yīng)的表單錯(cuò)誤。你可以直接在 withErrors
方法中傳遞第二個(gè)參數(shù)對(duì)其進(jìn)行命名:
return redirect('register')
->withErrors($validator, 'login');
你之后可以通過(guò) $errors
變量來(lái)訪問(wèn)被命名的 MessageBag
實(shí)例:
{{ $errors->login->first('email') }}
驗(yàn)證之后的 Hook
驗(yàn)證器也允許你在驗(yàn)證完成之后執(zhí)行特定的操作。這允許你輕松的進(jìn)行進(jìn)一步的驗(yàn)證,你也可以在消息集合里添加更多的錯(cuò)誤消息。在驗(yàn)證器的實(shí)例上使用 after
方法來(lái)進(jìn)行 hook:
$validator = Validator::make(...);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->ad('field', 'Something is wrong with this field!');
}
});
if ($validator->fails()) {
//
}
表單請(qǐng)求驗(yàn)證
對(duì)于更為復(fù)雜的驗(yàn)證場(chǎng)景,你或許希望構(gòu)建一個(gè)“表單請(qǐng)求”。表單請(qǐng)求是一個(gè)自定義的請(qǐng)求類,并且它包含了所有的驗(yàn)證邏輯。你可以使用 make:request
Artisan CLI 命令來(lái)創(chuàng)建一個(gè)表單請(qǐng)求類:
php artisan make:request StoreBlogPostRequest
被生成的類會(huì)被存儲(chǔ)在 app/Http/Requests
目錄。讓我們?cè)?rules
方法中來(lái)添加一些驗(yàn)證約束:
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
那么,這些驗(yàn)證約束是如何被評(píng)定的?你所要做的所有的事情就是在你的控制器方法中添加該請(qǐng)求類的類型提示。傳入進(jìn)來(lái)的表單請(qǐng)求會(huì)在控制器方法調(diào)用之前被自動(dòng)的進(jìn)行約束驗(yàn)證,這意味著你完全不需要再你的控制器方法中添加任何的驗(yàn)證邏輯:
/**
* Store the incoming blog post.
*
* @param StoreBlogPostRequest $request
* @return Response
*/
public function store(StoreBlogPostRequest $request)
{
// The incoming request is valid...
}
如果驗(yàn)證失敗,用戶會(huì)被自動(dòng)的重定向到他們之前的位置。那么驗(yàn)證錯(cuò)誤消息也會(huì)自動(dòng)的閃存進(jìn) session 數(shù)據(jù)中被用于顯示。如果你使用的是 AJAX 請(qǐng)求,那么會(huì)自動(dòng)的返回一個(gè)包含所有驗(yàn)證錯(cuò)誤消息的 JSON 格式的響應(yīng),它的 HTTP 狀態(tài)碼會(huì)被設(shè)置為 422。
授權(quán)表單請(qǐng)求
表單請(qǐng)求類也包含了 authorize
方法。在這個(gè)方法中,你可以檢查已認(rèn)證的用戶是否真的擁有修改所給定資源的權(quán)利。比如,如果用戶嘗試修改博客文章中的評(píng)論消息,我們需要考慮一下這個(gè)評(píng)論是屬于他的嗎:
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
$commentId = $this->route('comment');
return Comment::where('id', $commentId)
->where('user_id', Auth::id())->exists();
}
你應(yīng)該注意到了上述實(shí)例中的 route
方法的調(diào)用。這個(gè)方法用來(lái)在路由被訪問(wèn)時(shí)發(fā)放所定義的 URL 參數(shù),比如下面路由的 {comment}
參數(shù):
Route::post('comment/{comment}');
如果 authorize
方法返回 false
,那么會(huì)響應(yīng)一個(gè) 403 的狀態(tài)碼,并且控制器的方法不會(huì)被執(zhí)行。
如果你計(jì)劃在應(yīng)用的其它部分來(lái)處理授權(quán)邏輯,你可以簡(jiǎn)單的在 authorize
方法中返回 true
:
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
自定義閃存的錯(cuò)誤格式
如果你希望在驗(yàn)證失敗時(shí)自定義閃存到 session 數(shù)據(jù)中驗(yàn)證錯(cuò)誤消息的格式,那么你需要復(fù)寫(App\Http\Requests\Request
)基礎(chǔ)請(qǐng)求類中的 formatErros
方法。不要忘記引入 Illuminate\Contracts\Validation\Validator
類:
/**
* {@inheritdoc}
*/
protected function formatErrors(Validator $validator)
{
return $validator->errors()->all();
}
自定義錯(cuò)誤消息
你也可以通過(guò)在請(qǐng)求類中復(fù)寫 messages
方法來(lái)自定義錯(cuò)誤消息。該方法應(yīng)該返回一個(gè)包含相應(yīng)錯(cuò)誤消息的鍵值對(duì)數(shù)組:
/**
* Get the error messages for the defined validation rules.
*
* @return array
*/
public function message()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
與錯(cuò)誤消息協(xié)作
在調(diào)用 Validator
實(shí)例的 errors
方法之后,你可以檢索到一個(gè) Illuminate\Support\MessageBag
的實(shí)例,這實(shí)例擁有多種便捷的方法來(lái)與錯(cuò)誤消息進(jìn)行交互。
檢索給定字段中的首個(gè)錯(cuò)誤消息
你可以使用 first
方法來(lái)檢索給定字段的首個(gè)錯(cuò)誤消息:
$message = $validator->errors();
echo $message->first('email');
檢索給定字段的所有錯(cuò)誤消息
如果你需要檢索給定字段的所有消息所組成的數(shù)組,那么你應(yīng)該使用 get
方法:
foreach ($messages->get('email') as $message) {
//
}
檢索所有字段的所有錯(cuò)誤消息
你可以使用 all
方法來(lái)檢索所有字段的所有錯(cuò)誤消息所組成的數(shù)組:
foreach ($message->all() as $message) {
//
}
判斷所給定的字段中是否存在消息
if ($messages->has('email')) {
//
}
使用給定的格式來(lái)檢索獲取錯(cuò)誤消息
echo $message->first('email', '<p>:message</p>');
使用給定的格式來(lái)檢索所有的錯(cuò)誤消息
foreach ($messages->all('<li>:message</li>') as $message) {
//
}
自定義錯(cuò)誤消息
如果你需要,你可以使用自定義的錯(cuò)誤消息來(lái)取代默認(rèn)的驗(yàn)證消息。這里有幾種方式來(lái)指定自定義的消息。首先,你可以傳遞自定的消息作為 Validator::make
方法的第三個(gè)參數(shù):
$messages = [
'required' => 'The :attribute field is required.',
];
$validator = Validator::make($input, $rules, $messages);
在這個(gè)例子中,:attribute
占位符會(huì)被驗(yàn)證數(shù)據(jù)中真實(shí)的名稱所替換。你還可以利用其它的占位符到驗(yàn)證消息中,比如:
$message = [
'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',
];
為給定的屬性指定錯(cuò)誤消息
有時(shí)候,你可能希望指定自定義的錯(cuò)誤消息到特定的字段。你可以使用 .
符號(hào)來(lái)進(jìn)行分割,屬性名應(yīng)該在前,約束應(yīng)該在后:
$message = [
'email.required' => 'We need to know your e-mail address!',
];
在語(yǔ)言文件中指定自定義消息
在多數(shù)情況下,你可能希望使用一個(gè)語(yǔ)言文件中的自定義消息屬性直接傳遞到 Validator
。你可以在 resources/lang/xx/validation.php
語(yǔ)言文件中添加 custom
數(shù)組來(lái)存儲(chǔ)你的消息:
'custom' => [
'email' => [
'required' => 'We need to know your e-mail address!',
],
],
可用的驗(yàn)證約束
下面是所有的可用的驗(yàn)證約束和它們的功能的列表:
accepted
驗(yàn)證的字段必須為 yes,on,1,或者 true。這通常用來(lái)驗(yàn)證服務(wù)條款的承諾。
active_url
驗(yàn)證的字段必須可以通過(guò) checkdnsrr
PHP 方法的驗(yàn)證。
after:date
驗(yàn)證的字段必須是給定日期之后的值。日期會(huì)被傳遞到 strtotime
PHP 方法:
`start_date' => 'required|date|after:tomorrow'
你也可以指定使用其它字段的日期來(lái)進(jìn)行評(píng)估:
'finish_date' => 'required|date|after:start_date'
alpha
驗(yàn)證的字段必須全部是由字母字符組成的字符串。
alpha_dash
驗(yàn)證的字段可以是字母,數(shù)字,-,_ 所組成的字符串。
alpha_num
驗(yàn)證的字段必須全部由字母或數(shù)字所組成。
array
驗(yàn)證的字段必須是一個(gè) PHP array
。
before:date
驗(yàn)證的字段的值必須比指定的日期要早。指定的日期會(huì)被傳遞到 PHP 的 strtotime
方法。
between:min,max
驗(yàn)證的字段的大小必須在給定的 min 和 max 之間。字符串,數(shù)字和文件都會(huì)使用和 size
約束的相同的評(píng)估方式。
boolean
驗(yàn)證的字段必須能夠轉(zhuǎn)換為布爾值。所接受的輸入可以是 true
,false
,1
,0
,"1"
,"0"
。
confirmed
驗(yàn)證的字段必須能夠和 foo_confirmation
字段相匹配。比如,如果驗(yàn)證的字段是 password
,相應(yīng)的 password_confirmation
字段必須在輸入中被提供且與 password
相匹配。
date
驗(yàn)證的字段必須是一個(gè)有效的日期,它應(yīng)該能被 strtotime
PHP 方法通過(guò)。
date_format:format
驗(yàn)證的字段必須匹配給定的格式。該格式會(huì)被 PHP date_parse_from_format
方法評(píng)定,你應(yīng)該只使用 date
或者 date_format
其中之一來(lái)進(jìn)行驗(yàn)證字段,不要全部都使用。
different:field
驗(yàn)證的字段必須與給定的字段不同。
digits:value
驗(yàn)證的字段必須是數(shù)字類型并且具有指定的長(zhǎng)度。
digits_between:min,max
驗(yàn)證的字段必須具有指定區(qū)間的長(zhǎng)度。
dimensions
驗(yàn)證的字段必須是一個(gè)圖片類型的,并且要求符合指定的參數(shù)約束:
'avatar' => 'dimensions:min_with=100,min_height=200'
可用的參數(shù)有:min_width,max_width,min_height,max_height,width,height,ratio。
distinct
當(dāng)與數(shù)組協(xié)作時(shí),驗(yàn)證的字段中必須不能含有重復(fù)的值:
'foo.*.id' => 'distinct'
驗(yàn)證的字段必須是一個(gè)郵件地址的格式。
exists:table,column
驗(yàn)證的字段必須能在指定數(shù)據(jù)庫(kù)表中檢索的到。
Exists 基礎(chǔ)約束用法
'state' => 'exists:states'
指定自定義列名稱
'state' => 'exists:states,abbreviation'
你也可以像使用 where
語(yǔ)句一樣指定添加更多的查詢條件:
'email' => 'exists:staff,email,account_id,1'
查詢條件也可以使用 !
來(lái)表明否定值:
'eamil' => 'exists:staff,email,role,!admin'
你也可以傳遞 NULL
或者 NOT_NULL
到查詢語(yǔ)句中:
'eamil' => 'exists:staff,email,deleted_at,NULL'
'eamil' => 'exists:staff,email,deleted_at,NOT_NULL'
極個(gè)別的情況下,你可能需要在 exists
查詢下指定特定的數(shù)據(jù)庫(kù)連接。你可以使用 .
語(yǔ)法將數(shù)據(jù)庫(kù)連接名前置來(lái)進(jìn)行指定:
'email' => 'exists:connection.staff,email'
filled
驗(yàn)證的字段如果出現(xiàn),那么它一定不能為空值。
image
被驗(yàn)證的文件必須是一個(gè)圖片類型(jpeg,png,bmp,gif,svg)
in:foo,bar,...
驗(yàn)證的字段必須是給定值列中的一個(gè)。
in_array:anotherfield
驗(yàn)證的字段必須是指定的字段中值列之一。
integer
驗(yàn)證的字段必須是一個(gè)整數(shù)。
ip
驗(yàn)證的字段必須是一個(gè) IP 地址。
json
驗(yàn)證的字段必須是合法的 JSON 字符串
max:value
驗(yàn)證的字段必須小于等于指定值。字符串,數(shù)字,和文件類型會(huì)與 size
約束使用相同的評(píng)估方法。
mimetypes:text/plain,...
驗(yàn)證的字段必須匹配給定的 MIME 類型:
'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime'
為了判斷所上傳文件的 MIME 類型,laravel 會(huì)讀取文件的內(nèi)容并且會(huì)嘗試猜測(cè)文件的 MIME 類型,這可能會(huì)與客戶端提供的文件 MIME 類型有所區(qū)別。
mimes:foo,bar,...
驗(yàn)證的文件的 MIME 類型相應(yīng)的后綴必須是所列的值之一。
基礎(chǔ)用法
'photo' => 'mimes:jpeg,bmp,png'
你只需要指定文件的擴(kuò)展,這個(gè)約束會(huì)針對(duì)文件的內(nèi)容進(jìn)行猜測(cè)文件的 MIME 類型,然后進(jìn)行擴(kuò)展驗(yàn)證。
完整的 MIME 類型和其相應(yīng)的擴(kuò)展后綴,你可以從 這里 找到。
min:value
驗(yàn)證的字段必須比指定的值要小。字符串,數(shù)字和文件類型會(huì)使用 size
約束相同的評(píng)估方法。
not_in:foo,bar,...
驗(yàn)證的字段不應(yīng)該包含在給定的值列中。
numeric
驗(yàn)證的字段必須是一個(gè)數(shù)值類型。
present
驗(yàn)證的字段必須要求被提供,但是可以為空。
regex:pattern
驗(yàn)證的字段必須與給定的正則表達(dá)式相匹配。
注意:當(dāng)使用
regex
模式時(shí),你必須將約束放進(jìn)數(shù)組里來(lái)取代管道符分隔,特別是在正則表達(dá)式中包含管道符時(shí)。
required
驗(yàn)證的字段必須被提供并且不能為空值。判斷空值的依據(jù):
- 值是
null
- 值是空字符串
- 值是一個(gè)空數(shù)組或者空的
Countable
對(duì)象 - 值是一個(gè)沒(méi)有傳遞路徑的上傳的文件
required_if:anotherfield,value,...
驗(yàn)證的字段必須在以下情況下被提供:指定的字段等于任意列出的值。
required_unless:anotherfield,value,...
驗(yàn)證的字段必須在以下情況下被提供: 所指定的字段和所提供的值都不相等。
required_with:foo,bar,...
驗(yàn)證的字段只有在其它所指定字段之一被提供時(shí)才會(huì)被要求提供。
required_with_all:foo,bar,...
驗(yàn)證的字段只有在其它所指定字段全部被提供時(shí)才會(huì)被要求提供。
required_without:foo,bar,...
驗(yàn)證的字段只有在其它所指定字段之一沒(méi)有被提供時(shí)被要求提供。
required_without_all:foo,bar,...
驗(yàn)證的字段只有在所指定字段全部沒(méi)有被提供時(shí)才會(huì)被要求提供。
same:field
所驗(yàn)證的字段必須與指定的字段相匹配。
size:value
驗(yàn)證的字段必須具有給定值的大小。對(duì)于字符串?dāng)?shù)據(jù),值應(yīng)該是字符串的字符長(zhǎng)度。對(duì)于數(shù)值數(shù)據(jù),值應(yīng)該是相應(yīng)的整數(shù)值。對(duì)于數(shù)組,大小匹配數(shù)組的 count
大小。對(duì)于文件,應(yīng)該匹配文件的字節(jié)大小。
string
驗(yàn)證的字段必須是一個(gè)字符串。
timezone
驗(yàn)證的字段必須是經(jīng)過(guò) PHP timezone_identifiers_list
方法驗(yàn)證的合法的 timezone 標(biāo)識(shí)。
unique:table,column,except,idColumn
驗(yàn)證的字段必須在給定的數(shù)據(jù)表中唯一,如果 column
選型沒(méi)有被指定,那么會(huì)直接使用字段的名字。
指定自定義的列名
'email' => 'unique:users,email_address'
自定義數(shù)據(jù)庫(kù)連接
極少數(shù)情況下,你可能需要指定自定義的數(shù)據(jù)庫(kù)連接來(lái)進(jìn)行驗(yàn)證。就如上面所看到的,設(shè)置 unique:users
會(huì)使用默認(rèn)的數(shù)據(jù)庫(kù)連接來(lái)進(jìn)行約束驗(yàn)證。如果想指定其他數(shù)據(jù)庫(kù)連接,你可以使用 .
語(yǔ)法并前置指定數(shù)據(jù)庫(kù)連接:
'email' => 'unique:connection.users,email_address'
強(qiáng)迫 Unique 約束 忽略給定的 ID
有時(shí)候,你可能會(huì)希望 unique 檢查忽略給定的 ID。比如,考慮一下一個(gè)更新個(gè)人信息的場(chǎng)景,它應(yīng)該提供用戶的名稱,郵箱地址,和位置。你可能會(huì)想要驗(yàn)證郵箱的唯一性。但是你只想驗(yàn)證與用戶的當(dāng)前郵箱不一致的郵箱的唯一性。也就是說(shuō)你只想驗(yàn)證這個(gè)郵箱有沒(méi)有被其他用戶所使用。你需要傳遞 ID 作為第三個(gè)參數(shù)來(lái)通知 unique 約束來(lái)忽略當(dāng)前用戶的 ID:
'email' => 'unique:users,email_address,'.$user->id
如果表名使用的主鍵列名不是 id
,那么你還需要指定主鍵的列名到第四個(gè)參數(shù):
'email' => 'unique:users,email_address,'.$user->id.',user_id'
添加額外的條件查詢
你也可以指定更多的條件查詢:
'email' => 'unique:users,email_address,null,id,account_id,1'
在上面的約束中,只有 account_id
為 1
的行會(huì)被約束進(jìn)行檢查。
url
驗(yàn)證的字段必須符合 PHP filter_var
方法驗(yàn)證的有效 URL。
添加約束條件
在一些場(chǎng)景中,你會(huì)希望只有字段出現(xiàn)在了輸入數(shù)組中時(shí)才會(huì)對(duì)其進(jìn)行驗(yàn)證。你可以在約束列中添加 sometimes
約束來(lái)快速的完成指定:
$v = Validator::make($data, [
'email' => 'sometimes|required|email',
]);
這上面的例子中,只有 $data
中提供了 email
字段,email
的約束才會(huì)對(duì)其進(jìn)行驗(yàn)證。
復(fù)雜的驗(yàn)證條件
有時(shí)候,你可能會(huì)希望基于更復(fù)雜的條件邏輯去進(jìn)行約束的驗(yàn)證。比如,你希望只有另外一個(gè)字段擁有比 100 更大的值時(shí)才會(huì)驗(yàn)證給定的字段是否被提供。又或者你想要在只有另外一個(gè)字段被提供時(shí)才會(huì)需要其他兩個(gè)字段的值。添加這些條件判定并非是痛苦的一件事。首先,你還是需要?jiǎng)?chuàng)建一個(gè) Validator
實(shí)例和一些靜態(tài)的約束:
$v = Validator::make($data, [
'email' => 'required|email',
'games' => 'required|numeric'
]);
讓我們假定我們的應(yīng)用是服務(wù)于一些游戲收藏家的。如果一個(gè)游戲收藏家注冊(cè)了我們的應(yīng)用,并且它們添加了超過(guò) 100 個(gè)游戲時(shí)。我們需要它們解釋一下為什么他會(huì)擁有那么多的游戲。比如,或許他開了一個(gè)游戲販賣超市,又或者他僅僅就是喜歡收藏。我們可以使用 Validator
實(shí)例上的 sometimes
方法來(lái)添加這個(gè)必要的條件:
$v->sometimes('reason', 'required|max:500', function ($input) {
return $input->games >= 100;
});
傳遞到 sometimes
方法的第一個(gè)參數(shù)是我們需要考慮驗(yàn)證的字段的名字。第二個(gè)參數(shù)是我們想要添加的約束。如果第三個(gè)參數(shù)傳遞的 Closure
返回的結(jié)果是 true
,那么這個(gè)約束就會(huì)被添加進(jìn)去。這就可以輕松的對(duì)復(fù)雜的驗(yàn)證場(chǎng)景進(jìn)行條件的構(gòu)建。你甚至可以一次性的添加多個(gè)字段的條件驗(yàn)證:
$v->sometimes(['reson', 'cost'], 'required', function ($input) {
return $input->games >= 100;
});
注意:傳遞到
Closure
中的$input
是一個(gè)Illuminate\Support\Flument
實(shí)例,并且它可以被用來(lái)訪問(wèn)你的輸入和文件。
自定義驗(yàn)證約束
Laravel 提供了各種有用的驗(yàn)證約束。但是,你可能希望添加你自己的特定的約束。你可以使用 Validator
假面的 extend
方法來(lái)注冊(cè)自己的驗(yàn)證約束。讓我們?cè)诜?wù)提供者里注冊(cè)一個(gè)自定義的驗(yàn)證約束:
<?php
namespace App\Providers;
use Validator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Validator::extend('foo', function ($attribute, $value, $parameters, $validator) {
return $value == 'foo';
});
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
//
}
}
自定義的驗(yàn)證閉包中接收四個(gè)參數(shù):需要被驗(yàn)證的屬性名稱,屬性的值,一個(gè)需要被傳遞到約束的 $paramters
數(shù)組,和 Validator
實(shí)例。
你也可以傳遞一個(gè)類名和方法到 extend
方法中來(lái)代替閉包:
Validator::extend('foo', 'FooValidator@validate');
定義錯(cuò)誤消息
你也需要為你的自定義約束添加一個(gè)錯(cuò)誤消息。你可以使用行內(nèi)自定義錯(cuò)誤消息或者將其添加到獨(dú)立的驗(yàn)證語(yǔ)言文件中。這個(gè)消息應(yīng)該被存放在數(shù)組的一維中,而不是包含在 custom
數(shù)組里:
"foo" => 'Your input was invalid!',
'accepted' => 'The :attribute must be accepted.',
// The rest of the validation error messages...
當(dāng)構(gòu)建自定義的驗(yàn)證約束時(shí),你或許有時(shí)候也想為錯(cuò)誤消息定義一些占位符。你可以使用 Validator
假面的 replacer
方法來(lái)進(jìn)行占位替換。你可以在服務(wù)提供者的 boot
方法中來(lái)做這些:
/**
* Bootstrap any application services.
*
* @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)證時(shí),如果在輸入數(shù)組中沒(méi)有被提供,或者驗(yàn)證約束為 required
卻是一個(gè)空值。那么普通的驗(yàn)證約束,包括自定義的約束擴(kuò)展,都不會(huì)再執(zhí)行。比如,unique
約束就不會(huì)在出現(xiàn) null
值進(jìn)行執(zhí)行:
$rules = ['name' => 'unique'];
$input = ['name' => null];
Validator:make($input, $rules)->passes(); // true
如果需要約束即使是屬性值為空時(shí)也繼續(xù)執(zhí)行,那么約束需要暗示屬性是必須的。你可以使用 Validator::extendImplicit()
方法來(lái)構(gòu)建一個(gè) “隱式的” 擴(kuò)展:
Validator::extendImplicit('foo', function ($attribute, $value, $parameters, $validator) {
return $value == 'foo';
});
注意: 隱式的擴(kuò)展僅僅是暗示屬性是必須的,不論它實(shí)際上是缺失的值或者是空的屬性,這都取決于你。