Validation trong Laravel
Trong hướng dẫn này chúng ta cùng đi nghiên cứu cách xác thực và kiểm tra dữ liệu (Validation) trong Laravel 8.
Làm sao để kiểm tra, xác thực thông tin người dùng gửi lên trong các dự án PHP là một vấn đề quan trọng liên quan đến bảo mật. Trong hướng dẫn này chúng ta cùng đi xem xét vềvalidation trong Laravel8, một phần không thể thiếu trong các ứng dụng.
Giới thiệu về validation trong Laravel.
Laravel cung cấp cho cũng ta nhiều cách để xác thực, kiểm tra dữ liệu. Trong đó cách phổ biến nhất là xác thực các dữ liệu người dùng gửi lên HTTP request.
Trong laravel, validation được support rất mạnh và sử dụng cũng như mở rộng cũng rất dễ dàng.
Bạn có thể sử dụng rất nhiều cách để có thể validate được dữ liệu trong Laravel và ở phạm vi bài viết này mình sẽ giới thiệu với mọi người một số cách phổ biến nhất.
Validation sử dụng phương thức validate.
Để validate dữ liệu request gửi lên các bạn có thể sử dụng phương thức validate với cú pháp:
Ví dụ
$request->validate($rules, $customMessage);
Trong đó:
$rules
là một mảng dữ liệu với key là các input name, value là các rule mà bạn muốn ràng buộc.$customMessage
là một mảng dữ liệu chứa các custom message của bạn. Trường này có thể bỏ trống.
VD: Validate input id
bắt buộc phải có và phải là kiểu số.
Ví dụ
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::get('store', function (Request $request) {
$request->validate([
'id' => 'required|integer'
]);
})->name('store');
Ngoài cách ngăn cách giữa các rule bằng ký tự '|
' bạn cũng có thể viết dưới dạng sau:
Ví dụ
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::get('store', function (Request $request) {
$request->validate([
'id' => ['required', 'integer']
]);
})->name('store');
Trong trường hợp validate mà không pass laravel sẽ trả về một response redirect về request trước đó, kèm theo các error message được flash xuống session.
Nếu trong trường hợp bạn cần Laravel response về luôn json error code, bạn cần phải truyền thêm tham số accept header application/json hoặc request của bạn là một XHR request.
Validation sử dụng form request.
Laravel cung cấp cho chúng ta thêm một cách để tạo ra các validate nằm ở trong file riêng biệt, chứa các logic phục vụ cho việc validate data và có thể tái sử dụng trong những trường hợp tương tự.
Để tạo ra form request trong Laravel, các bạn sử dụng câu lệnh artisan:
Ví dụ
php artisan make:request FormRequestName
Trong đó, FormRequestName
là form request bạn muốn tạo.
VD: Mình sẽ tạo ra StoreContactRequest
.
Ví dụ
php artisan make:request StoreContactRequest
Lúc này Laravel sẽ sinh ra cho các bạn một file nằm trong app/Http/Requests/StoreContactRequest.php
. File này sẽ có nội dung như dạng như sau (tùy version):
Ví dụ
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreContactRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}
Trong đó:
Phương thức authorize sẽ quyết định xem người dùng có được thực thi request này hay không. Nếu trả về true thì người dùng được phép và ngược lại. Phương thức rules sẽ chứa các rule các bạn muốn validate.
VD: Mình sẽ chuyển validate ở ví dụ trên vào form request.
- app/Http/Requests/StoreContactRequest.php
Ví dụ
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreContactRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'id' => ['required', 'integer']
];
}
}
- routes/web.php
Ví dụ
use App\Http\Requests\StoreContactRequest;
use Illuminate\Support\Facades\Route;
Route::get('store', function (StoreContactRequest $request) {
return 'pass';
})->name('store');
Đối với form request bạn cũng có thể custom được error mesage bằng cách trả về message trong phương thức message.
VD: Custom message required cho trường id
.
Ví dụ
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreContactRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'id' => ['required', 'integer']
];
}
public function messages()
{
return ['id.required' => 'Trường ID là bắt buộc'];
}
}
Bạn cũng có thể sửa attribute name trong form request bằng cách sử dụng phương thức attributes
.
VD: Sửa attribute "id
" thành "contact id
"
Ví dụ
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes()
{
return [
'id' => 'Contact id',
];
}
Trong một số trường hợp bạn muốn thực hiện thêm một số logic sau khi validate thực thi bạn có sử dụng phương thức after.
Ví dụ
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreContactRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'id' => ['required', 'integer']
];
}
public function messages()
{
return ['id.required' => 'Trường ID là bắt buộc'];
}
/**
* Configure the validator instance.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
// logic
});
}
}
Tương tự bạn cũng có thể chỉnh sửa input data trước khi thực hiện validate bằng cách sử dụng phương thức prepareForValidation
.
VD: Xử lí slug
input về dạng đường dẫn trước khi validate.
Ví dụ
use Illuminate\Support\Str;
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$this->merge([
'slug' => Str::slug($this->slug),
]);
}
Validation sử dụng Validator.
Ngoài 2 cách trên, bạn cũng có thể sử dụng class Validator
để validate với cú pháp:
Ví dụ
Validator::make($inputs, $rules, $messages $attributes);
Trong đó:
$inputs
là một mảng dữ liệu chứa các dữ liệu bạn cần validate.$rules
là một mảng dữ liệu với key là các input name, value là các rule mà bạn muốn ràng buộc.$messages
là một mảng dữ liệu chứa các custom message của bạn. Trường này có thể bỏ trống.$attributes
là một mảng dữ liệu chứa các custom attribute của bạn. Trường này có thể bỏ trống.
Ví dụ
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Validator;
Route::get('store', function (Request $request) {
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
})->name('store');
Lúc này để thực hiện validate các bạn sử dụng phương thức validate.
Ví dụ
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Validator;
Route::get('store', function (Request $request) {
Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
])->validate();
})->name('store');
Hoặc bạn cũng có thể vừa validate và kiểm tra xem validate có lỗi hay không bằng cách sử dụng phương thức fails.
Ví dụ
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Validator;
Route::get('store', function (Request $request) {
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
// validate fails
}
})->name('store');
Hiển thị error massage.
Khi thực hiện validate data, nếu như không pass thì Laravel sẽ return về một MassageBag
(Illuminate\Support\MessageBag
) chứa các error massage. Và Laravel sẽ tự động gán MassageBag
vào trong $errors
trong views.
Để lấy ra error message đầu tiên của một field các bạn sử dụng phương thức first
.
VD: Lấy ra error message lỗi đầu tiên của trường email
.
Ví dụ
$errors = $validator->errors();
echo $errors->first('email');
Hoặc trong blade
Ví dụ
{{ $errors->first('email') }}
Để lấy ra tất cả message của một trường nào đó các bạn có thể sử dụng phương thức get
. Hàm này sẽ trả về một mảng các message lỗi của trường đó.
VD: In ra tất cả các message lỗi của trường email
.
Ví dụ
foreach ($errors->get('email') as $message) {
//
}
Nếu input của bạn là một mảng, bạn có thể lấy ra tất cả error message trong mảng input key đó bằng cách sử dụng ký tự '*
'.
VD: Lấy ra error massage của các attachments
.
Ví dụ
foreach ($errors->get('attachments.*') as $message) {
//
}
Còn trong trường hợp bạn muốn lấy ra tất cả các các error message của validator, bạn có thể sử dụng phương thức all
.
VD: lấy ra tất cả các error message.
Ví dụ
foreach ($errors->all() as $message) {
//
}
Đôi lúc, bạn sẽ cần kiểm tra xem trường nào đó có tồn tại error message hay không, bạn có thể sử dụng phương thức has
. Phương thức này sẽ trả về true nếu trường đó có error message.
VD: Kiểm tra xem validate input email
có sai hay không.
Ví dụ
if ($errors->has('email')) {
//
}
Sửa nội dung error message.
Mặc định các message trong Laravel được đặt trong resources/lang/en/validation.php
.
Và nếu như bạn muốn thay đổi nội dung message cho một trường nào đó, bạn có thể thêm vào trong key custom
.
VD: Thay đổi error mesage cho trường email với rule reqruire và max.
Ví dụ
'custom' => [
'email' => [
'required' => 'We need to know your email address!',
'max' => 'Your email address is too long!'
],
],
Tương tự bạn cũng có thể custom attribute trong file language, bằng cách thiết lập trong key attribute
.
VD: thay đổi attribute name của trường email
.
Ví dụ
'attributes' => [
'email' => 'email address',
],
Các rule có sẵn trong Laravel.
Do Laravel cung cấp rất nhiều rule, nên mình chỉ liệt kê ra một số rule hay dùng thôi. Các bạn có thể xem toàn bộ những rule mà Laravel hỗ trợ sẵn tại đây.
Rule | Mô Tả |
accepted | Rule này chỉ chấp nhận các giá trị"yes" ,"on" ,1 , hoặctrue . Rule này thường được dùng cho các input là radio, checkbox. |
active_url | Rule này sẽ kiểm tra xem URL này có đang thực sự tồn tại, bằng việc sử dụng hàmdns_get_record trong PHP. |
after |
Rule này sẽ kiểm tra xem ngày tháng có đang lớn hơn giá trị cần so sánh không. VD:'start_date' => 'required|date|after:tomorrow' |
before | Rule này tương tự after nhưng là so sánh nhỏ hơn. |
alpha | Rule này sẽ kiểm tra xem data gửi lên có phải là các ký tự alphabetic. |
alpha_num | Rule này sẽ kiểm tra xem dữ liệu có phải là các kí tự alphabetic và số. |
array | Rule này sẽ kiểm tra xem dữ liệu có phải là array. |
bail | Rule này sẽ dừng việc validate dữ liệu nếu như có một rule nào đó fail. |
between:min,max | Rule này sẽ kiểm tra xem giá trị có nằm trong khoảng min, max hay không |
confirmed |
Rule này sẽ kiểm tra xem dữ liệu có giống với dữ liệu của VD: Với trường hợp xác thực |
date | Kiểm tra xem dữ liệu gửi lên có phải là date không. |
dimensions |
Rule này sẽ kiểm tra kích thước của ảnh upload lên. VD: |
Rule này sẽ kiểm tra xem dữ liệu gửi lên có phải là email. | |
image | Rule này sẽ kiểm tra xem dữ liệu gửi lên có phải image. |
in_array:anotherfield | Rule này sẽ kiểm tra xem dữ liệu gửi lên có nằm trong mảnganotherfield. |
integer | Rule này sẽ kiểm tra xem dữ liệu gửi lên có phải số nguyên hay không. |
ip | Rule này sẽ kiểm tra xem dữ liệu gửi lên có phải là ip. |
ipv4 | Rule này sẽ kiểm tra xem dữ liệu gửi lên có phải là ipv4. |
ipv6 | Rule này sẽ kiểm tra xem dữ liệu gửi lên có phải là ipv6. |
json | Rule này sẽ kiểm tra xem dữ liệu gửi lên có phải là một json string. |
max:value | Rule này sẽ kiểm tra xem dữ liệu có nhỏ hơn giá trị value. |
min:value | Rule này sẽ kiểm tra xem dữ liệu có lớn hơn giá trị value. |
not_in:foo,bar | Rule này sẽ kiểm tra xem dữ liệu gửi lên không nằm trong mảng. |
nullable | Rule này sẽ cho phép không cần dữ liệu gửi lên. |
numberic | Rule này sẽ kiểm tra xem dữ liệu gửi lên có phải là numeric hay không. |
regex:pattern | Rule này sẽ kiểm tra xem dữ liệu phải matching vơi pattern. |
required | Rule này sẽ bắt buộc trường phải có dữ liệu. |
string | Rule này sẽ bắt buộc dữ liệu phải là string. |
unique:table,column,except,idColumn | Rule này sẽ kiểm tra dữ liệu bắt buộc phải chưa xuất hiện với điều kiện ở trong database. |
url | Rule này bắt buộc dữ liệu gửi lên phải là một URL. |
Thêm mới rule trong Laravel.
Nếu như các rule mà Laravel cung cấp không giải quyết được vấn đề của bạn. Bạn có thể tạo mới một rule theo cách của bạn một cách đơn giản bằng cách sử dụng command make:rule
. Command này sẽ tạo ra một rule trong app/Rules
cho các bạn viết logic vào trong.
VD: Tạo thêm rule Uppercase
để kiểm tra xem data có phải đang ở dạng chữ in hoa hay không.
Ví dụ
php artisan make:rule Uppercase
Lúc này file rule sẽ có dạng như sau:
- app/Rules/Uppercase.php
Ví dụ
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class Uppercase implements Rule
{
/**
* Create a new rule instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
//
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return 'The validation error message.';
}
}
Trong đó:
- Phương thức
passes
mà trả vềtrue
thì rule sẽ được pass và ngược lại. - Phương thức
massage
sẽ trả về message string nếu như rule không pass.
Lúc này khi muốn sử dụng rule vào validator bạn chỉ sử dụng như sau:
Ví dụ
use App\Rules\Uppercase;
$request->validate([
'name' => ['required', 'string', new Uppercase],
]);
Ngoài cách tạo thêm rule trên, bạn cũng có thể đưa logic vào trong một closure
với cú pháp:
Ví dụ
function ($attribute, $value, $fail) {
if ($value === 'foo') {
$fail('The '.$attribute.' is invalid.');
}
}
Trong đó:
$attribute
là tên của trường cần validate.$value
là giá trị của trường cần validate.$fail
là một callback function sẽ được gọi khi validate fail.
VD:
Ví dụ
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($request->all(), [
'title' => [
'required',
'max:255',
function ($attribute, $value, $fail) {
if ($value === 'foo') {
$fail('The '.$attribute.' is invalid.');
}
},
],
]);