Form Field Validation with Drupal 6
Drupal provides a number of ways to validate form fields. Firstly, Drupal itself performs a good deal of field validation automatically. This validation includes:
- Ensure all mandatory fields are filled in
- Ensure all multiple choice elements (ie. Radios, checkboxes and option pull-down menus) return only values that were supplied on the form
- Ensure all free-form elements (ie. Text areas and text fields) do not contain more information that the form allowed
- Ensure all file uploads are handled correctly and are appropriately sized (although most upload work is handled by the upload module)
- Ensure the submitted form data correlates to a recently delivered form (to defend against Cross Site Scripting attacks)
Despite all this validation, it's often necessary to do even more, usually on text fields. In complex applications validation may have to include checks on multiple elements simultaneously (e.g. If a checkbox is selected, then a text field must also be filled in).
Form Builder _validate() Functions
Drupal provides a number of API facilities to help developers validate form input. The first is the most common way to validate forms: the formbuilder_validate() function. For example, consider a module containing the following:
<?php
function mymodule_menu() {
$items['path/to/form'] = array(
'title' => 'My Form',
'page callback' => 'drupal_get_form',
'page arguments' => array('mymodule_form'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
function mymodule_form() {
$form = array();
$form['text'] = array(
'#type' => 'textfield',
'#title' => t('Enter some text'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
?>The above module could use an _validate() function like this:
<?php
function mymodule_form_validate($form, &$form_state) {
$uc = strtoupper($form_state['values']['text']);
if($form_state['values']['text'] != $uc) {
form_set_error('text', t('The text must be in capital letters only.'));
}
}
?>In the above example, the validator checks to make sure the text entered is entirely in capital letters. If any lower case letters are entered, then the form will return an error to the user when submitted. Note the function need not return success or failure to the API, simply specifying an error with form_set_error() is sufficient.
The Forms API can call a differently named function if required. This is specified with the '#validate' form element. It specified an array, each element of which is a form validator function. For example:
<?php
$form['#validate'] = array('mymodule_generic_validator');
?>However it is named, the validation function is always called with $form and a reference to $form_state. Any parameters specified in the drupal_get_form() that called the original form are also passed to the function after these two.
The $form variable contains the form shown to the user that they have now filled in and submitted to the system. The $form_state variable is an array containing a series of elements. These are described in detail in the API documentation, suffice to say the major elements are:
- storage – Free form persistent storage, useful for storing information between validate and submit phases of form processing
- values – The values of the form elements supplied by the user (in Drupal 5 this used to be called $form_values).
- submitted – set to TRUE if the form has been submitted rather than just posted. In other words, if the user pressed a 'submit' button this is TRUE, or false if they pressed a 'button'.
- clicked_button – the form element of the button that the user pressed to submit the form
With these items of information, it's possible to completely decompose the actions of the user and correctly validate the form. However, in some cases it's overly complicated to do so this way. Helpfully, the API provides another means: form element validation.
Form Element Validation
The API allows for each element to have it's own validator. This is achieved with the '#element_validate' form item. For example:
<?php
$form['example'] = array(
'#type' => 'textfield',
'#title' => 'Example Text',
'#element_validate' => array('mymodule_element_validator'),
);
?>In this case, the element validator is called with the same parameters as the form level validator above, except $form is just the element that requires validation. The $form['#value'] contains the information entered by the user, so it is this that can be checked for validation. The $form['#tree'] contains the hierarchy in the $form array this element is at in the original form, with #name specifying it's actual element name (not to be confused with #title). These may be used to determine the type of validation that needs to take place.
Element level validation provides an easy way to validate lots of similar form elements. For example, if every textfield on the form was supposed to capture a number, then each one could have specify a single element validator function that checks #value is a number. Indeed, it could be possible to call multiple validators in turn, perhaps to check if a value was a number, and then to check it was a positive integer.
Other Methods
It's possible to write all kinds of helper functions for field validation. For an example of one of these see the The Extra Validate Module.
