Input validation, error messages and exception handling the Cotonti way
1. Input and validation
As a PHP coder you might be used to $_GET, $_POST, $_COOKIE and such, but raw user input is not always good for your security and data integrity. That's why in Cotonti we import all data with cot_import() function:
function cot_import($name, $source, $filter, $maxlen = 0, $dieonerror = false, $buffer = false)
$name - the name of the input in the HTML form.
$source - source type of the data. Possible values are:
'G' or 'GET' - for GET parameters;
'P or 'POST' - for POST data;
'C' or 'COOKIE' - to import data from cookies;
'R' or 'REQUEST' - to import from PHP's $_REQUEST;
'D' or 'DIRECT' - used to filter data passed in the $name argument;
'PUT' - to import data from HTTP PUT request (for REST services);
'DELETE' - to import data from HTTP DELETE request (for REST);
'PATCH' - to import data from HTTP PATCH request (for REST).
$filter - filter name against which the data is validated. Supported filters:
'ALP' - passes digits, latin alphabet characters, dashes and underscores, useful for identifiers;
'ARR' - imports an unfiltered array, each array item needs further validation after this import;
'BOL' - import for booleans and checkboxes, returns TRUE if the input is checked or positive, FALSE if it is unchecked or zero and NULL if the input was not present in the form which sent the data;
'HTM' - passes any text and trims whitespace from the beginning and ending of it, HTML is passed by this filter;
'INT' - passes integer values only, a PHP (int) is returned or NULL if validation fails;
'NOC' - no check/encoding, passes everything as is;
'NUM' - passes numeric values only, PHP (float) is returned or NULL if validation fails;
'PSW' - special filter for passwords, removes quotes , &, <, > from input and limits its length to 32 characters;
'TXT' - filter accepting plain text except for HTML, in HTML some characters are replaced with HTML entities on import;
$maxlen - limits max. lenght of the input, 0 means unlimited;
$dieonerror - stop script execution with a fatal error if validation fails;
$buffer - enables import buffer feature, used by Forms API.
The returned value is either a value with a filter applied or NULL if validation failed and a user must enter another value instead. Here are some example calls:
$title = cot_import('title', 'P', 'TXT');
$code = cot_import('code', 'P', 'ALP');
$count = cot_import('count', 'P', 'INT');
$text = cot_import('text', 'P', 'HTM');
$notify = cot_import('notify', 'P', 'BOL');
After you have imported the values, you might want to check them against some value (first of all NULL which is returned if the input was not present or validation failed against the filter) and emit an error message.
In a verbose form you could do it like this:
cot_error('Please enter a correct integer count', 'count');
cot_error() is a standard way to inform the system that something went wrong and to emit an error message that can be displayed later on. It has two parameters:
$message - message text or language string code for the message to be displayed. E.g. if there is a language string $L['my_err_msg'] in connected language files, you can just pass 'my_err_msg' and localized message will be displayed to a user.
$src - name of the input where wrong data was entered (optional), this is used to display the error message next to the input depending on template configuration.
There is actually a shorter (and recommended) way to combine "if" and "cot_error()" call in case of error:
cot_check(is_null($count), 'Please enter a correct integer count', 'count');
cot_check() function has parameters:
$condition - a boolean expression which checks for an error, if it evaluates to TRUE, then the error will be triggered;
$message - error message displayed if $condition is TRUE, same as in cot_error();
$src - input name (optional) for the source of invalid data, same as in cot_error().
You should check whether any errors have been found in the system before proceeding to action such as saving data in database using cot_error_found() function:
// OK, we can save our data here because validation passed
This is it, now you know the basics of input validation in Cotonti.
2. Emitting messages and using other functions
Not all messages are error messages. You might as well inform the user that some operation ended successfully or warn him about something non-critical. Cotonti's messages API covers those cases too.
Here is the list of other Errors and Messages API functions:
Most of these functions are rather advanced and you will never have to use it in your modules or plugins. Let's have a look at the most common ones.
cot_message() function is similar to cot_error() but it is more generic. Here is the list of its parameters:
$text - message text or language string code;
$class - type or CSS class of the message, common values are 'error', 'success', warning', 'ok';
$src - source input name where the message was caused, used to display the message next to it in some configurations.
Use this function to inform the user about operation status when handling forms and returning back to the normal page:
cot_check($some_input != '', 'some_err_msg', 'some_input');
// Save the data...
// Emit the message
cot_message('New item added successfully');
// Return to the interface
Use cot_die() if something went wrong and you want to prevent further script execution:
// How did the user get here?
If that "something went wrong" is a standard situation that can be represented with a common HTTP error code and message, then use cot_die_message() function providing an error code:
// Print a standard 404 page with a correct HTTP code
You can also use cot_die_message() to handle non-standard errors and pass error page title and contents as 3rd and 4th arguments.
3. Displaying messages
Now you can validate data and emit messages but how do you display them? Normally you need to add just two lines to add errors and messages display to your module or plugin.
The first one is in your template, add a line that includes standard template for messages output:
And the second one should be put in your PHP code somewhere before the MAIN is parsed, e.g.:
The above example assumes that:
$t is the current XTemplate object;
You have put the line connecting the standard warnings.tpl template in the outer block called MAIN.
This assumption may be incorrect, so here is the explanation of cot_display_messages() parameters:
$tpl - XTemplate object where messages should be displayed;
$block - full block name where messages template is included. For example, if you have put it in the RESULTS block contained within MAIN block, then the value of this argument should be 'MAIN.RESULTS'.
4. All together now
Now that you know the pieces of the puzzle, here is a complete picture of a real application for you:
// Connect language file with messages
require_once cot_langfile('mailout', 'plug');
if ($a == 'send' && $_SERVER['REQUEST_METHOD'] == 'POST')
// Handle form submission
$subject = cot_import('subject', 'P', 'TXT');
$limit = cot_import('limit', 'P', 'INT');
$content = cot_import('content', 'P', 'HTM');
// Input validation
cot_check(empty($subject), 'mailout_err_subject_empty', 'subject');
cot_check(empty($content), 'mailout_err_content_empty', 'content');
cot_check($limit <= 0, 'mailout_err_invalid_limit', 'limit');
// Passed, save changes
$sql_limit = $limit > 0 ? "LIMIT $limit" : '';
$res = $db->query("SELECT user_name, user_email FROM $db_users $sql_limit");
$counter = 0;
foreach ($res->fetchAll() as $row)
$to = '"' . addslashes($row['user_name']) . '" <' . $row['user_email'] . '>';
cot_mail($to, $subject, $content, '', false, null, true);
// Emit success message
cot_message("$counter messages sent.");
// Redirect back to the original form and show messages there
cot_redirect(cot_url('admin', 'm=other&p=mailout', '', true));
// Display the user interface with the form
$t = new XTemplate(cot_tplfile('mailout.tools', 'plug'));
// Work with the template, assign tags and render blocks
// Don't forget to display the messages if they are present
Only registered users can post new comments