Data validation is important to the proper functioning of any application. There are two opportunities to validate data entered via web forms. You can use a client-side scripting solution like JavaScript that performs certain validation rules before submitting the form data. The advantage to this approach is that the user does not have to wait for the data to be submitted to your application, validated and returned. The disadvantage is that client-side scripting is optional on browsers and sometimes poorly supported. The alternative to client-side scripting is to validate your data when it is returned to your application. One downside to this is the added complexity of developing an interface that validates data and displays errors. Marmot employs only server-side validation. Most of the added complexity of server-side validation is handled behind-the-scenes by Marmot.
Examples can be found in the "Forms- Validation" example included with Marmot.
Validation rules are applied to form input items as an attribute named "validate". The format of the rule a colon separated list of rules. For example:
Since this is an item of type "numeric," it is automatically validated as a number. The validate rules "required:max=4:min=0" specify that the element is required and must be between 0 and 4.
The order of the rules is not important. However, if multiple rules are applied to an element, the validation process will throw a warning on the first violation and stop processing that element. All elements on the current form are processed for errors at the same time.
There are several rules that can be applied to fields. The type of data determines what rules are applicable and how the validation behaves. Many rules support a limit value to use as a comparison. The limit value can either be explicitly supplied, can be the value of another form field, or can even be calculated.
Table 11.2. Validation rules
| Rule | Applicable Types | Description |
|---|---|---|
| required | all | Causes the specified field to fail if no value is specified (null or empty). |
| number | numeric | Causes any data entered in the specified field to be validated as numeric. |
| integer | numeric | Causes any data entered in the specified field to be validated as an integer value. |
| date | date, time, datetime | Causes any date entered in the specified field to be validated as a valid date (date, time and date/time are supported). Use of the date rule requires that a valid format attribute also be included for the field. The format is used to both validate and format the input. |
| max=limit | numeric, date, time, datetime | The value in the specified field cannot exceed the value given as the limit (see the description of limits below). |
| min=limit | numeric, date, time, datetime | The value in the specified field cannot be below the value given as the limit (see the description of limits below). |
| default=value | all | The default value is used if the specified field is empty (not valid with the required rule). |
| maxlength=limit | all | Specifies the maximum number of characters allowed in the value. The value is treated as a string. |
| minlength=limit | all | Specifies the minimum number of characters allowed in the value. The value is treated as a string. |
| pattern=pattern|mask | all | Provides a pattern used to test the value. The pattern can be given as a named pattern or as a Perl compatible regular expression. The entire value must be represented by the pattern or the validation will fail. A mask may also be provided to cause the data to be returned in a specific format. Please refer to the section on pattern matching and input masks below for a full description. |
| callback=function_name | all | Provides a developer-defined function to be used to test the value. Please refer to the section on callbacks below for a full description. |
Some rules take limit arguments. The valid types of limits are explained in the following table:
Table 11.3. Acceptable limit values
| Rule | Description |
|---|---|
| string | Any valid string data (alphanumeric, date, etc). |
| calc(formula,base_value) | Calculates a new value by applying formula to base_value. Currently only available for the "date" rule. The formula must be a value acceptable to PHP's strtotime function (eg '+1 year'). The base_value may be either an explicit date value or a reference to another form field. |
| {form_field} | Any other form field can be used as a limit to another. |
Here are some examples of validation rules:
'required:number'
'required:integer'
'required:integer:max=10:min={lower}'
"date:max=calc('+1 year', '{lower}')"
Sometimes it is not sufficient to validate what the data is or is not. Rather, it must be validated by what it looks like: its pattern. By utilizing PHP's Perl compatible regular expresssion syntax, we are able to easily implement a pattern matching validation rule. Many common patterns will be provided by name and developers can supply any pattern they can create.
The pattern validation rule serves two purposes, the first is to validate if the data matches a specified pattern. The second is to manipulate that data so it matches a specific pattern. For example, consider a typical American style telephone number. It may legitimately be entered in a number of patterns, such as (513) 529-1809, 513.529.1809 or 513-529-1809. However, for consistency, the telephone number should always be stored as (513) 529-1809 in the database. A pattern validation rule will insure the telephone number is one of the acceptable patterns while an input mask will make it look correct.
The implementation of pattern matching and input masks are combined in one validation rule because they are intricately tied together. This can be somewhat confusing, but is the only effective way of specifying them. You can specify both a pattern and input mask or only one of them. In some cases, such as the telephone number, it does not make sense to specify a mask without a pattern, but you may want to specify a pattern without a mask. Likewise, using a pattern with the uppercase mask is not necessary.
When providing pattern and/or input mask rules, you must observe the following:
patterns and masks are separated by a bar (|)
patterns (named or custom) may stand alone: "pattern=american_phone"
to use a pattern and a mask, you must specify both: "pattern=american_phone|american_phone"
to use only a mask, you must precede it with a bar: "pattern=|uppercase"
The following predefined patterns available for pattern validation:
Table 11.4. Predefined Patterns
| Name | Pattern | Usage | Description |
|---|---|---|---|
| american_phone | /\(?(\d{3})\)?[- ]?(\d{3})[- ]?(\d{4})/|($1) $2-$3 | pattern and mask | Accepts American style phone numbers with optional parenthesis, spaces and hyphens. |
| email_address | /^\w(?:\w|-|\.(?!\.|@))*@\w(?:\w|-|\.(?!\.))*\.\w+/ | pattern | Accepts a correctly formatted email address. It does not validate the address or domain, only its pattern. |
| url_http | /\Ahttps?:\/\/.+/ | pattern | Accepts a (mostly) correctly formatted http or https URL. It does not validate the address or domain, only its pattern. |
| social_security_number | /(\d{3})-?(\d{2})-?(\d{4})/|$1-$2-$3 | pattern and mask | Accepts a correctly formatted Social Security Number with optional hyphens. |
| banner_plus_number | /\+\d{8}/ | pattern | Accepts a correctly formatted Miami University Banner Plus Number. |
| uppercase | /(.*)/e|strtoupper(\'$1\') | mask | Converts the input string to uppercase. |
| lowercase | /(.*)/e|strtolower(\'$1\') | mask | Converts the input string to lowercase. |
There are two possible outcomes to data validation, it either passes or it fails. The outcome will determine where the user is sent next:
failure: If any of the rule validations fail, the user is redirected to the referring page, where the incorrectly completed input items are highlighted. If you provided an error attribute for that input item, it is displayed, otherwise a generic error message is displayed.
success: If the validation succeeds (no fatal errors are encountered), the validation script will redirect the user to the script specified as the form action.
If you would like to perform a validation that is not directly supported by Marmot, you can create your own validation functions via a "callback" validation rule.
If, for example, we wished to make sure that a name entered by a user was a character on Scooby Doo, we might do the following:
Since validation is performed before our script is parsed, the function specified in the callback rule must reside in the application's Application.php file. The function is_on_scooby_doo might look like this:
Though only one is used in the example above, Marmot passes four arguments to a validation callback function: the value entered by the user, the name of the form element in which the value was entered, the type of input given ("text", "date", "date_struct", "time_struct", or "datetime_struct"), and the data format parameter, if one was specified. A validation callback function is expected to return true on success and false and an error message on failure.
The validated attribute of a form object will indicate if the data in the form has been validated. There are three possible values:
- null
The data has not been validated.
- true
A boolean true, indicates that data has passed all validation.
- false
A boolean false, indicates that the data has failed at least one validation rule.