Code Happy: Validation

← Back to Index

Please note that this chapter was written for VERSION 3 of the Laravel PHP Framework.

Validation is an important part of many web applications. You can never trust your users, they have been plotting to destroy you for weeks by abusing your forms with evil javascripts.

We can't let them win, they must not destroy our beautiful applications. Let's validate all input provided by the user, that way they won't be able to harm us at all.

Naturally Laravel has a library, aptly named 'Validation' that will do all the hard work for us.

Set up validation

Let's start by creating an imaginary form, close your eyes and imagine a nice long form with many fields... uh oh... how can I get you to open your eyes again..?

Right, I will assume you got fed up of waiting, have opened your eyes and are back with me again, along with our imaginary form. Let's get the input data from that form.

<?php

$input = Input::get();

Now normally you don't want to use the get() method, as its an easy way to populate your input array with extra data you don't need. In fact the open source collaboration site github was a victim to mass assignment. I have used get() to simplify the tutorial. In your applications please build the input array only with the fields you need.

Our input array now contains something that looks a little like this..

<?php

array(
    'name' => 'John',
    'age'  => 15
)

Let's validate these fields to make sure they make sense to our application. Before we can start the validation process we need to create a set of rules that will be used to validate each field. With the validator class, rules are defined in an array format. Let's jump right in and take a look.

<?php

$rules = array(
    'name'  => 'required|min:3|max:32|alpha',
    'age'   => 'required|integer|min:16'
);

Great, now we have some rules. The array key is the field that is being validated upon, and the array value contains a number of validation rules separate by a pipe | symbol.

In our case we are validating that both fields contain a value by using the 'required' rule. The length of the user's name must be a minimum of 3 characters (min:3) and a maximum length of 32 characters (max:32). The 'alpha' rule will check to make sure that the name field only contains letters.

Our age field must contain an integer and the value must be at least 16. You see that the min rule has adapted to fit the content that its validating, very clever!

Don't worry, we will cover all the validation rules later. For now let's see the validation in action, here we go.

<?php

$v = Validator::make($input, $rules);

We have created our validator object with the make() method, passing it our input array and our rules array. Let's see if it validates!

<?php

if( $v->fails() )
{
    // code for validation failure :(
}
else
{
    // code for validation success!
}

As you can see, we use the fails() method to check the result of the validation attempt, it will return true if the validation has failed and false if it was successful.

If you prefer a more positive outlook on your validations, you could use the passes() method, which returns the opposite values..

<?php

if( $v->passes() )
{
    // code for validation success!
}
else
{
    // code for validation failure :(
}

There, now we are positive and can dance over rainbows with sparkleponies.

Errors

If your validation fails, which it will because our user is under 16 (sorry for slaying your sparklepony), you will want to find out what went wrong. The validator provides an errors Messages object which allows us to easily find the information we need.

The errors object has similar methods to the Input class, so I will not need to go over them all. Let's retrieve an array of errors for a specific field.

<?php

$age_errors = $v->errors->get('age');

Now we have an array containing all of the errors associated with the age field..

<?php

array(
    'The age must be at least 16.'
)

Most of the time I find myself using the first() method in my views, which returns the first array item if it exists, or null if it doesn't. For example..

<?php echo Form::label('username', 'Username') ?>
<?php echo $errors->first('username') ?>
<?php echo Form::text('username') ?>

Now our validation errors will appear for this field if any are present. You can also pass a second parameter to the first() method to format the output..

<?php echo $errors->first('username', '<span class="error">:message</span>') ?>

Neat!

You can also use has() to check to see if an error exists, and all() to retrieve all errors as an array.

Validation Rules

Here is a list of validation rules, and their purpose.

required

Ensure that a value for a field is present, and is not an empty string.

alpha

The string must only consist of letters (alphabetical characters).

alpha_num

The string must only contain letters and numbers. Useful for usernames.

alpha_dash

The string must contain only letters, numbers, dashes or underscore characters. Useful for storing URL slugs.

size:5

(string) The string must be exactly five characters long. (numeric) The value must be five.

between:5,10

(string) The length of the string must be between five and ten characters. (numeric) The value must be between five and ten.

min:5

(string) The length of the string must be between five characters or more. (numeric) The value must be equal to or greater than five. (file) The file size must be 5 kilobytes or more.

max:5

(string) The length of the string must be less than or equal to five. (numeric) The value must be less than or equal to five. (file) The file size must be 5 kilobytes or less.

numeric

The value must be numeric.

integer

The value must be an integer or whole number.

in:red,green,blue

Ensure that the value is contained within the list of values provided.

not_in:pink,purple

Ensure that none of the values provided match the value.

confirmed

The value of the field must match a confirmation field, named in the format '_confirmation'.

accepted

The field value must be equal to 'yes' or 1. Useful for validating check-boxes.

same:age

The field value must match the field specified by the same rule.

different:age

The field value must not match the field specified by the same rule.

match:/[a-z]+/

The field value must match the provided regular expression.

unique:users

This is one of my favourites. The validator will look at the users database table, and make sure that the value is unique within the column that has the same name as the field name. Useful for making sure that duplicate usernames or email addresses don't occur.

If you would like to specify an alternate column name, simply pass it as a second parameter..

unique:users,nickname

You can also force the rule to ignore a provided id by passing it as a third parameter.

unique:users,nickname,5

exists:colors

Acts as the opposite of unique, the value must already exist in the database table. Once more you can pass a second parameter to refer to another column.

before:1984-12-12

The date provided by the field, must have occurred before the date template provided to the before rule.

The before and after filters use strtotime() to calculate a timestamp for comparison, this means you can do some neat tricks like..

before:next Thursday

Unfortunately I was on the one that added this functionality, so if it breaks you can go ahead and shout at me... sorry!

after:1984-12-12

Similar to before, only the date must occur after the date provided to the after rule.

email

The value must be a valid email address.

url

The value must match the format of an URL.

active_url

The value must match a valid active URL. checkdnsr is used to verify that the URL is active.

mimes:png,mp3

The value must be a $_FILE which whose MIME type matches the file extensions provided.
You can add additional MIME types to the array in config/mimes.php.

image

The uploaded file must be an image.

Custom Error Messages

I find the default error messages quite descriptive, but your clients might have their own ideas. Let's see how we can customize our error messages to suit our needs.

You can edit the validation error messages directly by modifying the file application/language/en/validation.php...

...
"after"          => "The :attribute must be a date after :date.",
"alpha"          => "The :attribute may only contain letters.",
"alpha_dash"     => "The :attribute may only contain letters, numbers, and dashes.",
...

Laravel replaces the :attribute marker with the name of the field. Other markers also exist within the rules, and their purpose is quite self explanatory.

If you would rather change the messages for a single form, rather than edit them globally, you can pass a third array of messages to the Validator::make() method.

<?php

$messages = array(
    'same'    => 'The :attribute and :other must match, fool!',
    'size'    => 'The :attribute must be exactly :size , like duh!'
);

$v = Validator::make($input, $rules, $messages);

Great now we have custom messages! We can even specify error messages for individual fields by setting the message key to field_rule, for example..

<?php

$messages = array(
    'age_required'    => 'You need to have had at least one birthday!'
);

Custom Validation Rules

The validator allows you add extra rules to suit the needs of your application, let's jump right in and take a look at how we register a new validation rule.

<?php

Validator::register('superdooper', function($attribute, $value, $parameters){
    return $value == 'superdooper';
});

Our newly created validation rule superdooper will ensure that our value matches the string 'superdooper'. Your custom validations should return true on success, or false on failure.

The $attribute value will be the name of the field being validated, and $value will of course contain the value.

The $parameters attribute contains an array of parameters that have been passed to the rule after the colon, and separated by commas.

As you have created a new validator, there will be no error messages associated with it yet, we will need to add one so that Laravel knows what to say when it fails. We can add an error message in the same way as we have previously..

<?php

'superdooper' => 'The :attribute must be superdooper, ok trooper?!',

Once again you can pass the extra error message array as a third parameter to the Validator::make() method, or simply add it to your application/language/en/validation.php file for safe keeping.

Validation Classes

If we want to provide many new validation methods, or reuse them across a number if projects, it would be best to create a validation class. Validation classes extend Laravel's data, and overload it with additional validation methods. The class is created in the application/libraries directory for easy loading, but you could place it elsewhere as long as it is registered with the Autoloader (later chapter). Let's take a look at the class.

<?php

// application/libraries/validator.php

class Validator extends Laravel\Validator {

    public function validate_awesome($attribute, $value, $parameters)
    {
        return $value == 'awesome';
    }

}

As you can see our Validator class extends the Laravel\Validator name-spaced core class and provides additional validations in the form of validate_<rulename> methods. The validation methods accept the same parameters as the Validator::register() closure, and work in the same way.

In order to use our new validation class, we will need to remove the existing alias for Validator from our application/config/application.php file. This way Laravel will use our created class instead of the one in the Laravel source folder.

You could use this method to replace the original validation methods with your own, for example you could create a validate_size method and calculate the size in an alternate format.

I would suggest adding custom error messages to the validation language file when using Validation classes, this will allow for a much easier migration to another project, and will not require any 'source-digging' to find all the messages used.

My books are available online for free to encourage learning. However, if you'd like for me to keep writing, then please consider buying a digital copy over at Leanpub.com.

It's available in PDF, ePub, and Kindle format, and contains a bunch of extras that you won't find on the site. I have a full-time job, and I write my books in my spare time. Please consider buying a copy so that I can continue to write new books from the comfort of my sofa!