Validation

CodeIgniter provides a comprehensive data validation class thathelps minimize the amount of code you’ll write.

Overview

Before explaining CodeIgniter’s approach to data validation, let’sdescribe the ideal scenario:

  • A form is displayed.
  • You fill it in and submit it.
  • If you submitted something invalid, or perhaps missed a requireditem, the form is redisplayed containing your data along with anerror message describing the problem.
  • This process continues until you have submitted a valid form.On the receiving end, the script must:

  • Check for required data.

  • Verify that the data is of the correct type, and meets the correctcriteria. For example, if a username is submitted it must bevalidated to contain only permitted characters. It must be of aminimum length, and not exceed a maximum length. The username can’tbe someone else’s existing username, or perhaps even a reserved word.Etc.
  • Sanitize the data for security.
  • Pre-format the data if needed (Does the data need to be trimmed? HTMLencoded? Etc.)
  • Prep the data for insertion in the database.Although there is nothing terribly complex about the above process, itusually requires a significant amount of code, and to display errormessages, various control structures are usually placed within the formHTML. Form validation, while simple to create, is generally very messyand tedious to implement.

Form Validation Tutorial

What follows is a “hands on” tutorial for implementing CodeIgniter’s FormValidation.

In order to implement form validation you’ll need three things:

  • A View file containing a form.
  • A View file containing a “success” message to be displayed uponsuccessful submission.
  • A controller method to receive andprocess the submitted data.Let’s create those three things, using a member sign-up form as theexample.

The Form

Using a text editor, create a form called Signup.php. In it, place thiscode and save it to your app/Views/ folder:

  1. <html>
  2. <head>
  3. <title>My Form</title>
  4. </head>
  5. <body>
  6.  
  7. <?= $validation->listErrors() ?>
  8.  
  9. <?= form_open('form') ?>
  10.  
  11. <h5>Username</h5>
  12. <input type="text" name="username" value="" size="50" />
  13.  
  14. <h5>Password</h5>
  15. <input type="text" name="password" value="" size="50" />
  16.  
  17. <h5>Password Confirm</h5>
  18. <input type="text" name="passconf" value="" size="50" />
  19.  
  20. <h5>Email Address</h5>
  21. <input type="text" name="email" value="" size="50" />
  22.  
  23. <div><input type="submit" value="Submit" /></div>
  24.  
  25. </form>
  26.  
  27. </body>
  28. </html>

The Success Page

Using a text editor, create a form called Success.php. In it, placethis code and save it to your app/Views/ folder:

  1. <html>
  2. <head>
  3. <title>My Form</title>
  4. </head>
  5. <body>
  6.  
  7. <h3>Your form was successfully submitted!</h3>
  8.  
  9. <p><?= anchor('form', 'Try it again!') ?></p>
  10.  
  11. </body>
  12. </html>

The Controller

Using a text editor, create a controller called Form.php. In it, placethis code and save it to your app/Controllers/ folder:

  1. <?php namespace App\Controllers;
  2.  
  3. use CodeIgniter\Controller;
  4.  
  5. class Form extends Controller
  6. {
  7. public function index()
  8. {
  9. helper(['form', 'url']);
  10.  
  11. if (! $this->validate([]))
  12. {
  13. echo view('Signup', [
  14. 'validation' => $this->validator
  15. ]);
  16. }
  17. else
  18. {
  19. echo view('Success');
  20. }
  21. }
  22. }

Try it!

To try your form, visit your site using a URL similar to this one:

  1. example.com/index.php/form/

If you submit the form you should simply see the form reload. That’sbecause you haven’t set up any validation rules yet.

Since you haven’t told the Validation class to validate anythingyet, it returns false (boolean false) by default. The validate() methodonly returns true if it has successfully applied your rules without anyof them failing.

Explanation

You’ll notice several things about the above pages:

The form (Signup.php) is a standard web form with a couple of exceptions:

  • It uses a form helper to create the form opening. Technically, thisisn’t necessary. You could create the form using standard HTML.However, the benefit of using the helper is that it generates theaction URL for you, based on the URL in your config file. This makesyour application more portable in the event your URLs change.

  • At the top of the form you’ll notice the following function call:

  1. <?= $validation->listErrors() ?>

This function will return any error messages sent back by thevalidator. If there are no messages it returns an empty string.

The controller (Form.php) has one method: index(). This methoduses the Controller-provided validate method and loads the form helper and URLhelper used by your view files. It also runs the validation routine.Based on whether the validation was successful it either presents theform or the success page.

Loading the Library

The library is loaded as a service named validation:

  1. $validation = \Config\Services::validation();

This automatically loads the Config\Validation file which contains settingsfor including multiple Rulesets, and collections of rules that can be easily reused.

Note

You may never need to use this method, as both the Controller andthe Model provide methods to make validation even easier.

Setting Validation Rules

CodeIgniter lets you set as many validation rules as you need for agiven field, cascading them in order. To set validation rules youwill use the setRule(), setRules(), or withRequest()methods.

setRule()

This method sets a single rule. It takes the name of the field asthe first parameter, an optional label and a string with a pipe-delimited list of rulesthat should be applied:

  1. $validation->setRule('username', 'Username', 'required');

The field name must match the key of any data array that is sent in. Ifthe data is taken directly from $_POST, then it must be an exact match forthe form input name.

setRules()

Like, setRule(), but accepts an array of field names and their rules:

  1. $validation->setRules([
  2. 'username' => 'required',
  3. 'password' => 'required|min_length[10]'
  4. ]);

To give a labeled error message you can set up as:

  1. $validation->setRules([
  2. 'username' => ['label' => 'Username', 'rules' => 'required'],
  3. 'password' => ['label' => 'Password', 'rules' => 'required|min_length[10]']
  4. ]);

withRequest()

One of the most common times you will use the validation library is when validatingdata that was input from an HTTP Request. If desired, you can pass an instance of thecurrent Request object and it will take all of the input data and set it as thedata to be validated:

  1. $validation->withRequest($this->request)
  2. ->run();

Working with Validation

Validating Keys that are Arrays

If your data is in a nested associative array, you can use “dot array syntax” toeasily validate your data:

  1. // The data to test:
  2. 'contacts' => [
  3. 'name' => 'Joe Smith',
  4. 'friends' => [
  5. [
  6. 'name' => 'Fred Flinstone'
  7. ],
  8. [
  9. 'name' => 'Wilma'
  10. ]
  11. ]
  12. ]
  13.  
  14. // Joe Smith
  15. $validation->setRules([
  16. 'contacts.name' => 'required'
  17. ]);
  18.  
  19. // Fred Flintsone & Wilma
  20. $validation->setRules([
  21. 'contacts.friends.name' => 'required'
  22. ]);

You can use the ‘*’ wildcard symbol to match any one level of the array:

  1. // Fred Flintsone & Wilma
  2. $validation->setRules([
  3. 'contacts.*.name' => 'required'
  4. ]);

Validate 1 Value

Validate one value against a rule:

  1. $validation->check($value, 'required');

Saving Sets of Validation Rules to the Config File

A nice feature of the Validation class is that it permits you to store allyour validation rules for your entire application in a config file. You organizethe rules into “groups”. You can specify a different group every time you runthe validation.

How to save your rules

To store your validation rules, simply create a new public property in the Config\Validationclass with the name of your group. This element will hold an array with your validationrules. As shown earlier, the validation array will have this prototype:

  1. class Validation
  2. {
  3. public $signup = [
  4. 'username' => 'required',
  5. 'password' => 'required',
  6. 'pass_confirm' => 'required|matches[password]',
  7. 'email' => 'required|valid_email'
  8. ];
  9. }

You can specify the group to use when you call the run() method:

  1. $validation->run($data, 'signup');

You can also store custom error messages in this configuration file by naming theproperty the same as the group, and appended with _errors. These will automaticallybe used for any errors when this group is used:

  1. class Validation
  2. {
  3. public $signup = [
  4. 'username' => 'required',
  5. 'password' => 'required',
  6. 'pass_confirm' => 'required|matches[password]',
  7. 'email' => 'required|valid_email'
  8. ];
  9.  
  10. public $signup_errors = [
  11. 'username' => [
  12. 'required' => 'You must choose a username.',
  13. ],
  14. 'email' => [
  15. 'valid_email' => 'Please check the Email field. It does not appear to be valid.'
  16. ]
  17. ];
  18. }

Or pass all settings in an array:

  1. class Validation
  2. {
  3. public $signup = [
  4. 'username' => [
  5. 'label' => 'Username',
  6. 'rules' => 'required',
  7. 'errors' => [
  8. 'required' => 'You must choose a {field}.'
  9. ]
  10. ],
  11. 'email' => 'required|valid_email'
  12. ];
  13.  
  14. public $signup_errors = [
  15. 'email' => [
  16. 'valid_email' => 'Please check the Email field. It does not appear to be valid.'
  17. ]
  18. ];
  19. }

See below for details on the formatting of the array.

Getting & Setting Rule Groups

Get Rule Group

This method gets a rule group from the validation configuration:

  1. $validation->getRuleGroup('signup');

Set Rule Group

This method sets a rule group from the validation configuration to the validation service:

  1. $validation->setRuleGroup('signup');

Running Multiple Validations

Note

run() method will not reset error state. Should a previous run fail,run() will always return false and getErrors() will returnall previous errors until explicitly reset.

If you intend to run multiple validations, for instance on different data sets or with differentrules after one another, you might need to call $validation->reset() before each run to get rid oferrors from previous run. Be aware that reset() will invalidate any data, rule or custom erroryou previously set, so setRules(), setRuleGroup() etc. need to be repeated:

  1. for ($userAccounts as $user) {
  2. $validation->reset();
  3. $validation->setRules($userAccountRules);
  4. if (!$validation->run($user)) {
  5. // handle validation errors
  6. }
  7. }

Working With Errors

The Validation library provides several methods to help you set error messages, providecustom error messages, and retrieve one or more errors to display.

By default, error messages are derived from language strings in system/Language/en/Validation.php, whereeach rule has an entry.

Setting Custom Error Messages

Both the setRule() and setRules() methods can accept an array of custom messagesthat will be used as errors specific to each field as their last parameter. This allowsfor a very pleasant experience for the user since the errors are tailored to eachinstance. If not custom error message is provided, the default value will be used.

These are two ways to provide custom error messages.

As the last parameter:

  1. $validation->setRules([
  2. 'username' => 'required|is_unique[users.username]',
  3. 'password' => 'required|min_length[10]'
  4. ],
  5. [ // Errors
  6. 'username' => [
  7. 'required' => 'All accounts must have usernames provided',
  8. ],
  9. 'password' => [
  10. 'min_length' => 'Your password is too short. You want to get hacked?'
  11. ]
  12. ]
  13. );

Or as a labeled style:

  1. $validation->setRules([
  2. 'username' => [
  3. 'label' => 'Username',
  4. 'rules' => 'required|is_unique[users.username]',
  5. 'errors' => [
  6. 'required' => 'All accounts must have {field} provided'
  7. ]
  8. ],
  9. 'password' => [
  10. 'label' => 'Password',
  11. 'rules' => 'required|min_length[10]',
  12. 'errors' => [
  13. 'min_length' => 'Your {field} is too short. You want to get hacked?'
  14. ]
  15. ]
  16. ]
  17. );

If you’d like to include a field’s “human” name, or the optional parameter some rules allow for (such as max_length),or the value that was validated you can add the {field}, {param} and {value} tags to your message, respectively:

  1. 'min_length' => 'Supplied value ({value}) for {field} must have at least {param} characters.'

On a field with the human name Username and a rule of min_length[6] with a value of “Pizza”, an error would display: “Supplied value (Pizza) for Username must haveat least 6 characters.”

Note

If you pass the last parameter the labeled style error messages will be ignored.

Getting All Errors

If you need to retrieve all error messages for failed fields, you can use the getErrors() method:

  1. $errors = $validation->getErrors();
  2.  
  3. // Returns:
  4. [
  5. 'field1' => 'error message',
  6. 'field2' => 'error message',
  7. ]

If no errors exist, an empty array will be returned.

Getting a Single Error

You can retrieve the error for a single field with the getError() method. The only parameter is the fieldname:

  1. $error = $validation->getError('username');

If no error exists, an empty string will be returned.

Check If Error Exists

You can check to see if an error exists with the hasError() method. The only parameter is the field name:

  1. if ($validation->hasError('username'))
  2. {
  3. echo $validation->getError('username');
  4. }

Customizing Error Display

When you call $validation->listErrors() or $validation->showError(), it loads a view file in the backgroundthat determines how the errors are displayed. By default, they display with a class of errors on the wrapping div.You can easily create new views and use them throughout your application.

Creating the Views

The first step is to create custom views. These can be placed anywhere that the view() method can locate them,which means the standard View directory, or any namespaced View folder will work. For example, you could createa new view at /app/Views/_errors_list.php:

  1. <div class="alert alert-danger" role="alert">
  2. <ul>
  3. <?php foreach ($errors as $error) : ?>
  4. <li><?= esc($error) ?></li>
  5. <?php endforeach ?>
  6. </ul>
  7. </div>

An array named $errors is available within the view that contains a list of the errors, where the key isthe name of the field that had the error, and the value is the error message, like this:

  1. $errors = [
  2. 'username' => 'The username field must be unique.',
  3. 'email' => 'You must provide a valid email address.'
  4. ];

There are actually two types of views that you can create. The first has an array of all of the errors, and is whatwe just looked at. The other type is simpler, and only contains a single variable, $error that contains theerror message. This is used with the showError() method where a field must be specified:

  1. <span class="help-block"><?= esc($error) ?></span>

Configuration

Once you have your views created, you need to let the Validation library know about them. Open Config/Validation.php.Inside, you’ll find the $templates property where you can list as many custom views as you want, and provide anshort alias they can be referenced by. If we were to add our example file from above, it would look something like:

  1. public $templates = [
  2. 'list' => 'CodeIgniter\Validation\Views\list',
  3. 'single' => 'CodeIgniter\Validation\Views\single',
  4. 'my_list' => '_errors_list'
  5. ];

Specifying the Template

You can specify the template to use by passing it’s alias as the first parameter in listErrors:

  1. <?= $validation->listErrors('my_list') ?>

When showing field-specific errors, you can pass the alias as the second parameter to the showError method,right after the name of the field the error should belong to:

  1. <?= $validation->showError('username', 'my_single') ?>

Creating Custom Rules

Rules are stored within simple, namespaced classes. They can be stored any location you would like, as long as theautoloader can find it. These files are called RuleSets. To add a new RuleSet, edit Config/Validation.php andadd the new file to the $ruleSets array:

  1. public $ruleSets = [
  2. \CodeIgniter\Validation\Rules::class,
  3. \CodeIgniter\Validation\FileRules::class,
  4. \CodeIgniter\Validation\CreditCardRules::class,
  5. ];

You can add it as either a simple string with the fully qualified class name, or using the ::class suffix asshown above. The primary benefit here is that it provides some extra navigation capabilities in more advanced IDEs.

Within the file itself, each method is a rule and must accept a string as the first parameter, and must returna boolean true or false value signifying true if it passed the test or false if it did not:

  1. class MyRules
  2. {
  3. public function even(string $str): bool
  4. {
  5. return (int)$str % 2 == 0;
  6. }
  7. }

By default, the system will look within CodeIgniter\Language\en\Validation.php for the language strings usedwithin errors. In custom rules, you may provide error messages by accepting a $error variable by reference in thesecond parameter:

  1. public function even(string $str, string &$error = null): bool
  2. {
  3. if ((int)$str % 2 != 0)
  4. {
  5. $error = lang('myerrors.evenError');
  6. return false;
  7. }
  8.  
  9. return true;
  10. }

Your new custom rule could now be used just like any other rule:

  1. $this->validate($request, [
  2. 'foo' => 'required|even'
  3. ]);

Allowing Parameters

If your method needs to work with parameters, the function will need a minimum of three parameters: the string to validate,the parameter string, and an array with all of the data that was submitted the form. The $data array is especially handyfor rules like require_with that needs to check the value of another submitted field to base its result on:

  1. public function required_with($str, string $fields, array $data): bool
  2. {
  3. $fields = explode(',', $fields);
  4.  
  5. // If the field is present we can safely assume that
  6. // the field is here, no matter whether the corresponding
  7. // search field is present or not.
  8. $present = $this->required($str ?? '');
  9.  
  10. if ($present)
  11. {
  12. return true;
  13. }
  14.  
  15. // Still here? Then we fail this test if
  16. // any of the fields are present in $data
  17. // as $fields is the lis
  18. $requiredFields = [];
  19.  
  20. foreach ($fields as $field)
  21. {
  22. if (array_key_exists($field, $data))
  23. {
  24. $requiredFields[] = $field;
  25. }
  26. }
  27.  
  28. // Remove any keys with empty values since, that means they
  29. // weren't truly there, as far as this is concerned.
  30. $requiredFields = array_filter($requiredFields, function ($item) use ($data) {
  31. return ! empty($data[$item]);
  32. });
  33.  
  34. return empty($requiredFields);
  35. }

Custom errors can be returned as the fourth parameter, just as described above.

Available Rules

The following is a list of all the native rules that are available to use:

Note

Rule is a string; there must be no spaces between the parameters, especially the “is_unique” rule.There can be no spaces before and after “ignore_value”.

  • “is_unique[supplier.name,uuid, $uuid]” is not ok
  • “is_unique[supplier.name,uuid,$uuid ]” is not ok
  • “is_unique[supplier.name,uuid,$uuid]” is ok
RuleParameterDescriptionExample
alphaNoFails if field has anything other than alphabetic characters.
alphaspaceNoFails if field contains anything other than alphabetic characters or spaces.
alpha_dashNoFails if field contains anything other than alphanumeric characters, underscores or dashes.
alpha_numericNoFails if field contains anything other than alphanumeric characters.
alpha_numeric_spaceNoFails if field contains anything other than alphanumeric or space characters.
alpha_numeric_punctNoFails if field contains anything other than alphanumeric, space, or this limited set ofpunctuation characters: ~ (tilde), ! (exclamation), # (number), $ (dollar), % (percent),& (ampersand), * (asterisk), - (dash), (underscore), + (plus), = (equals),| (vertical bar), : (colon), . (period).
decimalNoFails if field contains anything other than a decimal number.Also accepts a + or - sign for the number.
differsYesFails if field does not differ from the one in the parameter.differs[field_name]
exact_lengthYesFails if field is not exactly the parameter value. One or more comma-separated values.exact_length[5] or exact_length[5,8,12]
greater_thanYesFails if field is less than or equal to the parameter value or not numeric.greater_than[8]
greater_than_equal_toYesFails if field is less than the parameter value, or not numeric.greater_than_equal_to[5]
hexNoFails if field contains anything other than hexadecimal characters.
if_existNoIf this rule is present, validation will only return possible errors if the field key exists,regardless of its value.
in_listYesFails if field is not within a predetermined list.in_list[red,blue,green]
integerNoFails if field contains anything other than an integer.
is_naturalNoFails if field contains anything other than a natural number: 0, 1, 2, 3, etc.
is_natural_no_zeroNoFails if field contains anything other than a natural number, except zero: 1, 2, 3, etc.
is_not_uniqueYesChecks the database to see if the given value exist. Can ignore records by field/value tofilter (currently accept only one filter).is_not_unique[table.field,where_field,where_value]
is_uniqueYesChecks if this field value exists in the database. Optionally set acolumn and value to ignore, useful when updating records to ignore itself.is_unique[table.field,ignore_field,ignore_value]
less_thanYesFails if field is greater than or equal to the parameter value or not numeric.less_than[8]
less_than_equal_toYesFails if field is greater than the parameter value or not numeric.less_than_equal_to[8]
matchesYesThe value must match the value of the field in the parameter.matches[field]
max_lengthYesFails if field is longer than the parameter value.max_length[8]
min_lengthYesFails if field is shorter than the parameter value.min_length[3]
numericNoFails if field contains anything other than numeric characters.
regex_matchYesFails if field does not match the regular expression.regex_match[/regex/]
permit_emptyNoAllows the field to receive an empty array, empty string, null or false.
requiredNoFails if the field is an empty array, empty string, null or false.
required_withYesThe field is required when any of the other required fields are present in the data.required_with[field1,field2]
required_withoutYesThe field is required when all of the other fields are present in the data but not required.required_without[field1,field2]
stringNoA generic alternative to the alpha* rules that confirms the element is a string
timezoneNoFails if field does match a timezone per timezone_identifiers_list
valid_base64NoFails if field contains anything other than valid Base64 characters.
valid_jsonNoFails if field does not contain a valid JSON string.
valid_emailNoFails if field does not contain a valid email address.
valid_emailsNoFails if any value provided in a comma separated list is not a valid email.
valid_ipNoFails if the supplied IP is not valid. Accepts an optional parameter of ‘ipv4’ or‘ipv6’ to specify an IP format.valid_ip[ipv6]
valid_urlNoFails if field does not contain a valid URL.
valid_dateNoFails if field does not contain a valid date. Accepts an optional parameterto matches a date format.valid_date[d/m/Y]
valid_cc_numberYesVerifies that the credit card number matches the format used by the specified provider.Current supported providers are: American Express (amex), China Unionpay (unionpay),Diners Club CarteBlance (carteblanche), Diners Club (dinersclub), Discover Card (discover),Interpayment (interpayment), JCB (jcb), Maestro (maestro), Dankort (dankort), NSPK MIR (mir),Troy (troy), MasterCard (mastercard), Visa (visa), UATP (uatp), Verve (verve),CIBC Convenience Card (cibc), Royal Bank of Canada Client Card (rbc),TD Canada Trust Access Card (tdtrust), Scotiabank Scotia Card (scotia), BMO ABM Card (bmoabm),HSBC Canada Card (hsbc)valid_cc_number[amex]

Rules for File Uploads

These validation rules enable you to do the basic checks you might need to verify that uploaded files meet your business needs.Since the value of a file upload HTML field doesn’t exist, and is stored in the $_FILES global, the name of the input field willneed to be used twice. Once to specify the field name as you would for any other rule, but again as the first parameter of allfile upload related rules:

  1. // In the HTML
  2. <input type="file" name="avatar">
  3.  
  4. // In the controller
  5. $this->validate([
  6. 'avatar' => 'uploaded[avatar]|max_size[avatar,1024]'
  7. ]);
RuleParameterDescriptionExample
uploadedYesFails if the name of the parameter does not match the name of any uploaded files.uploaded[field_name]
max_sizeYesFails if the uploaded file named in the parameter is larger than the second parameter inkilobytes (kb).max_size[field_name,2048]
max_dimsYesFails if the maximum width and height of an uploaded image exceed values. The first parameteris the field name. The second is the width, and the third is the height. Will also fail ifthe file cannot be determined to be an image.max_dims[field_name,300,150]
mime_inYesFails if the file’s mime type is not one listed in the parameters.mime_in[field_name,image/png,image/jpg]
ext_inYesFails if the file’s extension is not one listed in the parameters.ext_in[field_name,png,jpg,gif]
is_imageYesFails if the file cannot be determined to be an image based on the mime type.is_image[field_name]

The file validation rules apply for both single and multiple file uploads.

Note

You can also use any native PHP functions that permit upto two parameters, where at least one is required (to passthe field data).