Validation
Introduction
Laravel provides several different approaches to validate your application's incoming data. By default, Laravel's base controller class uses a ValidatesRequests
trait which provides a convenient method to validate incoming HTTP requests with a variety of powerful validation rules.
Validation Quickstart
To learn about Laravel's powerful validation features, let's look at a complete example of validating a form and displaying the error messages back to the user.
Defining The Routes
First, let's assume we have the following routes defined in our routes/web.php
file:
Route::get('post/create', 'PostController@create');
Route::post('post', 'PostController@store');
The GET
route will display a form for the user to create a new blog post, while the POST
route will store the new blog post in the database.
Creating The Controller
Next, let's take a look at a simple controller that handles these routes. We'll leave the store
method empty for now:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
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...
}
}
Writing The Validation Logic
Now we are ready to fill in our store
method with the logic to validate the new blog post. To do this, we will use the validate
method provided by the Illuminate\Http\Request
object. If the validation rules pass, your code will keep executing normally; however, if validation fails, an exception will be thrown and the proper error response will automatically be sent back to the user. In the case of a traditional HTTP request, a redirect response will be generated, while a JSON response will be sent for AJAX requests.
To get a better understanding of the validate
method, let's jump back into the store
method:
/**
* Store a new blog post.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// The blog post is valid...
}
As you can see, we pass the desired validation rules into the validate
method. Again, if the validation fails, the proper response will automatically be generated. If the validation passes, our controller will continue executing normally.
Alternatively, validation rules may be specified as arrays of rules instead of a single |
delimited string:
$validatedData = $request->validate([
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
]);
You may use the validateWithBag
method to validate a request and store any error messages within a named error bag:
$validatedData = $request->validateWithBag('post', [
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
]);
Stopping On First Validation Failure
Sometimes you may wish to stop running validation rules on an attribute after the first validation failure. To do so, assign the bail
rule to the attribute:
$request->validate([
'title' => 'bail|required|unique:posts|max:255',
'body' => 'required',
]);
In this example, if the unique
rule on the title
attribute fails, the max
rule will not be checked. Rules will be validated in the order they are assigned.
A Note On Nested Attributes
If your HTTP request contains "nested" parameters, you may specify them in your validation rules using "dot" syntax:
$request->validate([
'title' => 'required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);
Displaying The Validation Errors
So, what if the incoming request parameters do not pass the given validation rules? As mentioned previously, Laravel will automatically redirect the user back to their previous location. In addition, all of the validation errors will automatically be flashed to the session.
Again, notice that we did not have to explicitly bind the error messages to the view in our GET
route. This is because Laravel will check for errors in the session data, and automatically bind them to the view if they are available. The $errors
variable will be an instance of Illuminate\Support\MessageBag
. For more information on working with this object, check out its documentation.
The $errors
variable is bound to the view by the Illuminate\View\Middleware\ShareErrorsFromSession
middleware, which is provided by the web
middleware group. When this middleware is applied an $errors
variable will always be available in your views, allowing you to conveniently assume the $errors
variable is always defined and can be safely used.
So, in our example, the user will be redirected to our controller's create
method when validation fails, allowing us to display the error messages in the view:
<!-- /resources/views/post/create.blade.php -->
<h1>Create Post</h1>
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- Create Post Form -->
The @error
Directive
You may also use the @error
Blade directive to quickly check if validation error messages exist for a given attribute. Within an @error
directive, you may echo the $message
variable to display the error message:
<!-- /resources/views/post/create.blade.php -->
<label for="title">Post Title</label>
<input id="title" type="text" class="@error('title') is-invalid @enderror">
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
A Note On Optional Fields
By default, Laravel includes the TrimStrings
and ConvertEmptyStringsToNull
middleware in your application's global middleware stack. These middleware are listed in the stack by the App\Http\Kernel
class. Because of this, you will often need to mark your "optional" request fields as nullable
if you do not want the validator to consider null
values as invalid. For example:
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'publish_at' => 'nullable|date',
]);
In this example, we are specifying that the publish_at
field may be either null
or a valid date representation. If the nullable
modifier is not added to the rule definition, the validator would consider null
an invalid date.
AJAX Requests & Validation
In this example, we used a traditional form to send data to the application. However, many applications use AJAX requests. When using the validate
method during an AJAX request, Laravel will not generate a redirect response. Instead, Laravel generates a JSON response containing all of the validation errors. This JSON response will be sent with a 422 HTTP status code.
Form Request Validation
Creating Form Requests
For more complex validation scenarios, you may wish to create a "form request". Form requests are custom request classes that contain validation logic. To create a form request class, use the make:request
Artisan CLI command:
php artisan make:request StoreBlogPost
The generated class will be placed in the app/Http/Requests
directory. If this directory does not exist, it will be created when you run the make:request
command. Let's add a few validation rules to the rules
method:
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
You may type-hint any dependencies you need within the rules
method's signature. They will automatically be resolved via the Laravel service container.
So, how are the validation rules evaluated? All you need to do is type-hint the request on your controller method. The incoming form request is validated before the controller method is called, meaning you do not need to clutter your controller with any validation logic:
/**
* Store the incoming blog post.
*
* @param StoreBlogPost $request
* @return Response
*/
public function store(StoreBlogPost $request)
{
// The incoming request is valid...
// Retrieve the validated input data...
$validated = $request->validated();
}
If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an AJAX request, a HTTP response with a 422 status code will be returned to the user including a JSON representation of the validation errors.
Adding After Hooks To Form Requests
If you would like to add an "after" hook to a form request, you may use the withValidator
method. This method receives the fully constructed validator, allowing you to call any of its methods before the validation rules are actually evaluated:
/**
* Configure the validator instance.
*
* @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!');
}
});
}
Authorizing Form Requests
The form request class also contains an authorize
method. Within this method, you may check if the authenticated user actually has the authority to update a given resource. For example, you may determine if a user actually owns a blog comment they are attempting to update:
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
$comment = Comment::find($this->route('comment'));
return $comment && $this->user()->can('update', $comment);
}
Since all form requests extend the base Laravel request class, we may use the user
method to access the currently authenticated user. Also note the call to the route
method in the example above. This method grants you access to the URI parameters defined on the route being called, such as the {comment}
parameter in the example below:
Route::post('comment/{comment}');
If the authorize
method returns false
, a HTTP response with a 403 status code will automatically be returned and your controller method will not execute.
If you plan to have authorization logic in another part of your application, return true
from the authorize
method:
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
You may type-hint any dependencies you need within the authorize
method's signature. They will automatically be resolved via the Laravel service container.
Customizing The Error Messages
You may customize the error messages used by the form request by overriding the messages
method. This method should return an array of attribute / rule pairs and their corresponding error messages:
/**
* Get the error messages for the defined validation rules.
*
* @return array
*/
public function messages()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
Customizing The Validation Attributes
If you would like the :attribute
portion of your validation message to be replaced with a custom attribute name, you may specify the custom names by overriding the attributes
method. This method should return an array of attribute / name pairs:
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes()
{
return [
'email' => 'email address',
];
}
Prepare Input For Validation
If you need to sanitize any data from the request before you apply your validation rules, you can use the prepareForValidation
method:
use Illuminate\Support\Str;
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$this->merge([
'slug' => Str::slug($this->slug),
]);
}
Manually Creating Validators
If you do not want to use the validate
method on the request, you may create a validator instance manually using the Validator
facade. The make
method on the facade generates a new validator instance:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
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...
}
}
The first argument passed to the make
method is the data under validation. The second argument is the validation rules that should be applied to the data.
After checking if the request validation failed, you may use the withErrors
method to flash the error messages to the session. When using this method, the $errors
variable will automatically be shared with your views after redirection, allowing you to easily display them back to the user. The withErrors
method accepts a validator, a MessageBag
, or a PHP array
.
Automatic Redirection
If you would like to create a validator instance manually but still take advantage of the automatic redirection offered by the request's validate
method, you may call the validate
method on an existing validator instance. If validation fails, the user will automatically be redirected or, in the case of an AJAX request, a JSON response will be returned:
Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
])->validate();
You may use the validateWithBag
method to store the error messages in a named error bag if validation fails:
Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
])->validateWithBag('post');
Named Error Bags
If you have multiple forms on a single page, you may wish to name the MessageBag
of errors, allowing you to retrieve the error messages for a specific form. Pass a name as the second argument to withErrors
:
return redirect('register')
->withErrors($validator, 'login');
You may then access the named MessageBag
instance from the $errors
variable:
{{ $errors->login->first('email') }}
After Validation Hook
The validator also allows you to attach callbacks to be run after validation is completed. This allows you to easily perform further validation and even add more error messages to the message collection. To get started, use the after
method on a validator instance:
$validator = Validator::make(...);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
if ($validator->fails()) {
//
}
Working With Error Messages
After calling the errors
method on a Validator
instance, you will receive an Illuminate\Support\MessageBag
instance, which has a variety of convenient methods for working with error messages. The $errors
variable that is automatically made available to all views is also an instance of the MessageBag
class.
Retrieving The First Error Message For A Field
To retrieve the first error message for a given field, use the first
method:
$errors = $validator->errors();
echo $errors->first('email');
Retrieving All Error Messages For A Field
If you need to retrieve an array of all the messages for a given field, use the get
method:
foreach ($errors->get('email') as $message) {
//
}
If you are validating an array form field, you may retrieve all of the messages for each of the array elements using the *
character:
foreach ($errors->get('attachments.*') as $message) {
//
}
Retrieving All Error Messages For All Fields
To retrieve an array of all messages for all fields, use the all
method:
foreach ($errors->all() as $message) {
//
}
Determining If Messages Exist For A Field
The has
method may be used to determine if any error messages exist for a given field:
if ($errors->has('email')) {
//
}
Custom Error Messages
If needed, you may use custom error messages for validation instead of the defaults. There are several ways to specify custom messages. First, you may pass the custom messages as the third argument to the Validator::make
method:
$messages = [
'required' => 'The :attribute field is required.',
];
$validator = Validator::make($input, $rules, $messages);
In this example, the :attribute
placeholder will be replaced by the actual name of the field under validation. You may also utilize other placeholders in validation messages. For example:
$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',
];
Specifying A Custom Message For A Given Attribute
Sometimes you may wish to specify a custom error message only for a specific field. You may do so using "dot" notation. Specify the attribute's name first, followed by the rule:
$messages = [
'email.required' => 'We need to know your e-mail address!',
];
Specifying Custom Messages In Language Files
In most cases, you will probably specify your custom messages in a language file instead of passing them directly to the Validator
. To do so, add your messages to custom
array in the resources/lang/xx/validation.php
language file.
'custom' => [
'email' => [
'required' => 'We need to know your e-mail address!',
],
],
Specifying Custom Attribute Values
If you would like the :attribute
portion of your validation message to be replaced with a custom attribute name, you may specify the custom name in the attributes
array of your resources/lang/xx/validation.php
language file:
'attributes' => [
'email' => 'email address',
],
You may also pass the custom attributes as the fourth argument to the Validator::make
method:
$customAttributes = [
'email' => 'email address',
];
$validator = Validator::make($input, $rules, $messages, $customAttributes);
Specifying Custom Values In Language Files
Sometimes you may need the :value
portion of your validation message to be replaced with a custom representation of the value. For example, consider the following rule that specifies that a credit card number is required if the payment_type
has a value of cc
:
$request->validate([
'credit_card_number' => 'required_if:payment_type,cc'
]);
If this validation rule fails, it will produce the following error message:
The credit card number field is required when payment type is cc.
Instead of displaying cc
as the payment type value, you may specify a custom value representation in your validation
language file by defining a values
array:
'values' => [
'payment_type' => [
'cc' => 'credit card'
],
],
Now if the validation rule fails it will produce the following message:
The credit card number field is required when payment type is credit card.
Available Validation Rules
Below is a list of all available validation rules and their function:
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 Email Ends With Exclude If Exclude Unless 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 Password Present Regular Expression Required Required If Required Unless Required With Required With All Required Without Required Without All Same Size Sometimes Starts With String Timezone Unique (Database) URL UUID
accepted
The field under validation must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance.
active_url
The field under validation must have a valid A or AAAA record according to the dns_get_record
PHP function. The hostname of the provided URL is extracted using the parse_url
PHP function before being passed to dns_get_record
.
after:date
The field under validation must be a value after a given date. The dates will be passed into the strtotime
PHP function:
'start_date' => 'required|date|after:tomorrow'
Instead of passing a date string to be evaluated by strtotime
, you may specify another field to compare against the date:
'finish_date' => 'required|date|after:start_date'
after_or_equal:date
The field under validation must be a value after or equal to the given date. For more information, see the after rule.
alpha
The field under validation must be entirely alphabetic characters.
alpha_dash
The field under validation may have alpha-numeric characters, as well as dashes and underscores.
alpha_num
The field under validation must be entirely alpha-numeric characters.
array
The field under validation must be a PHP array
.
bail
Stop running validation rules after the first validation failure.
before:date
The field under validation must be a value preceding the given date. The dates will be passed into the PHP strtotime
function. In addition, like the after
rule, the name of another field under validation may be supplied as the value of date
.
before_or_equal:date
The field under validation must be a value preceding or equal to the given date. The dates will be passed into the PHP strtotime
function. In addition, like the after
rule, the name of another field under validation may be supplied as the value of date
.