Introduction - validation and filters

Introduction - validation and filters – How to process submitted data

Validation rules

QuickForm makes client-side and server-side form validation easy. It allows for validation against regular expressions or custom functions and methods. You can define your own validation rules and apply them to the elements or groups you want. In this section, we will explore the different possibilities QuickForm offers to make validation easier.

QuickForm can verify if required elements are filled when the form is submitted. This works with every type of elements or groups, integer 0 is not considered as an empty value.

<?php
require_once 'HTML/QuickForm.php';

$form = new HTML_QuickForm('myform''post');
$form->addElement('text''email''Your email:');
$form->addElement('submit''submit''Submit');

// Validation rules

$form->addRule('email''E-Mail is required''required');

// Validation

if ($form->validate()) {
    
$form->freeze();
}
$form->display();
?>
On empty elements validation

If the element is empty, no validation rules other than required are checked for it. This means that empty element can be invalid only when it is required.

On required uploads

required rule does not work for file elements. Use uploadedfile.

The HTML_QuickForm::validate() method will scan through each rules in the order they have been set. If a rule is not validated, the error message corresponding to the element will be displayed and the form will be shown once again. You can use templates to set the position of this error message. The order you decide to set your validation rules is important because it will determine which error message is used.

Client-side validation

QuickForm can generate the javascript necessary to validate the form on the client side. This feature works for all standard elements and for groups. Server side validation is always performed in case the client has javascript turned off.

<?php
$form
->addRule('email''E-Mail is required''required'null'client');
?>

By setting the parameter 'client', you trigger the javascript automatic generation.

Built-in validation rules

QuickForm offers a few registered rules that are often used when validating forms. Some of the rules may need an extra $format parameter passed to addRule() / addGroupRule() to work properly.

List of built-in validation rules
Name Description $format parameter
required value is not empty  
maxlength value must not exceed given number of characters number of characters, integer
minlength value must have more than given number of characters number of characters, integer
rangelength value must have between min and max characters array(min characters, max characters)
regex value must pass the regular expression regular expression to check, string
email value is a correctly formatted email whether to perform an additional domain check via checkdnsrr() function, boolean
lettersonly value must contain only letters  
alphanumeric value must contain only letters and numbers  
numeric value must be a number  
nopunctuation value must not contain punctuation characters  
nonzero value must be a number not starting with 0  
compare The rule allows to compare the values of two form fields. This can be used for e.g. 'Password repeat must match password' kind of rule. Please note that you need to pass an array of elements' names to compare as a first parameter to addRule().

Type of comparison to perform, string:

'eq' or '=='
(default) the elements should have the same values
'neq' or '!='
the elements should have different values
'gt' or '>'
first element's value should be greater (compared as numbers)
'gte' or '>='
first element's value should be greater or equal (compared as numbers)
'lt' or '<'
first element's value should be smaller (compared as numbers)
'lte' or '<='
first element's value should be smaller or equal (compared as numbers)
callback This rule allows to use an external function/method for validation. This can be done either explicitly, by passing a callback as a format parameter or implicitly, by registering it via registerRule(). Function/method to use, callback.
Validation rules for file uploads
uploadedfile required file upload  
maxfilesize the file size must not exceed the given number of bytes maximum file size, integer
mimetype the file must have a correct MIME type either a string for single allowed MIME type, or an array of allowed MIME types
filename the filename must match the given regex regular expression to test, string
On rules for file uploads

These rules are defined in HTML/QuickForm/file.php, and are automatically registered when a file type element is added to the form. These rules are server-side only, for obvious reasons.

Usage of builtin rules is covered in rules-builtin.php example provided with the package. The rules-custom.php example covers the usage of custom rule classes and callback type rules. It also contains a NumericRange class for checking whether a number is between a maximum and a minimum.

Validation classes

Since release 3.2 all builtin validation is performed by subclasses of HTML_QuickForm_Rule class. You can create your own subclass of it and implement validate() and getValidationScript() methods. Consult the source for the examples.

Validation functions and methods

When you need a more complex validation, QuickForm can use your own custom-made functions to validate an element or a group. QuickForm can also call a method of a class. This way, it is possible to use PEAR's Validate package or any other class. If you want to use your own functions, you basically have two options:

  1. Register the function via registerRule() using 'callback' as $type and giving the new rule a custom $ruleName. Later you add the rule with this name via addRule() like any buitin rule.

  2. Add the rule of callback type via addRule() passing the name of your function as $format. This way you'll have less characters to type, but will be unable to pass additional data to your function.

Email validation function

<?php
/**
 * Validate an email address
 *
 * @param string    $email         Email address to validate
 * @param boolean   $domainCheck   Check if the domain exists
 */
function checkEmail($email$domainCheck false)
{
    if (
preg_match('/^[a-zA-Z0-9\._-]+\@(\[?)[a-zA-Z0-9\-\.]+'.
                   
'\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/'$email)) {
        if (
$domainCheck && function_exists('checkdnsrr')) {
            list (, 
$domain)  = explode('@'$email);
            if (
checkdnsrr($domain'MX') || checkdnsrr($domain'A')) {
                return 
true;
            }
            return 
false;
        }
        return 
true;
    }
    return 
false;
}
$form->registerRule('checkmail''callback''checkEmail');
$form->addRule('email''Email is incorrect''checkmail'true);
?>

You can pass an extra parameter of the type you want to your function when set with HTML_QuickForm::addRule(). Here we used TRUE to enable the DNS check of our function.

If you use a method, you must specify the class your method is in. Use this syntax when you register your rule:

<?php
// Method checkEmail is in class Validate
$form->registerRule('checkmail''callback''checkEmail''Validate');
?>

You can also use a javascript function to validate your form, give it the same name as your PHP function, have it return a boolean and set the 'client' parameter.

Group validation

Groups of elements can be validated the same way other elements are, or use a more complex validation scheme. To validate a group as a whole, just use HTML_QuickForm::addRule(). The group elements' values will be passed to the validation function as an array.

You can have more complex validation for your groups using the HTML_QuickForm::addGroupRule() method. This allows for a per element validation. It also makes it possible to specify the number of elements that need to be valid for the group to be valid too.

Complex group validation

<?php
// Group
$id[] = &HTML_QuickForm::createElement('text''username''Username');
$id[] = &HTML_QuickForm::createElement('text''code''Code');
$form->addGroup($id'id''Your ID:''-');

// Validation rules per element

$rule['username'][] = array('Username is required''required');
$rule['username'][] = array('Username contains only letters''lettersonly');
$rule['username'][] = array('Username has between 5-8 characters''rangelength', array(58));

$rule['code'][] = array('Code is required''required');
$rule['code'][] = array('Code contains numbers only''regex''/^\d+$/');
$rule['code'][] = array('Code is 5 numbers long''rangelength', array(55));

$form->addGroupRule('id'$rule);
?>

In this example, we have set rules for the elements inside our group. Instead of using their names, we could have used their index (determined by the order they were created) in the group, it would speed up the validation process.

The following example takes the same group and will validate the form only if at least one of our two elements is not empty. To achieve this, we use the howmany parameter and set it to 1.

<?php
$form
->addGroupRule('id''Fill at least one element''required'null1);
?>

Conclusion

You have seen that QuickForm makes it easy to validate your elements and groups without having to write all the usually necessary code to find the different values. It takes care of required elements, generates the javascript automatically and adds a lot of flexibility by allowing you to use your own validation functions and regular expressions. It's time to experiment...

Filters

If we add a rule like

<?php
$form
->addRule('element''The element is required''required');
?>

to the form, then any input will satisfy it, including, for example, a single space. This is because the rule simply ensures that there are one or more characters present, and a space character satisfies the rule.

Of course this can be fixed by making a custom regex rule, but there is an easier solution. We usually do not care about leading and trailing spaces at all, and we can make the element's value pass through builtin trim() function before doing any validation on it:

<?php
$form
->applyFilter('element''trim');
?>

Filters are applied recursively, which means that trim() on an array will work, too. You can pass any valid callback as an argument to applyFilter() method.

Use filters if you want to 'sanitize' user input and do not really care about invalid values.