Downloaded from www.biorust.com on Sun Nov 22, 2009 18:59:22

 
Expandable Form Validation Class : Part 1
Tutorial Author - Limitless (http://www.llstudios.net)

IMPORTANT: This tutorial (and other component parts) make use of the datLib library, which you can download here. The author has stopped working on this project, but you can check out their website for similar up-to-date libraries.

In this rather advanced and sequential tutorial, we will teach you how to create an expandable Form Validation Class, that once complete, you will able to use in any of your PHP scripts. The beauty of this Class is that it is expandable with ease. This means that once the base code of the Class is complete, you can easily configure it to validate different types of form data with virtually no changes. The extra configurations will only be limited to your programming knowledge.

This tutorial is rather long and thus will be divided into several Parts. In Part 1 here, we will give an overview of the Class and how it will be used. Please make sure you have an idea of how to program in PHP as well as an idea on Object Oriented Programming. These concepts are not discussed here and even though we will try to be as descriptive as possible, an idea will help you understand what we are exactly talking about.

The ideas discussed in this tutorial are basically the same as the ones that our script, datVForm, is based on. So after you complete this tutorial, you might want to download datVForm to give it a shot and build upon it to test your know skills. Okay enough introductions, let's get started...


The Idea Behind The Code
There are literally hundreds, if not thousands, of tutorials available that teach you how to validate form data. This is important to ensure the security of your script and also to ensure that any user received data is in the format you want it to be in. As you develop different web sites, however, it becomes a big pain to copy the same code over and over again, modifying it to fit the new web site's needs.

Even if you wrap your form validation in functions, what happens when you want to expand on them? You have to rewrite them. And what about the error messages for each validation? These are all common features that with object oriented programming can become easier.


The Keyword Concept
Our Class will operate on a keyword basis. This means that based on a specific keyword we assign to each form field, the Class will know how to validate it. This makes the validation process very fast because the Class only validates fields with a keyword and nothing else. Secondly, it makes expanding the Class quite easy. To create new validation Methods, all you have to do is add a new keyword and tell the Class how to validate that keyword. Very simple.

A third concept is that because the validation always takes place on the server, the form will always be validated no matter where it is sent, from your server, or from a clients computer. In our script, we always instruct the Class to expect specific form fields and keywords. If such fields are not present, then it will assume the form has been tampered with and will always return an error. If the form field exists, it will always be validated!  Our Class will also be able to validate form data received by either a _POST or _GET method, which makes it much more portable.


Class Common Features
Our Class will have common features as well as several Methods. Let's first discuss the common features. First, there are the Form Error Messages and the System Error Messages.

The Form Error Messages are the error messages that are generated if a form field does not pass validation. So for example, if a form field is suppose to be an email and a user did not supply a valid email, this would generate a Form Error Message.

The System Error Messages are those that are generated by the Class when it encounters an internal error, such as a non existent keyword or non existent form field. These messages are helpful in the development process but should not be displayed when the Class is eventually used in a working environment.

The second set of common features are the Methods. Each Method in our Class will correspond to a keyword. Like stated before, a keyword instructs our Class to validate a form field in a specific way. This is done by calling the Method that corresponds to each keyword. Adding a new validation method is as simple as adding a new keyword and the Class Method that corresponds to it.


Creating The Class
Let's get started in creating our Class. The base code of our Class will contain several Attributes, a Constructor, and one Method. This one Method will be in charge of actually finding all form fields, determining if there are keywords associated with it, and calling the appropriate validation Method.

Because it is usually easier to see the code and then explain it, we will provide the code for the above elements that proceed to explain them one section a time. You should get an idea though of what is going on by reading the comments.

Please keep in mind that the code we show in this Part of the tutorial is not the complete Class, bur rather the important segments relevant to this Part. As Parts 2 and 3 become available, the code will be expanded to be much bigger.

<?php

class datVForm
{
    
/**
     * Form field names including the keywords.
     *
     * @var array
     */
    
var $_f_cFName;
    
/**
     * Form data.
     *
     * @var array
     */
    
var $_f_data;
    
/**
     * Form field names without the keywords.
     *
     * @var array
     */
    
var $_f_tFName;
    
/**
     * Form method.
     *
     * @var string
     */
    
var $_f_type;

    
/**
     * Form validation error messages.
     *
     * @var array
     */
    
var $_l_fError;
    
/**
     * Class system error messages.
     *
     * @var array
     */
    
var $_l_sError;

    
//////////////////////////////////////////////////////////////////////

    /**
     * Constructor.
     *
     * The Constructor has several jobs. First based on the form
     * method type, POST or GET, it will get all form data from
     * the PHP Super Global. Also it defines the attributes that
     * will be used by the Class.
     */
    
function datVForm$f_type )
    {
        
// Initialize Class Variables.

        
$this->_f_cFName    = array( );
        
$this->_f_data      = array( );
        
$this->_f_tFName    = array( );
        
$this->_f_type      $f_type;
        
$this->_l_fError    = array( );
        
$this->_l_sError    = array( );

        
// Determine Form Method.

        
if( $this->_f_type == 'p' ) {
            
$this->_f_data datLib::string_trim_array$_POST );
        }
        else if( 
$this->_f_type == 'g' ) {
            
$this->_f_data datLib::string_trim_array$_GET );
        }
        else {
            
$this->_l_sError[] =    'datVForm() Method : Invalid Form ' .
                                    
'Method :: Ignore Validation : <em>' .
                                    
'All Fields</em>';
        }
    }

    
//////////////////////////////////////////////////////////////////////

    /**
     * Validate.
     *
     * This Method does several things. First it determines how many form fields
     * there are in the submitted form, then loops through each and every single
     * one of them to determine which keywords, if any, are assosiated with one.
     *
     * If there are keywords assosiated with a field, it calls the appropiate
     * validation Method for that field.
     */
    
function validate( )
    {
        
// Define Local Variables.

        
$l_dataCount    count$this->_f_data );
        
$l_key          = array( );
        
$l_keyCount     NULL;
        
$l_vm             NULL;

        
// Find Complete Field Names.

        
$this->_f_cFName array_keys$this->_f_data );

        
// Find Field Names Without Keywords.

        
$this->_s_tFName( );

        
// Loop.

        
for( $i 0$i $l_dataCount$i++ )
        {
            
// Determine If Keyword Exists In Field Name.

            
preg_match_all'/\((.*?)\)/s' $this->_f_cFName$i ] , $l_key );

            
// Determine Number Of Keywords, If Any.

            
$l_keyCount datLib::array_count_2D$l_key );

            
// Loop.

            
for( $j 0$j $l_keyCount$j++ )
            {
   if( 
method_exists$this '_vm_' strtolower$l_key][ $j ] ) ) == TRUE )
                {
                    
// Extract Keyword Validation Method.

                    
$l_vm '_vm_' strtolower$l_key][ $j ] );

                    
// Call Validation Method.

                    
$this->$l_vm$this->_f_data$this->_f_cFName$i ] ] , $i );
                }
                else {
        
$this->_l_sError[] =    'validate() Method : Non Existant Keyword : ' .
               
'Ignore Validation : ' .
               
'<strong>' $this->_f_tFName$i ] . '</strong>';
                }
            }
        }

        
// Return.

        
if( datLib::array_isNull$this->_l_fError ) == FALSE ) {
            return 
FALSE;
        }

        if ( 
datLib::array_isNull$this->_l_sError ) == FALSE ) {
            return 
FALSE;
        }

        
/**
         * Return TRUE.
         *
         * The Method will only return TRUE if there are no validation errros.
         * Return TRUE means that every field has been validated
         * correctly and it is now generally safe to use this form data.
         */
        
return TRUE;
    }

    
//////////////////////////////////////////////////////////////////////
}

?>

That was a lot of code, so let's break up the code into segments and explain each segment alone...


The Class Attributes



<?php

class datVForm
{
    
/**
     * Form field names including the keywords.
     *
     * @var array
     */
    
var $_f_cFName;
    
/**
     * Form data.
     *
     * @var array
     */
    
var $_f_data;
    
/**
     * Form field names without the keywords.
     *
     * @var array
     */
    
var $_f_tFName;
    
/**
     * Form method.
     *
     * @var string
     */
    
var $_f_type;

    
/**
     * Form validation error messages.
     *
     * @var array
     */
    
var $_l_fError;
    
/**
     * Class system error messages.
     *
     * @var array
     */
    
var $_l_sError;

    
//////////////////////////////////////////////////////////////////////

?>

The Class Attributes are the variables that are shared between all Class Methods. From the comments you can pretty much determine what each Attribute is used for, but there are several that need some clarification.

$_f_cFName is an array housing the form field names in the order in which they appear in the form. The Class automatically appends each keyword associated with each field to the start of it's name. This array houses each form field name with the keywords included.

$_f_tFName is also an array housing the form field names in the order in which they appear in the form. The only difference is that it does so without the keywords included. Why? So when a form error is generated, only the field name is included, not the keywords as well.

$_f_type is whether the form was submitted via a POST or GET method.



The Constructor

<?php

    
/**
     * Constructor.
     *
     * The Constructor has several jobs. First based on the form
     * method type, POST or GET, it will get all form data from
     * the PHP Super Global. Also it defines the attributes that
     * will be used by the Class.
     */
    
function datVForm$f_type )
    {
        
// Initialize Class Variables.

        
$this->_f_cFName    = array( );
        
$this->_f_data      = array( );
        
$this->_f_tFName    = array( );
        
$this->_f_type      $f_type;
        
$this->_l_fError    = array( );
        
$this->_l_sError    = array( );

        
// Determine Form Method.

        
if( $this->_f_type == 'p' ) {
            
$this->_f_data datLib::string_trim_array$_POST );
        }
        else if( 
$this->_f_type == 'g' ) {
            
$this->_f_data datLib::string_trim_array$_GET );
        }
        else {
            
$this->_l_sError[] =    'datVForm() Method : Invalid Form ' .
                                    
'Method :: Ignore Validation : <em>' .
                                    
'All Fields</em>';
        }
    }

    
//////////////////////////////////////////////////////////////////////

?>

The Constructor Method is used when an object is first created. First, it accepts one argument, which is the form submission Method. It uses it to save the form data from either the POST or GET PHP Super Global. There are several things to notice, particularly in this code section:

<?php

        
// Determine Form Method.

        
if( $this->_f_type == 'p' ) {
            
$this->_f_data datLib::string_trim_array$_POST );
        }
        else if( 
$this->_f_type == 'g' ) {
            
$this->_f_data datLib::string_trim_array$_GET );
        }
        else {
            
$this->_l_sError[] =    'datVForm() Method : Invalid Form ' .
                                    
'Method :: Ignore Validation : <em>' .
                                    
'All Fields</em>';
        }

    
//////////////////////////////////////////////////////////////////////

?>

We used datLib Method string_trim_array to trim all the form data before saving it in our Class. We did that so that no extra white space characters are included to avoid any errors in validation.

Consider a validation for a field that can not have any new line characters in it for example. If the User by mistake included a new line character by pressing the enter key before submitting the form, an error message will always be triggered. To save us and the User the headache, we just trim the data.

We also make sure that the form submission method was either POST or GET, or a system error will be triggered to inform us that an invalid method was detected.


The Validation Method

<?php

    
/**
     * Validate.
     *
     * This Method does several things. First it determines how many form fields
     * there are in the submitted form, then loops through each and every single
     * one of them to determine which keywords, if any, are assosiated with one.
     *
     * If there are keywords assosiated with a field, it calls the appropiate
     * validation Method for that field.
     */
    
function validate( )
    {
        
// Define Local Variables.

        
$l_dataCount    count$this->_f_data );
        
$l_key          = array( );
        
$l_keyCount     NULL;
        
$l_vm             NULL;

        
// Find Complete Field Names.

        
$this->_f_cFName array_keys$this->_f_data );

        
// Find Field Names Without Keywords.

        
$this->_s_tFName( );

        
// Loop.

        
for( $i 0$i $l_dataCount$i++ )
        {
            
// Determine If Keyword Exists In Field Name.

            
preg_match_all'/\((.*?)\)/s' $this->_f_cFName$i ] , $l_key );

            
// Determine Number Of Keywords, If Any.

            
$l_keyCount datLib::array_count_2D$l_key );

            
// Loop.

            
for( $j 0$j $l_keyCount$j++ )
            {
 if( 
method_exists$this '_vm_' strtolower$l_key][ $j ] ) ) == TRUE )
                {
                    
// Extract Keyword Validation Method.

                    
$l_vm '_vm_' strtolower$l_key][ $j ] );

                    
// Call Validation Method.

         
$this->$l_vm$this->_f_data$this->_f_cFName$i ] ] , $i );
                }
                else {
                    
$this->_l_sError[] =    'validate() Method : Non Existant Keyword : ' .
                            
'Ignore Validation : ' .
                           
'<strong>' $this->_f_tFName$i ] . '</strong>';
                }
            }
        }

        
// Return.

        
if( datLib::array_isNull$this->_l_fError ) == FALSE ) {
            return 
FALSE;
        }

        if ( 
datLib::array_isNull$this->_l_sError ) == FALSE ) {
            return 
FALSE;
        }

        
/**
         * Return TRUE.
         *
         * The Method will only return TRUE if there are no validation errors.
         * Return TRUE means that every field has been validated
         * correctly and it is now generally safe to use this form data.
         */
        
return TRUE;
    }

    
//////////////////////////////////////////////////////////////////////

?>

This Method is the heart of our Class. Its main job is to loop through every form field, determine if there are any keywords associated with it and call the appropriate validation Method for each keyword.

Remember that we said that, for expansion reasons, each keyword will have its own validation Method. What this Method does is that it matches any keyword with the validation Method of the same name. If no Method exists, then it assumes an invalid keyword was associated with the field and will trigger a system error.

Keywords for our Class are detected as any text between parenthesis, ( ). So in order for this Class to work no parenthesis can be used in the form field name. If any text between parenthesis is found and does not have an associated validation Method, a system error will be triggered.

You might now be wondering how a keyword is matched with a validation Method. All validation Methods have the prefix _vm_ followed by the keyword in lowercase letters.

Consider the keyword Required for example. Its validation Method will be called _vm_required.

<?php

        
// Define Local Variables.

        
$l_dataCount    count$this->_f_data );
        
$l_key          = array( );
        
$l_keyCount     NULL;
        
$l_vm             NULL;

?>

What we do here is define the variables we will use within the Method.

$l_dataCount is simply the number of form fields. This is used so that we can loop through each field. You will remember that the Attribute $this->_f_data is used to house the form fields along with their values based on the submission Method.

$l_key is an array that will house all keywords for the current field in the loop.

$l_keyCount is simply the number of keywords found for the current field. It is used to start a nested loop to loop through each keyword found and call the appropriate validation Method.

$l_vm is where the fun really started. PHP allows for dynamic function or Method calls from string variables if the value of that string variable matches the name of a function or a Method. $l_vm will include the value of the Validation Method based on the keyword found so that it can be called. This will become more clear in the code that follows.

What do we mean by dynamic function calls? Consider the PHP native function count. If we save a string variable as follows:

We created a string variable with the value of count, which also happens to be the same name as a PHP native function. If we were to use the variable as a function, PHP will consider it the same as calling count( ). Take a look at the example to understand :

<?php

$dynamicCall 
'count';

// Call Function Count.
// Same As Writing count( $myArray ).

$dynamicCall$myArray );

// Same As Above.

count$myArray );

?>

<?php
        
// Find Complete Field Names.

        
$this->_f_cFName array_keys$this->_f_data );

        
// Find Field Names Without Keywords.

        
$this->_s_tFName( );

?>

Okay what we do here is get the form field names with the keywords and without the keywords. The _s_tFName( ) Method will be discussed in Part 2 of this tutorial, but for now just know that it extracts each form field name without the keywords included.

Let's now discuss the PHP native function array_keys( ). This function simply returns all the keys of an array. Remember that when a form is saved in the PHP Super Global POST or GET, it is saved in the format of $_POST[ key ] = value. In this case, each key in the Super Global is the name of our fields and each value is the value entered by the User for that field!.

So by calling the function array_keys we are returning the name of our form field names only! So simple to understand and follow.

<?php
        
// Loop.

        
for( $i 0$i $l_dataCount$i++ )
        {
            
// Determine If Keyword Exists In Field Name.

    
preg_match_all'/\((.*?)\)/s' $this->_f_cFName$i ] , $l_key );

            
// Determine Number Of Keywords, If Any.

            
$l_keyCount datLib::array_count_2D$l_key );

            
// Loop.

            
for( $j 0$j $l_keyCount$j++ )
            {
 if( 
method_exists$this '_vm_' strtolower$l_key][ $j ] ) ) == TRUE )
                {
                    
// Extract Keyword Validation Method.

                    
$l_vm '_vm_' strtolower$l_key][ $j ] );

                    
// Call Validation Method.

        
$this->$l_vm$this->_f_data$this->_f_cFName$i ] ] , $i );
                }
                else {
                    
$this->_l_sError[] =    'validate() Method : Non Existant Keyword : ' .
                             
'Ignore Validation : ' .
                             
'<strong>' $this->_f_tFName$i ] . '</strong>';
                }
            }
        }

?>

Over in this code segment, what we are doing is that we are looping through each form field. That is what the first For Loop is for. Inside it we do several things to extract the keywords for each field.

<?php

            
// Determine If Keyword Exists In Field Name.

  
preg_match_all'/\((.*?)\)/s' $this->_f_cFName$i ] , $l_key );

            
// Determine Number Of Keywords, If Any.

  
$l_keyCount datLib::array_count_2D$l_key );

?>

We call the PHP function preg_match_all to match any characters inside parenthesis, ( ). Like stated before, any keyword in our form field will be enclosed in them.

We then use the datLib Method array_count_2D to determine how many actual keywords are found. The preg_match_all function returns a 2D array that is why we do not use the native PHP function count. This is so we can loop through each keyword through a second nested For Loop.

The way preg_match_all works is that it finds any characters inside the given pattern. The first dimension in the array returned, $l_key are the matches including the pattern, which in our case is the parenthesis. The second dimension in the array are the matches alone, which in this case would be the actual keywords.

We need the keywords alone so that we can use them in our dynamic call to their Method. That is why further down in the code, when we reference to the matches array, we always reference to it from the second dimension.

<?php
            
// Loop.

            
for( $j 0$j $l_keyCount$j++ )
            {
 if( 
method_exists$this '_vm_' strtolower$l_key][ $j ] ) ) == TRUE )
                {
                    
// Extract Keyword Validation Method.

                 
$l_vm '_vm_' strtolower$l_key][ $j ] );

                    
// Call Validation Method.

                 
$this->$l_vm$this->_f_data$this->_f_cFName$i ] ] , $i );
                }
                else {
     
$this->_l_sError[] =    'validate() Method : Non Existant Keyword : ' .
                             
'Ignore Validation : ' .
                             
'<strong>' $this->_f_tFName$i ] . '</strong>';
                }
            }

?>

In the second nested For Loop, we loop through each found keyword. We first check that a Method for the keyword found exists to avoid any possible errors. If a Method does exist, we save the entire keyword, with _vm_ appended to it at the start in a variable called $l_vm to get the entire Method Name.

We then dynamically call the Method. If the Method does not exist, then a system error will be triggered to give us a proper warning.

Some things to pay close attention to in the last code segment. First, each validation Method is executed as soon as its associated keyword is found and in the order that they are found. Second, and most importantly, each validation Method is called with two arguments. This will be discussed in Part 3 of this tutorial, but lets give a little heads up here why. Each validation Method will be responsible for generating its own error messages. Thus it will need two things. The name of the field it is validation so that it can optionally include the form field name in the generated error message and the current position of the field in the array that includes the form field name without the keywords.

Each validation Method will obviously do some test on the form field name. Because the form field names are stored in an Attribute that includes the keywords, the first argument is required. A second Attribute, as you remember, also includes the form field names but without the keywords. The array is ordered in the order the fields are in the form.

Because the first For Loop also loops through each form field in the order it appears in the form, thus the current position of the For Loop will also provide an indicator as to the current form field's name without the keywords in the array.

<?php

        
// Return.

        
if( datLib::array_isNull$this->_l_fError ) == FALSE ) {
            return 
FALSE;
        }

        if ( 
datLib::array_isNull$this->_l_sError ) == FALSE ) {
            return 
FALSE;
        }

        
/**
         * Return TRUE.
         *
         * The Method will only return TRUE if there are no validation errros.
         * Return TRUE means that every field has been validated
         * correctly and it is now generally safe to use this form data.
         */
        
return TRUE;
    }

?>

After each form field is looped through and validated, the Method will only return TRUE if there are no system or validation errors. If you remember, each validation Method generates its own error message. This error message should be saved in the form error Attribute so that it can later be displayed to the user in the place where you decide to display it.

Returning TRUE means that the form data is generally safe to use or is in the format that you want it to be. Thus it can then be used in your script.



Conclusion
In this Part of the tutorial, we have an overview of our Class, how it operates and how it can be expanded. We also gave an overview of key PHP features such as dynamic function calling and regular expressions.

In Part 2, we will discuss the remaining portions of our Class such as displaying the validation Method generated error messages as well as the system error messages.

In Part 3, we will discuss how to create several example validation Methods as well as put the Class into an example test to showcase our creation. We will also provide ideas on how the Class can be expanded or improved and some more ideas.




All Content © BioRUST 2009 All Rights Reserved.