Validate

The Validate class provides a comprehensive form validation and data prepping class that helps minimize the amount of code you'll write.

Form

Here's an example form we may use to perform validation, save it in the "application/views" folder as "my_form.php":

<form action="" method="post" name="sample">
	<? if ( validate::getTotalErrors() ): ?>
		<div><?=validate::getErrors()?></div>
	<? endif; ?>
	<p>First name</p>
	<input type="text" name="first_name" value="" size="50" />
	<p>Last name</p>
	<input type="text" name="last_name" value="" size="50" />
	<p>Email</p>
	<input type="text" name="email" value="" size="50" />
	<p>Password</p>
	<input type="password" name="password" value="" size="50" />
	<p>Confirm password</p>
	<input type="password" name="password2" value="" size="50" />
	<div><input type="submit" name="submit" value="Submit" /></div>
</form>

Notice the code in the beginning of the form that checks if there are any errors, and displays them if any exist.

The controller

Now create a controller called "form.php" in "application/controllers" folder with the following code in it:

class Form_Controller extends Controller
{
	public function index()
	{
		if ( input::postCount() )
		{
			if ( $this->validate_form() )
			{
				die("Success");
			}
		}

		view::load('my_form');
	}

	private function validate_form()
	{
		return true;
	}
}

If you open it in your browser and submit the form, you will get "Success" message since no validation is being done at this point.

Validation rules

Let's update the "validate_form" function with this code:

private function validate_form()
{
	$rules = array(
		'first_name' => array(
			'label' => 'first name',
			'rules' => array('trim', 'required', 'min_length' => 2, 'max_length' => 30)
		),
		'last_name' => array(
			'label' => 'last name',
			'rules' => array('trim', 'required', 'min_length' => 2, 'max_length' => 30)
		),
		'email' => array(
			'label' => 'email',
			'rules' => array('trim', 'required', 'max_length' => 255, 'valid_email')
		),
		'password' => array(
			'label' => 'password',
			'rules' => array('trim', 'required', 'min_length' => 5, 'max_length' => 50)
		),
		'password2' => array(
			'label' => 'confirm password',
			'rules' => array('matches' => 'password')
		),
	);

	validate::setRules($rules);

	if ( !validate::run() )
	{
		return false;
	}

	return true;
}

Now if you submit the empty form, you will see error messages. The form fields are not pre-populated at this point, we'll get to it shortly.

Settings rules

The $rules array contains a bunch of rules for every form field we have:

  • First rule removes blank spaces around the first name, makes sure that it's not empty and is at least 2 characters but no more than 30.
  • Last name rules are the same.
  • With the email we use a built-in "valid_email" function to validate email address.
  • And with the second password, we use "matches" function to make sure it matches the first password field.

Each of these rules has a "label" item which stores the field name which is used in error messages.

Repopulating the form

Now that we've figured out how to perform validation, it's time to repopulate form values since nobody will want to refill the same values over and over again. We'll be using the "setValue" function from the "form" helper which looks like this:

<form action="" method="post" name="sample">
	<? if ( validate::getTotalErrors() ): ?>
		<div><?=validate::getErrors()?></div>
	<? endif; ?>
	<p>First name</p>
	<input type="text" name="first_name" value="<?=form_helper::setValue('first_name')?>" size="50" />
	<p>Last name</p>
	<input type="text" name="last_name" value="<?=form_helper::setValue('last_name')?>" size="50" />
	<p>Email</p>
	<input type="text" name="email" value="<?=form_helper::setValue('email')?>" size="50" />
	<p>Password</p>
	<input type="password" name="password" value="<?=form_helper::setValue('password')?>" size="50" />
	<p>Confirm password</p>
	<input type="password" name="password2" value="<?=form_helper::setValue('password2')?>" size="50" />
	<div><input type="submit" name="submit" value="Submit" /></div>
</form>

Try reloading the page and submitting the form again. If you get any errors, your form values you've filled in should still be there.

Custom validation functions

Validation class allows you to create your own validation functions. Update "email" validation rule to the following:

'rules' => array('trim', 'required', 'max_length' => 255, 'valid_email', 'callback__educational_emails')

And add this function in the controller:

public function _educational_emails($value)
{
	if ( strtolower(substr($value, -4)) != '.edu' )
	{
		validate::setError('_educational_emails', '%s must contain a value that ends with .edu');
		return false;
	}

	return true;
}

If you submit the form now, only email that end with ".edu" will be accepted. Note that "%s" will be replaced with the field's "label". In addition to that, you may pass parameters to your validation function. Update your "email" rules to the following:

'rules' => array('trim', 'required', 'max_length' => 255, 'valid_email', 'callback__educational_emails' => ".edu")

And your custom validation function will look like this:

public function _educational_emails($value, $domain)
{
	if ( strtolower(substr($value, -4)) != $domain )
	{
		validate::setError('_educational_emails', '%s must contain a value that ends with .edu');
		return false;
	}

	return true;
}

You may pass one parameter or as many parameters as you like via array.

Individual errors

To display errors individually next to the field where user made an error, we should modify our form like this:

<form action="" method="post" name="sample">
	<p>First name</p>
	<input type="text" name="first_name" value="<?=form_helper::setValue('first_name')?>" size="50" />
	<?=validate::getErrors('first_name')?>
	<p>Last name</p>
	<input type="text" name="last_name" value="<?=form_helper::setValue('last_name')?>" size="50" />
	<?=validate::getErrors('last_name')?>
	<p>Email</p>
	<input type="text" name="email" value="<?=form_helper::setValue('email')?>" size="50" />
	<?=validate::getErrors('email')?>
	<p>Password</p>
	<input type="password" name="password" value="<?=form_helper::setValue('password')?>" size="50" />
	<?=validate::getErrors('password')?>
	<p>Confirm password</p>
	<input type="password" name="password2" value="<?=form_helper::setValue('password2')?>" size="50" />
	<?=validate::getErrors('password2')?>
	<div><input type="submit" name="submit" value="Submit" /></div>
</form>

Available rules

You may use any native PHP function that accepts one parameter such as htmlspecialchars, trim, MD5, etc. Below is a reference for built-in rules in the validation class that are also available.

required

Return false if value is empty.

required_file

Returns false if file was not selected. Used only with "file" element.

'required_file' => 'my_file' // 'my_file' is the name of the 'file' form element

matches

Returns false is value does not match specified element.

'matches' => 'password' // 'password' is the name of the form element we're match against

regex

Returns false if specified regular expression fails.

'regex' => '/^[A-Z]+$/' // allow only upper case letters

min_length

Returns false if value is shorter than specified number.

'min_length' => 10 // minimum 10 characters

max_length

Returns false if value is longer than specified number.

'max_length' => 50 // maximum 50 characters

exact_length

Returns false if value is not exact length as the specified number.

min_value

Returns false if value is smaller than specified number.

max_value

Returns false if value is bigger than specified number.

exact_value

Returns false if value does not equal to specified number.

valid_url

Returns false if URL is not valid.

valid_email

Returns false if email is not valid.

valid_ip

Returns false if IP address is not valid.

valid_date

Returns false if value is not an array or does not contain valid items such as year, month and day.

alpha

Returns false if value contains anything other than alphabetical characters.

alpha_numeric

Returns false if value contains anything other than alpha-numeric characters.

alpha_dash

Returns false if value contains anything other than alpha-numeric characters, underscores or dashes.

numeric

Returns false if value contains anything other than numeric characters.

is_numeric_no_zero

Returns false if value contains anything other than a number, but not zero: 1, 2, 3, etc.

integer

Returns false if value contains anything other than an integer.

is_natural

Returns false if value contains anything other than a natural number: 0, 1, 2, 3, etc.

is_natural_no_zero

Returns false if value contains anything other than a natural number, but not zero: 1, 2, 3, etc.

is_captcha

Returns false if client did not fill in security image correctly.