SitePoint Sponsor

User Tag List

Results 1 to 25 of 25
  1. #1
    SitePoint Member
    Join Date
    Jan 2009
    Location
    Sibiu, Romania
    Posts
    15
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Question In Search of the Holy Grail of Form Validation

    Hi guys,

    I'm sure that many of you, like me, hate writing boring form validation. Form validation seems to be the least interesting thing in web development and, however, the activity that takes most of the time in the development of an online project.

    What I'm trying to look for now, is a way, some simple to implement and reusable functions or a class that would allow me to automate somehow this validation process.

    I was wondering, if any of you guys have found some smart way of doing this, my only requirements for this would be that this method would work for the most important input types (text input, radio and check boxes, text areas and select boxes - at least) and that I can still write myself the markup of the form itself ( I many times need that for styling ).

    Thank you in advance for your input,
    titel

  2. #2
    Use The Cloud
    Join Date
    Jan 2006
    Location
    Boise, ID
    Posts
    556
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I use Zend_Form as my primary form library.
    Brad Hanson, Web Applications & Scalability Specialist
    ► Is your website outgrowing its current hosting solution?
    ► PM me for a FREE scalability consult!
    ► USA Based: Available by Phone, Skype, AIM, and E-mail.

  3. #3
    SitePoint Member
    Join Date
    Jan 2009
    Location
    Sibiu, Romania
    Posts
    15
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yes, there's something I forgot to say actually, I'm not really looking for some of these big classes or frameworks.

    There are situations when these are just not necessary, imagine you have 2 or3 forms on a website you're developing. Is it really worth loading it up with one of these big packages only to validate 3 forms.

    I hope there's an easier way to achieve the same thing.

  4. #4
    Use The Cloud
    Join Date
    Jan 2006
    Location
    Boise, ID
    Posts
    556
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by titel View Post
    Yes, there's something I forgot to say actually, I'm not really looking for some of these big classes or frameworks.

    There are situations when these are just not necessary, imagine you have 2 or3 forms on a website you're developing. Is it really worth loading it up with one of these big packages only to validate 3 forms.

    I hope there's an easier way to achieve the same thing.
    The classes are robust, but you don't have to include the entire framework. In fact, it is designed in a way that can be used as a library (which many people do).

    For example, Zend_Form's requirements are about 250KB, IIRC.
    Brad Hanson, Web Applications & Scalability Specialist
    ► Is your website outgrowing its current hosting solution?
    ► PM me for a FREE scalability consult!
    ► USA Based: Available by Phone, Skype, AIM, and E-mail.

  5. #5
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Zend_Form can be used on its own. If you like the library, just go ahead and use it.

    Whether form-libraries are a good idea or not, is a different matter though. For simple cases they work fine, but in my experience there are so many edge cases that the library either have to cover a lot of ground (And thus become rather complex) or limit you to the 80% cases.

  6. #6
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,151
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    Depending on how much flexible you would like the processing to be I divide the process in two processes.

    1. form - visual
    2. processing - data handling


    My system is built on a factory pattern and uses one base class and a interface.

    1. Form Class
    2. Processable Interface


    The Form class is the front-end class and essentially returns the processing object. The processing object must implement the Processable Interface. You return a processing object by extending the Form class and redefining a method such as getProcessor(), which will be responsible for returning the processing object.

    The below represents the Form class. As you should see it contains two abstract methods:

    1. processor() - returns processor for form
    2. render() - shows physical form


    Form Class
    PHP Code:
    <?php
    abstract class Form {
        
        protected 
    $_processor;
        
        public function 
    __construct(PDO &$pConnector,Pathway &$pPathway,Client &$pClient) {
            
    $this->_processor $this->processor();
            
    $this->_processor->preProcess($pConnector,$pPathway,$pClient);
            
    $this->_processor->process($pConnector,$pPathway,$pClient);
        }
        
        abstract public function 
    processor();
        abstract public function 
    render();
        
    }
    ?>
    The $connection,$pathway and $client variables are passed so that they may be used by the processor to eliminate dependencies. The connection object could be a mysql connection object of any type. The $pathway object is glorified $_GET array to that those variables may be accessible without relying on $_GET itself and the $client parameter is a object that represents the current logged in user, so that you may check their access level, name,etc in the processor.

    The Processor may be anything you like as long as it implements the Processable interface. The Processable interface is meant to provide key methods which that return information that the Processing object is responsible for validating in the $_POST array. The key methods of the Processable interface are outlined below.

    1. process() - should process $_POST/passed data of the form
    2. preProcess() - checks whether the form should be processed
    3. missing() - used to see if field data is missing
    4. isInvalid() - used to see if a field has invalid data
    5. messages() - builds and returns a array() of error messages for the user to see
    6. feedbackFor() - provides feedback about particular feed is it was invalid
    7. isReq() - check whether a field is required
    8. val() - returns value of field provided in $_POST array
    9. nameFor - provides html name attribute for html form elements


    This is a example of the Processable interface.

    Processable Interface
    PHP Code:
    <?php
    interface IProcessable {
        public function 
    process(PDO &$pConnector,Pathway &$pPathway,Client &$pClient);
        public function 
    preProcess(PDO &$pConnector,Pathway &$pPathway,Client &$pClient);
        public function 
    missing($pName);
        public function 
    isInvalid($pName);
        public function 
    messages();
        public function 
    feedbackFor($pName);
        public function 
    isReq($pName);
        public function 
    val($pName);
        public function 
    nameFor($pName);
    }
    ?>
    Now to create a processor for any form you simply declare the class and have it implement that interface. Then you may change the implementation of interface methods as you see fit for any specific form. The below outlines a example of a processor for registration form. The processing object itself does not show the form. It only handles the data passed by the form and defines the required fields while providing messages,feedback and information about items that may be missing or invalid in the $_POST array or passed data.

    Registration Processor
    PHP Code:
    <?php
    class RegistrationProcessor implements IProcessable {
        
        private 
    $_allow;
        private 
    $_validation;
        
        private 
    $_missing;
        private 
    $_invalid;
        private 
    $_messages;
        private 
    $_feedback;
        
        var 
    $_required = array(
            
    'first-name'
            
    ,'last-name'
            
    ,'country'
            
    ,'desired-name'
            
    ,'desired-password'
            
    ,'city'
            
    ,'security-question'
            
    ,'security-answer'
            
    ,'terms-agreement'
            
    ,'email-address'
            
    ,'birth-day'
            
    ,'birth-month'
            
    ,'birth-year'
        
    );
        
        public function 
    __construct() {
            
    $this->_missing = array();
            
    $this->_invalid = array();
            
    $this->_messages = array();
            
    $this->_feedback = array();
            
    $this->_validation = new Validation;
        }
        
        public function 
    preProcess(PDO &$pConnector,Pathway &$pPathway,Client &$pClient) {
            
            
    /*
             * called before anything else. This allows use the ability
             * to see if the user should even be able to access the forms.
             * Not very important here, but in some other forms such as 
             * bids this becomes crucial becasue a user can only have one bid
             * per project. So this allow use to check things like that and 
             * if they have allready placed a bid we can redirect them or error.
             */
            
    $this->_allow true;
            
        }
        
        
        
        public function 
    process(PDO &$pConnector,Pathway &$pPathway,Client &$pClient) {
            if(isset(
    $_REQUEST['register']) && $this->_allow) {

                
    //return; kills processor for remote testing
                /*
                 * without wasting time make sure they agreed to our terms
                 */
                 
    if(!isset($_REQUEST['record']['terms-agreement'])) { 
                    
    $this->_messages[] = 'You need to agree to our terms to register';
                    
    $this->_missing[] = 'terms-agreement';
                     return;
                 }
         
                
    /*
                * once they are here it means they have agreed to your terms.
                * Now check to make sure all required fields have been filled out.
                */
                
    foreach($this->_required as $field) {
                    if(!isset(
    $_REQUEST['record'][$field])) {
                        
    $this->_missing[] = $field;
                    } else if(empty(
    $_REQUEST['record'][$field])) {
                        
    $this->_missing[] = $field;
                    }
                }    
        
                
    /*
                 * array with nothing in it evaluates to false. Therefore,
                 * if nothing is missing proceed to validation.
                 */
                
    if($this->_missing) {
                    
    $this->_messages[] = 'Some missing fields found';
                    return;
                }
        
                
    /*
                 * Begin validation of all fields if validation is required
                 */
         
                 // first name validation
                 
    if(!$this->_validation->validStr($_POST['record']['first-name'],array(25,'/^[a-zA-Z\s]{2,25}$/'))) {
                     
    $this->_invalid[] = 'first-name';
                     
    $this->_messages[] = 'First Name is not valid';
                     
    $this->_feedback['first-name'] = 'Alpabetic characters only allowed';                 
                 }
                 
                 if(!
    $this->_validation->validStr($_POST['record']['last-name'],array(25,'/^[a-zA-Z\s]{2,25}$/'))) {
                     
    $this->_invalid[] = 'last-name';
                     
    $this->_messages[] = 'Last Name is not valid';
                     
    $this->_feedback['last-name'] = 'Alpabetic characters only allowed';                 
                 }    
                 
                 if(
    $_POST['record']['phone-number'] && !$this->_validation->validStr($_POST['record']['phone-number'],array(20,'/^[0-9\-\/]{5,20}$/'))) {
                     
    $this->_invalid[] = 'phone-number';
                     
    $this->_messages[] = 'Phone Number is not valid';
                     
    $this->_feedback['phone-number'] = 'Should be formated x-xxx-xxx-xxxx';                 
                 }
                 
                 if(!
    $this->_validation->validStr($_POST['record']['email-address'],array(100,'/^.{5,100}$/'))) {
                     
    $this->_invalid[] = 'email-address';
                     
    $this->_messages[] = 'Email Address is not valid';
                     
    $this->_feedback['email-address'] = 'Should be formatted name@host';                 
                 } 
                 
                 
    $birth_date $_POST['record']['birth-year'].'-'.$_POST['record']['birth-month'].'-'.$_POST['record']['birth-day'];
                 if(!
    $this->_validation->validDate($birth_date,array())) {
                     
    $this->_invalid[] = 'birth-date';
                     
    $this->_messages[] = 'Birth date is not valid';
                     
    $this->_feedback['birth-date'] = 'should be formatted 00/00/0000';                 
                 }
                 
                 if(!
    $this->_validation->validStr($_POST['record']['desired-name'],array(15,'/^[a-zA-Z0-9-_]{2,15}$/'))) {
                     
    $this->_invalid[] = 'desired-name';
                     
    $this->_messages[] = 'Desired name is not valid';
                     
    $this->_feedback['desired-name'] = '2 - 15 characters';                 
                 }
                 
                 if(!
    $this->_validation->validStr($_POST['record']['desired-password'],array(20,'/^[0-9a-zA-Z]{6,20}$/'))) {
                     
    $this->_invalid[] = 'desired-password';
                     
    $this->_invalid[] = 'confirmed-password';
                     
    $this->_messages[] = 'Desired password is not valid';
                     
    $this->_feedback['desired-password'] = 'Alphanumeric characters only allowed';
                     
    $this->_feedback['confirmed-password'] = 'Must match desired password';                 
                 }
                 
                 if(!
    $this->_validation->validStr($_REQUEST['record']['security-answer'],array(25,'/^.{2,25}$/'))) {
                     
    $this->_invalid[] = 'security-answer';
                     
    $this->_messages[] = 'Security answer is invalid';
                     
    $this->_feedback['security-answer'] = 'Must be at least 2 characters and at most 25';                 
                 }
         
                 
    /*
                  * empty array evaluates to false.
                  */
                 
    if($this->_invalid) {  
                     return;
                 }
                
                
    $desired_name $_REQUEST['record']['desired-name'];
                
    $email_address $_REQUEST['record']['email-address'];
                
    $user = new User($pConnector);
                
                
    /*
                 * user name is taken so stop and prompt with message
                 */
                
    if($user->fetchById($desired_name)) {
                    
    $this->_messages[] = 'Desired user name is allready in use. Please choose a different user name.';
                    return;
                }
                
                
    /*
                 * email has allready been registered so stop and prompt with message
                 */
                
    if($user->fetchByEmail($email_address)) {
                    
    $this->_messages[] = 'Our records indicate this email currently has a account with project-pad. Forgot your login information click here.';
                    return;
                }
                
                
    $time time();
                
    $user->create(
                    array(array(
                        
    'id'=>$_POST['record']['desired-name']
                        ,
    'email'=>$_POST['record']['email-address']
                        ,
    'pwd'=>array($_POST['record']['desired-password'],User::salt,$time)
                        ,
    'pass_question'=>$_POST['record']['security-question']
                        ,
    'pass_answer'=>array($_POST['record']['security-answer'],User::salt,$time)
                        ,
    'access_level'=>1
                        
    ,'first_name'=>$_POST['record']['first-name']
                        ,
    'last_name'=>$_POST['record']['last-name']
                        ,
    'birth'=>$birth_date
                        
    ,'country'=>$_POST['record']['country']
                        ,
    'state'=>$_POST['record']['state']
                        ,
    'city'=>$_POST['record']['city']
                        ,
    'phone'=>$_POST['record']['phone-number']
                        ,
    'website'=>$_POST['record']['website']
                        ,
    'bio'=>$_POST['record']['bio']
                        ,
    'created'=>$time
                    
    )
                ));
                
                if(
    $user->fetchById($desired_name)) {
                    
    $this->_messages[] = 'user created';
                }
            
            }
            
        }
        
        public function 
    missing($pName) {
            return 
    in_array($pName,$this->_missing)?true:false;
        }
        
        public function 
    isInvalid($pName) {
            return 
    in_array($pName,$this->_invalid)?true:false;
        }
        
        public function 
    messages() {
            if(
    $this->_messages) {
                echo 
    '<ul id="form-messages">',"\n";
                    if(
    count($this->_messages)>1) {
                        echo 
    '<p>',implode("</p>\n<p>",$this->_messages).'</p>';
                    } else {
                        echo 
    '<p>'.implode('',$this->_messages).'</p>';
                    }
                echo 
    "\n",'</ul>',"\n";
            }
        }
        
        public function 
    feedbackFor($pName) {
            return 
    array_key_exists($pName,$this->_feedback)?$this->_feedback[$pName]:'';
        }
        
        public function 
    isReq($pName) {
            return 
    in_array($pName,$this->_required)?true:false;
        }
        
        public function 
    val($pName) {
            return isset(
    $_REQUEST['record'][$pName])?$_REQUEST['record'][$pName]:'';
        }
        
        public function 
    nameFor($pName) {
            return 
    'record['.$pName.']';
        }
        
    }
    ?>
    Once that is set up all that needs to be done is create the physical form and have that form return the appropriate processing object. The below outlines the appropriate implementation for a Registration form that uses the previously outlines processor as its processing mechanism. The Form class itself it only responsible for connecting the form and processor. It is also responsible for rending the actual form on screen through its render method. The render method then uses the processor object and calls methods of the Processable interface to provide data about the data oriented aspects of the form and information that may have been processed. This in itself makes the entire system very flexible because you could theoretically reuse processors and forms. You also are able to define you own implementation of how to handle the interface methods for a particular processor. The below outlines a example, of the finalized Registration Form Class.

    Registration Form
    PHP Code:
    <?php
    class RegistrationForm extends Form {

        protected 
    $_processor;
        
        protected 
    $_countries = array(
            
    "Afghanistan",
            
    "Albania",
            
    "Algeria",
            
    "Andorra",
            
    "Angola",
            
    "Antigua and Barbuda",
            
    "Argentina",
            
    "Armenia",
            
    "Australia",
            
    "Austria",
            
    "Azerbaijan",
            
    "Bahamas",
            
    "Bahrain",
            
    "Bangladesh",
            
    "Barbados",
            
    "Belarus",
            
    "Belgium",
            
    "Belize",
            
    "Benin",
            
    "Bhutan",
            
    "Bolivia",
            
    "Bosnia and Herzegovina",
            
    "Botswana",
            
    "Brazil",
            
    "Brunei",
            
    "Bulgaria",
            
    "Burkina Faso",
            
    "Burundi",
            
    "Cambodia",
            
    "Cameroon",
            
    "Canada",
            
    "Cape Verde",
            
    "Central African Republic",
            
    "Chad",
            
    "Chile",
            
    "China",
            
    "Colombi",
            
    "Comoros",
            
    "Congo (Brazzaville)",
            
    "Congo",
            
    "Costa Rica",
            
    "Cote d'Ivoire",
            
    "Croatia",
            
    "Cuba",
            
    "Cyprus",
            
    "Czech Republic",
            
    "Denmark",
            
    "Djibouti",
            
    "Dominica",
            
    "Dominican Republic",
            
    "East Timor (Timor Timur)",
            
    "Ecuador",
            
    "Egypt",
            
    "El Salvador",
            
    "Equatorial Guinea",
            
    "Eritrea",
            
    "Estonia",
            
    "Ethiopia",
            
    "Fiji",
            
    "Finland",
            
    "France",
            
    "Gabon",
            
    "Gambia, The",
            
    "Georgia",
            
    "Germany",
            
    "Ghana",
            
    "Greece",
            
    "Grenada",
            
    "Guatemala",
            
    "Guinea",
            
    "Guinea-Bissau",
            
    "Guyana",
            
    "Haiti",
            
    "Honduras",
            
    "Hungary",
            
    "Iceland",
            
    "India",
            
    "Indonesia",
            
    "Iran",
            
    "Iraq",
            
    "Ireland",
            
    "Israel",
            
    "Italy",
            
    "Jamaica",
            
    "Japan",
            
    "Jordan",
            
    "Kazakhstan",
            
    "Kenya",
            
    "Kiribati",
            
    "Korea, North",
            
    "Korea, South",
            
    "Kuwait",
            
    "Kyrgyzstan",
            
    "Laos",
            
    "Latvia",
            
    "Lebanon",
            
    "Lesotho",
            
    "Liberia",
            
    "Libya",
            
    "Liechtenstein",
            
    "Lithuania",
            
    "Luxembourg",
            
    "Macedonia",
            
    "Madagascar",
            
    "Malawi",
            
    "Malaysia",
            
    "Maldives",
            
    "Mali",
            
    "Malta",
            
    "Marshall Islands",
            
    "Mauritania",
            
    "Mauritius",
            
    "Mexico",
            
    "Micronesia",
            
    "Moldova",
            
    "Monaco",
            
    "Mongolia",
            
    "Morocco",
            
    "Mozambique",
            
    "Myanmar",
            
    "Namibia",
            
    "Nauru",
            
    "Nepa",
            
    "Netherlands",
            
    "New Zealand",
            
    "Nicaragua",
            
    "Niger",
            
    "Nigeria",
            
    "Norway",
            
    "Oman",
            
    "Pakistan",
            
    "Palau",
            
    "Panama",
            
    "Papua New Guinea",
            
    "Paraguay",
            
    "Peru",
            
    "Philippines",
            
    "Poland",
            
    "Portugal",
            
    "Qatar",
            
    "Romania",
            
    "Russia",
            
    "Rwanda",
            
    "Saint Kitts and Nevis",
            
    "Saint Lucia",
            
    "Saint Vincent",
            
    "Samoa",
            
    "San Marino",
            
    "Sao Tome and Principe",
            
    "Saudi Arabia",
            
    "Senegal",
            
    "Serbia and Montenegro",
            
    "Seychelles",
            
    "Sierra Leone",
            
    "Singapore",
            
    "Slovakia",
            
    "Slovenia",
            
    "Solomon Islands",
            
    "Somalia",
            
    "South Africa",
            
    "Spain",
            
    "Sri Lanka",
            
    "Sudan",
            
    "Suriname",
            
    "Swaziland",
            
    "Sweden",
            
    "Switzerland",
            
    "Syria",
            
    "Taiwan",
            
    "Tajikistan",
            
    "Tanzania",
            
    "Thailand",
            
    "Togo",
            
    "Tonga",
            
    "Trinidad and Tobago",
            
    "Tunisia",
            
    "Turkey",
            
    "Turkmenistan",
            
    "Tuvalu",
            
    "Uganda",
            
    "Ukraine",
            
    "United Arab Emirates",
            
    "United Kingdom",
            
    "United States",
            
    "Uruguay",
            
    "Uzbekistan",
            
    "Vanuatu",
            
    "Vatican City",
            
    "Venezuela",
            
    "Vietnam",
            
    "Yemen",
            
    "Zambia",
            
    "Zimbabwe"
        
    );
        
        
        
        protected 
    $_states = array(
            
    'AL'=>'ALABAMA',
            
    'AK'=>'ALASKA',
            
    'AZ'=>'ARIZONA',
            
    'AR'=>'ARKANSAS',
            
    'CA'=>'CALIFORNIA',
            
    'CO'=>'COLORADO',
            
    'CT'=>'CONNECTICUT',
            
    'DE'=>'DELAWARE',
            
    'DC'=>'DISTRICT OF COLUMBIA',
            
    'FL'=>'FLORIDA',
            
    'GA'=>'GEORGIA',
            
    'HA'=>'HAWAII',
            
    'ID'=>'IDAHO',
            
    'IL'=>'ILLINOIS',
            
    'IN'=>'INDIANA',
            
    'IA'=>'IOWA',
            
    'KS'=>'KANSAS',
            
    'KY'=>'KENTUCKY',
            
    'LA'=>'LOUISIANA',
            
    'ME'=>'MAINE',
            
    'MD'=>'MARYLAND',
            
    'MA'=>'MASSACHUSETTS',
            
    'MI'=>'MICHIGAN',
            
    'MN'=>'MINNESOTA',
            
    'MS'=>'MISSISSIPPI',
            
    'MO'=>'MISSOURI',
            
    'MT'=>'MONTANA',
            
    'NE'=>'NEBRASKA',
            
    'NV'=>'NEVADA',
            
    'NH'=>'NEW HAMPSHIRE',
            
    'NJ'=>'NEW JERSEY',
            
    'NM'=>'NEW MEXICO',
            
    'NY'=>'NEW YORK',
            
    'NC'=>'NORTH CAROLINA',
            
    'ND'=>'NORTH DAKOTA',
            
    'OH'=>'OHIO',
            
    'OK'=>'OKLAHOMA',
            
    'OR'=>'OREGON',
            
    'PA'=>'PENNSYLVANIA',
            
    'RI'=>'RHODE ISLAND',
            
    'SC'=>'SOUTH CAROLINA',
            
    'SD'=>'SOUTH DAKOTA',
            
    'TN'=>'TENNESSEE',
            
    'TX'=>'TEXAS',
            
    'UT'=>'UTAH',
            
    'VT'=>'VERMONT',
            
    'VA'=>'VIRGINIA',
            
    'WA'=>'WASHINGTON',
            
    'WV'=>'WEST VIRGINIA',
            
    'WI'=>'WISCONSIN',
            
    'WY'=>'WYOMING'
        
    );
            
        protected 
    $_questions = array(
            
    'Mothers Maiden Name'
            
    ,'Birth City'
        
    );
        
        protected 
    $_months = array(
            
    'JAN'=>'01'
            
    ,'FEB'=>'02'
            
    ,'MAR'=>'03'
            
    ,'APR'=>'04'
            
    ,'MAY'=>'05'
            
    ,'JUN'=>'06'
            
    ,'JUL'=>'07'
            
    ,'AUG'=>'08'
            
    ,'SEPT'=>'09'
            
    ,'OCT'=>'10'
            
    ,'NOV'=>'11'
            
    ,'DEC'=>'12'
        
    );

        public function 
    processor() {
            return new 
    RegistrationProcessor();
        }
        
        public function 
    render() {
        
            
    $form =& $this->_processor;
            
            
    ?>
            
            <?php $form->messages(); ?>
            
            <form id="registration" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">

                <fieldset class="required">
                    <ol>
                        <li class="terms-explaination">
                            <p>If you have not yet read the project-pad terms and conditions we advise you so before registering. All new members are
                            required to agree to these terms before being allowed to register.</p>
                        </li>
                        <li class="terms-agreement">
                            <input type="checkbox" <?php if($form->missing('terms-agreement')) { ?>class="missing" <?php ?>name="record[terms-agreement]" <?php if(strcmp($form->val('terms-agreement'),'on')==0) { ?>checked="checked"<?php ?>id="terms-agreement" />
                            <label for="terms-agreement"><?php if($form->isReq('terms-agreement')) { ?><span class="required"></span><?php ?>Agree<?php echo $form->feedBackFor('terms-agreement'); ?></label>
                        </li>
                    </ol>
                    <ol class="profile">
                        <li class="first-name">
                            <label for="first-name">First Name</label>
                            <input maxlength="25" type="text" name="<?php echo $form->nameFor('first-name'); ?><?php if($form->missing('first-name')) { ?>class="missing" <?php ?>value="<?php echo $form->val('first-name'); ?>" id="first-name">
                            <?php echo $form->feedBackFor('first-name'); ?>
                        </li>
                        <li class="last-name">
                            <label for="last-name">Last Name</label>
                            <input maxlength="25" type="text" name="<?php echo $form->nameFor('last-name'); ?><?php if($form->missing('last-name')) { ?>class="missing" <?php ?>value="<?php echo $form->val('last-name'); ?>" id="last-name">
                            <?php echo $form->feedBackFor('last-name'); ?>
                        </li>
                        <li class="birth-date">
                            <label>Birth Date</label>
                    
                            <select name="<?php echo $form->nameFor('birth-day'); ?><?php if($form->missing('birth-day')) { ?>class="missing" <?php ?>id="day">            
                            <option value="">d</option>
                            <?php 
                            $match
    =false;
                            
    $days range(1,31,1);
                            foreach(
    $days as $value) { ?>
                                <option value="<?php echo $value?>"<?php if(!$match && strcmp($form->val('birth-day'),$value)==0) { echo ' selected="selected"';$match=true; } ?>><?php echo $value?></option>
                            <?php ?>
                            </select>
                    
                            <select name="<?php echo $form->nameFor('birth-month'); ?><?php if($form->missing('birth-month')) { ?>class="missing" <?php ?>id="month">
                            <option value="">m</option>
                            <?php 
                            $match
    =false;
                            foreach(
    $this->_months as $key=>$value) { ?>
                                <option value="<?php echo $value?>"<?php if(!$match && strcmp($form->val('birth-month'),$value)==0) { echo ' selected="selected"';$match=true; } ?>><?php echo $key?></option>
                            <?php ?>    
                            </select>
                    
                            <select name="<?php echo $form->nameFor('birth-year'); ?><?php if($form->missing('birth-year')) { ?>class="missing" <?php ?>id="year">
                            <option value="">y</option>
                            <?php 
                            $match
    =false;
                            
    $years array_reverse(range(1900,(date("Y")-17),1));
                            foreach(
    $years as $value) { ?>
                                <option value="<?php echo $value?>"<?php if(!$match && strcmp($form->val('birth-year'),$value)==0) { echo ' selected="selected"';$match=true; } ?>><?php echo $value?></option> 
                            <?php ?>    
                            </select>
                            
                            <?php echo $form->feedBackFor('birth-date'); ?>
                    
                        </li>
                        <li class="country">
                            <label for="country">Country</label>
                            <select name="<?php echo $form->nameFor('country'); ?><?php if($form->missing('country')) { ?>class="missing" <?php ?>id="country">
                            <option value="">select</option>
                            <?php 
                            $match
    =false;
                            foreach(
    $this->_countries as $value) { ?>
                                <option value="<?php echo $value?>"<?php if(!$match && strcmp($form->val('country'),$value)==0) { echo ' selected="selected"';$match=true; } ?>><?php echo $value?></option>
                            <?php ?>    
                            </select>
                            <?php echo $form->feedBackFor('country'); ?>
                        </li>
                    </ol>
                    <ol id="city-email">
                        <li class="email">
                            <label for="email">Email</label>
                            <input maxlength="100" type="text" name="<?php echo $form->nameFor('email-address'); ?><?php if($form->missing('email-address')) { ?>class="missing" <?php ?>value="<?php echo $form->val('email-address'); ?>" id="email">
                            <?php echo $form->feedBackFor('email-address'); ?>
                        </li>
                        <li class="city">
                            <label for="city">City</label>
                            <input maxlength="50" type="text" name="<?php echo $form->nameFor('city'); ?><?php if($form->missing('city')) { ?>class="missing" <?php ?>value="<?php echo $form->val('city'); ?>" id="city">
                            <?php echo $form->feedBackFor('city'); ?>
                        </li>
                    </ol>
                    <ol id="user">
                        <li class="id">
                            <label for="id">Desired User Name</label>
                            <input maxlength="15" type="text" name="<?php echo $form->nameFor('desired-name'); ?><?php if($form->missing('desired-name')) { ?>class="missing" <?php ?>value="<?php echo $form->val('desired-name'); ?>" id="id">
                            <?php echo $form->feedBackFor('desired-name'); ?>
                        </li>
                        <li class="pwd">
                            <label for="password">Password</label>
                            <input maxlength="20" type="password" name="<?php echo $form->nameFor('desired-password'); ?><?php if($form->missing('desired-password')) { ?>class="missing" <?php ?>value="<?php echo $form->val('desired-password'); ?>" id="pwd">
                            <?php echo $form->feedBackFor('desired-password'); ?>
                        </li>
                        <li class="security-question">
                            <label for="security-question">Security Question</label>
                            <select name="<?php echo $form->nameFor('security-question'); ?><?php if($form->missing('security-question')) { ?>class="missing" <?php ?>id="security-question">
                            <option value="">select</option>
                            <?php 
                            $match
    =false;
                            foreach(
    $this->_questions as $value) { ?>
                                <option value="<?php echo $value?>"<?php if(!$match && strcmp($form->val('security-question'),$value)==0) { echo ' selected="selected"';$match=true; } ?>><?php echo $value?></option> 
                            <?php ?>
                            </select>
                            <?php echo $form->feedBackFor('security-question'); ?>
                        </li>
                        <li class="security-answer">
                            <label for="security-answer">Security Answer</label>
                            <input maxlength="25" type="text" name="<?php echo $form->nameFor('security-answer'); ?><?php if($form->missing('security-answer')) { ?>class="missing" <?php ?>value="<?php echo $form->val('security-answer'); ?>" id="security-answer">
                            <?php echo $form->feedBackFor('security-answer'); ?>
                        </li>
                    </ol>
                </fieldset>    
        
                <fieldset class="optional">
                    <ol class="bio">
                        <li class="bio">
                            <label for="bio">Personal Bio</label>
                            <textarea name="<?php echo $form->nameFor('bio'); ?>" id="bio"><?php echo $form->val('bio'); ?></textarea>
                            <?php echo $form->feedBackFor('bio'); ?>
                        </li>
                    </ol>
                    <ol class="profile">
                        <li class="state">
                            <label for="state">State</label>
                            <select name="<?php echo $form->nameFor('state'); ?>" id="state">
                            <option value="">select</option>
                            <?php 
                            $match
    =false;
                            foreach(
    $this->_states as $key=>$value) { ?>
                                <option value="<?php echo $value?>"<?php if(!$match && strcmp($form->val('state'),$value)==0) { echo ' selected="selected"';$match=true; } ?>><?php echo $value?></option>
                            <?php ?>
                            </select>
                            <?php echo $form->feedBackFor('state'); ?>
                        </li>
                        <li class="phone">
                            <label for="phone">Phone</label>
                            <input maxlength="20" type="text" name="<?php echo $form->nameFor('phone-number'); ?>" value="<?php echo $form->val('phone-number'); ?>" id="phone">
                            <?php echo $form->feedBackFor('phone-number'); ?>
                        </li>
                        <li class="website">
                            <label for="website">Website<?php echo $form->feedBackFor('website'); ?></label>
                            <input maxlength="100" type="text" name="<?php echo $form->nameFor('website'); ?>" value="<?php echo $form->val('website'); ?>" id="website">
                            <?php echo $form->feedBackFor('website'); ?>
                        </li>
                    </ol>
                    <input type="submit" name="register" id="submit" value="Register">
                </fieldset>

            </form>
        
        <?php }

    }
    ?>
    Ignoring all the arrays the processor method returns the appropriate processor and the base class is responsible for calling the beginning methods. It can call those methods because the processor is a Processable object based on its implementation of the Processable interface.

    Furthermore, the render() method then uses the processor object stored as a property i the base class as a means to communicate with the processor. This allows the data processing and visual aspects to be separated in the code. The processor is only responsible for processing data and the form is only responsible for displaying the form, and may change the way it shows the form(creates the html) based on information from the processable. However, it will never handle logic beyond communicating with the processor as its the processors sole job to handle the actual data.

    That is pretty much the system I have been using for a couple months and I find it incredibly flexible and reusable because nothing is automated. However, key methods exist that you may define your own implementation for on a individual basis. It also separates the data/error handling from the visual aspects for cleaner and more readable code. Just something I thought I would share as I've yet to see similar concept and implementation of form processing. Normally, the ideal seems to be to generalize, but that often leads to problems down the road. I think having a system that is malleable at least provides a alternative and a different way to consider things if nothing else.

  7. #7
    SitePoint Guru
    Join Date
    Jan 2005
    Location
    heaven
    Posts
    953
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If your using Zend Form then your also going to be using Zend View, Zend Validate, Zend Filter and you'll probably want to use Zend Cache as well. So in that sense, it does get a little cumbersome. But Zend Form is fairly well designed in many areas, though you could probably create a smaller Form class that is just as flexible, using Decorator and Strategy design patterns. But sooner or later you'll begin realizing that you've essentially re-written Zend Form -- I speak from personal experience ._. ..
    Creativity knows no other restraint than the
    confines of a small mind.
    - Me
    Geekly Humor
    Oh baby! Check out the design patterns on that framework!

  8. #8
    SitePoint Member
    Join Date
    Jan 2009
    Location
    Sibiu, Romania
    Posts
    15
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Searching more on the internet for good form validation solutions I found the FormProcessor class ( http://www.richardwillars.com/articl...orm-processor/ ). It seems that this implementation was developed starting from an blog post written back in 2003 ( http://simonwillison.net/2003/Jun/17/theHolyGrail/ ) - notice the URL name???

    What do you guys think about this approach?

    titel

  9. #9
    SitePoint Enthusiast
    Join Date
    Jul 2005
    Location
    Norway
    Posts
    88
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You could try ini files. There is a function in php called parse_ini_file which parses an ini file to an array. This means that you could specify your validation rules like this:

    person.ini:

    [firstName]
    required = true
    minLenght = 2

    [lastName]
    required = true
    minLenght = 2

    [username]
    regEx = '/^[a-zA-Z0-9_-]{4,16}$/'

    To validate a form, you would then call a method in a class like this: $obj->validate('person.ini', $data);

    This class needs to implement the validate method and one method for each type of validation (minLength, maxLength, regEx...), including the error-messages. You could put the error-messages in session and load them on the next page-request.

    This class could also be extended for different modules/apps to create specialized validation of some kind..

    I have not tested this method thoroughly, it might have some pitfalls..

    Another method I have just heard of but not tested, is to populate forms with javascript. One would pass an array of data to javascript via json_encode and let some javascript function loop through the inputs in a form and populate it..

  10. #10
    SitePoint Enthusiast
    Join Date
    Aug 2008
    Location
    Australia
    Posts
    31
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I find this method using regex very easy, all you really have to do is copy and paste and change up a couple things for any form. You just store the regex patterns in an array like this:

    PHP Code:
      $someform_validations = array('title' => '/^[[:alnum:][:punct:][:space:]]{1,50}$/',
                                   
    'description' => '/^[[:alnum:][:punct:][:space:]]{1,255}$/',
                                   
    'body' => '/^[[:alnum:][:punct:][:space:]]{1,15000}$/',
                               ); 
    Then you just loop through using preg_match to match them against the posted data, and if any don't match return an error and have them fix it.

  11. #11
    SitePoint Wizard silver trophybronze trophy Stormrider's Avatar
    Join Date
    Sep 2006
    Location
    Nottingham, UK
    Posts
    3,133
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    I'm thinking about specifying forms with XML on my next project, but not sure yet

  12. #12
    SitePoint Member
    Join Date
    Jan 2009
    Location
    Sibiu, Romania
    Posts
    15
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So guys, what's the deal?

    I'm sure if this thread will help many people, and maybe you as well, so please contribute any other advice you might have concerning form validation.

    So far, the closest solution to what I was looking for is the Form Processor class ( http://www.richardwillars.com/articl...orm-processor/ ) which basically relies on defining the validation rules and the associate error messages as XML code, inside the XHTML form itself.

    Did any of you guys try this class, or are you aware or concerned about any reason for which it would not be a good choice?

    Are there any other solutions that provide a similar functionality, that are reusable and as simple to implement as this one?

    Thank you for your contribution,
    titel

  13. #13
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It's a nice solution for simple cases, but I'm not sure I like the idea of putting form validation logic inside the template. It's simply not the proper place for that.

    Basically this looks very similar to asp. For PHP you might have a look at prado, which does some of the same.

  14. #14
    Use The Cloud
    Join Date
    Jan 2006
    Location
    Boise, ID
    Posts
    556
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by titel View Post
    So guys, what's the deal?

    I'm sure if this thread will help many people, and maybe you as well, so please contribute any other advice you might have concerning form validation.

    So far, the closest solution to what I was looking for is the Form Processor class ( http://www.richardwillars.com/articl...orm-processor/ ) which basically relies on defining the validation rules and the associate error messages as XML code, inside the XHTML form itself.

    Did any of you guys try this class, or are you aware or concerned about any reason for which it would not be a good choice?

    Are there any other solutions that provide a similar functionality, that are reusable and as simple to implement as this one?

    Thank you for your contribution,
    titel
    That class is terrible, I would be surprised if the author ever took a CS course in his life. He has no concept of OOP or writing readable, maintainable code.

    There's this guideline where you're supposed to limit scope of a function to about a screen of code, and line length to around 80 characters...

    On my 19" monitor the first method took up 5 screen lengths, and line lengths are pushing 160 characters! Not to mention the use of the deprecated var when it is clearly a PHP5 script.

    Anyway, if you look at the source, it's a prime example of everything not to do in a PHP program.

    Here's an example I posted a little while ago showing a basic form class from the ground up utilizing OOP and object composition:

    http://www.sitepoint.com/forums/showpost.php?p=4094642

    Edit:

    To clarify, I'm a big proponent for using pre-built libraries for as much functionality as possible, but I absolutely refuse to use code in my projects that completely sucks, such as the above.
    Brad Hanson, Web Applications & Scalability Specialist
    ► Is your website outgrowing its current hosting solution?
    ► PM me for a FREE scalability consult!
    ► USA Based: Available by Phone, Skype, AIM, and E-mail.

  15. #15
    SitePoint Guru
    Join Date
    Jun 2006
    Posts
    638
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Use something like this:
    http://www.phppatterns.com/docs/desi...ern?s=strategy

    It's way cleaner than anything else I see posted here.

    Littlej's method works also, but 2 problems with that:
    - #1 you either put that array on each page, and end up with duplicate rules (ex: email rule on login, registration, options)
    - #2 you put all the rules in one file, include that file and keep using the same map, but then you include allot of unused validation rules (some big sites might have quite a few)

    bhanson, get with the times, we have horizontal scroll bars now.
    Also, most serious developers use 2 screens, working with one 19" is like working with both hands and one leg tied behind your back, and typing with ... well you fill in the blanks here (seriously, when I changed from 1 19" to 2, my productivity doubled)

  16. #16
    Use The Cloud
    Join Date
    Jan 2006
    Location
    Boise, ID
    Posts
    556
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Vali View Post
    bhanson, get with the times, we have horizontal scroll bars now.
    Also, most serious developers use 2 screens, working with one 19" is like working with both hands and one leg tied behind your back, and typing with ... well you fill in the blanks here (seriously, when I changed from 1 19" to 2, my productivity doubled)
    You're joking right? Are you actually defending that junk script? Did you even look at the code? You cannot see at that and honestly look someone in the eyes and say you would enjoy maintaining that. Horizontal scroll bars are retarded and if your subroutines last any longer than about the page, you have serious design issues.

    Okay, you use two 19" screens, great. Do you really want the code to span across both monitors? I've never seen anyone program with code spaned across multiple monitors.

    Anyway, I'm not sure what point you were trying to make other than saying you use two monitors.
    Brad Hanson, Web Applications & Scalability Specialist
    ► Is your website outgrowing its current hosting solution?
    ► PM me for a FREE scalability consult!
    ► USA Based: Available by Phone, Skype, AIM, and E-mail.

  17. #17
    SitePoint Guru
    Join Date
    Jun 2006
    Posts
    638
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by bhanson View Post
    You're joking right? Are you actually defending that junk script?
    Was referring to your 80 char limit comment. That was set to 80 because back in the old days (1980 or something), most computer terminals could only display 25 rows of 80 columns of text on screen at once.

    I can fit around 225 characters on my screen (1 of them), not to say that you should put a 225 characters limit on your code. Butas long as the most important stuff is on the left of the line, and when you scroll to it you can see it, the 80 character limit does not apply no more.

    Quote Originally Posted by bhanson View Post
    Do you really want the code to span across both monitors? I've never seen anyone program with code spaned across multiple monitors.
    Ya... sure why not, and when I run out of screen I use a notebook on the right on my second 24" screen... just so my lines can be longer.

    And the guys class, even if I don't necessarily agree with it, has some good ideas (like the rules in the xml file), so it can still be used to give some useful ideas on how someone solved this problem. (and I seen worst classes...)

  18. #18
    Use The Cloud
    Join Date
    Jan 2006
    Location
    Boise, ID
    Posts
    556
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Vali View Post
    Was referring to your 80 char limit comment. That was set to 80 because back in the old days (1980 or something), most computer terminals could only display 25 rows of 80 columns of text on screen at once.

    I can fit around 225 characters on my screen (1 of them), not to say that you should put a 225 characters limit on your code. Butas long as the most important stuff is on the left of the line, and when you scroll to it you can see it, the 80 character limit does not apply no more.
    Actually it very much still applies. Humans can only interpret and understand so much in one line. 80 is the guideline and around 120 is the maximum any line should be. Anything past 120 has a significant diminished human readability penalty.

    Why do you think books break things up into multiple columns? Or use really wide margins.

    I can say pretty definitively that you should never have a line of code that is 225 characters in length, unless the goal of the project is brevity and whitespace is a secondary concern.
    Brad Hanson, Web Applications & Scalability Specialist
    ► Is your website outgrowing its current hosting solution?
    ► PM me for a FREE scalability consult!
    ► USA Based: Available by Phone, Skype, AIM, and E-mail.

  19. #19
    SitePoint Member
    Join Date
    Jan 2009
    Posts
    13
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Brad,

    I'm Richard, the guy the created PHP Form Processor script you've been talking about. I was looking through my website stats and happened to see a few referrals from this thread, so decided to have a read through.

    Some very interesting opinions here, ones that i'll definetely take into account when coding in the future...

    Quote Originally Posted by bhanson View Post
    That class is terrible, I would be surprised if the author ever took a CS course in his life. He has no concept of OOP or writing readable, maintainable code.
    When I initially wrote this script I had just completed an OOP module on my Computer Science course at university. Yes, I may not be the best at OOP but everyone has to start somewhere.. more than anything this project has provided me with a learning curve and some practical experience at coding in this style.


    Quote Originally Posted by bhanson View Post
    There's this guideline where you're supposed to limit scope of a function to about a screen of code, and line length to around 80 characters...

    On my 19" monitor the first method took up 5 screen lengths, and line lengths are pushing 160 characters! Not to mention the use of the deprecated var when it is clearly a PHP5 script.

    Anyway, if you look at the source, it's a prime example of everything not to do in a PHP program.
    I was unaware of any standards/guidelines as to the length of functions and line length, but this is useful to know for in the future. I'm quite immune to line length problems as I'm using a 24" iMac. I also didn't know that var had been deprecated in PHP 5 so I've updated the script to suit. As to the length of the method I don't see the problem.. as long as the method achieves its objective(s) then I don't see why the length of it matters. Surely by limiting how long you can have the method is just limiting the amount of functionality that the method can achieve.

    Quote Originally Posted by bhanson View Post
    Even though his code uses a class, it's a gigantic POS. Basically he just dumped a bunch of functions in a class.
    Thanks for that, a very mature remark. No I may not be the world's best programmer, but the aim of the script was to achieve a certain task and solve a problem, and it does that quite well. No the code may not be the best format etc but I am striving to improve it (when I can find the time). As to 'dumping a bunch of functions in a class' you're completely wrong.. each function was written from scratch just for that class.

    Anyway, I've learnt a few lessons and I'd suggest that you learn some decent manners and how to give positive criticism instead of just ripping down others code. I released that script with good intentions to help others, and it's people like you with remarks such as "it's a gigantic POS" which make me reluctant to contribute code in the future.

    Richard

  20. #20
    Use The Cloud
    Join Date
    Jan 2006
    Location
    Boise, ID
    Posts
    556
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Richard,

    Quote Originally Posted by richwillars View Post
    When I initially wrote this script I had just completed an OOP module on my Computer Science course at university. Yes, I may not be the best at OOP but everyone has to start somewhere.. more than anything this project has provided me with a learning curve and some practical experience at coding in this style.
    That's good, you have to start from somewhere. The only point I was trying to make is that others probably shouldn't be using your "learning" scripts. There are some huge concepts you have yet to grasp and if others are relying on your script to work, well... I just don't think it's a very good idea.

    Quote Originally Posted by richwillars View Post
    I was unaware of any standards/guidelines as to the length of functions and line length, but this is useful to know for in the future. I'm quite immune to line length problems as I'm using a 24" iMac. I also didn't know that var had been deprecated in PHP 5 so I've updated the script to suit. As to the length of the method I don't see the problem.. as long as the method achieves its objective(s) then I don't see why the length of it matters. Surely by limiting how long you can have the method is just limiting the amount of functionality that the method can achieve.
    See, the thing is, line length is about so much more than how many characters you can fit on your particular monitor. It's about readability. Anything past 120 characters has a very significant human readability penalty. It's hard for humans to grasp the entire scope of the line when they start getting that long. Google around for "coding standards" and I think you'll find nearly every single one has a maximum line length of 80-120 characters.

    The point of limiting method length is limiting the functionality! Right now, your first method does way too much. It should almost certainly be refactored into either several methods or several classes. The scope of each method should be very simple, and it is the combination of multiple methods which creates our desired functionality. When you place too much code into a method it becomes harder to read, harder to maintain, and harder to understand what it really does. If you make one change in a large method it could break a lot of functionality where as if they were broken down into smaller methods, the scope of the problem becomes easier to see.

    Quote Originally Posted by richwillars View Post
    Thanks for that, a very mature remark. No I may not be the world's best programmer, but the aim of the script was to achieve a certain task and solve a problem, and it does that quite well. No the code may not be the best format etc but I am striving to improve it (when I can find the time). As to 'dumping a bunch of functions in a class' you're completely wrong.. each function was written from scratch just for that class.

    Anyway, I've learnt a few lessons and I'd suggest that you learn some decent manners and how to give positive criticism instead of just ripping down others code. I released that script with good intentions to help others, and it's people like you with remarks such as "it's a gigantic POS" which make me reluctant to contribute code in the future.
    I'm sorry if you take offense to that, I did not mean it as a personal insult but rather it is directed at the script, and it is quite true.

    You're not really using OOP in the script, just using classes. It's hard to really explain as it's one of those things kind of like recursion. In order to understand recursion, you must first understand recursion.

    Anyway, maybe it's just me, but I personally appreciate when other people are completely honest with me. Direct and to the point creates the highest level of efficiency. If something I do sucks, I'd kind of want someone to tell me about it so I can fix it, instead of getting only half of the story by being pampered.

    So yes, I have directly and publicly told you that your script sucks in respect to format and methodology. You have two choices, you can say I'm an ****, or you can maybe admit that your script does suck and learn how to fix it. If I were you, I'd choose the latter.
    Brad Hanson, Web Applications & Scalability Specialist
    ► Is your website outgrowing its current hosting solution?
    ► PM me for a FREE scalability consult!
    ► USA Based: Available by Phone, Skype, AIM, and E-mail.

  21. #21
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Richard, welcome to Sitepoint.

    Brads words may come off a little harsh, but if there's one thing I've learned from hacker culture, it is that the tone is rather direct. You really don't need to take it as a personal attack, when someone criticise your work. I know that's a lot easier said than done; Code is a reflection of your thought process at the time of making, so when it's criticised, it can feel like it's directed at your person. It's the same problem that any artist faces.

    The other side of the equation is of course that programming is a craft and as such there are a lot of subjectivity to the implementation choices. Hackers can get really opinionated about these aesthetics. So while I agree that it's inappropriate to call someones work a POS, you have to appreciate that he is using this language because he actually care; Just like you must be doing, since you can take offence about it.

    I have to say that if this is your first venture into object oriented programming, you have done quite good. I certainly hope that you'll keep contributing to the collective pool of open source.

    Quote Originally Posted by richwillars View Post
    I also didn't know that var had been deprecated in PHP 5 so I've updated the script to suit.
    It's a good idea to develop with php error-reporting set to strict. By default, certain kinds of warnings are hidden. If you put this line at the top of your script, you'll get warnings on a lot of things, such as the deprecated var keyword:
    PHP Code:
    error_reporting(E_ALL E_STRICT); 
    Quote Originally Posted by richwillars View Post
    I was unaware of any standards/guidelines as to the length of functions and line length, but this is useful to know for in the future. I'm quite immune to line length problems as I'm using a 24" iMac. As to the length of the method I don't see the problem.. as long as the method achieves its objective(s) then I don't see why the length of it matters. Surely by limiting how long you can have the method is just limiting the amount of functionality that the method can achieve.
    The idea about maximum line length, as well as a limit to the size of a function body, are rules of thumb. The assumption is that these metrics generally means that the code is getting complex. Such complexity can usually be remedied by refactoring the code; For example by moving blocks of code out to separate functions. Source code has two targets - The computer and other programmers. The former has no problem with complexity, as long as it works, but the latter needs abstractions to have any chance of understanding what's going on.

  22. #22
    SitePoint Wizard Hammer65's Avatar
    Join Date
    Nov 2004
    Location
    Lincoln Nebraska
    Posts
    1,161
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by titel View Post
    Hi guys,

    I'm sure that many of you, like me, hate writing boring form validation. Form validation seems to be the least interesting thing in web development and, however, the activity that takes most of the time in the development of an online project.

    What I'm trying to look for now, is a way, some simple to implement and reusable functions or a class that would allow me to automate somehow this validation process.

    I was wondering, if any of you guys have found some smart way of doing this, my only requirements for this would be that this method would work for the most important input types (text input, radio and check boxes, text areas and select boxes - at least) and that I can still write myself the markup of the form itself ( I many times need that for styling ).

    Thank you in advance for your input,
    titel
    I wrote my own classes for this. The same code takes care of both client side and server side validation. Each field that is to have requirements has an array of rules that it will be validated against. Each field can also have a list of fields that it is dependent on. If any one of those dependent fields passes it's test(s), then that field is run through it's validation rules (ie if a checkbox is checked, then determine if this field is a valid email address, if it's not then return true and don't validate). The code is as simple as the following...

    PHP Code:
    // for server side
    $method 'POST';
    $v = new validator($method);
    $v->addField('first_name','First Name'); // name of field and label to show on error
    $v->addRule('first_name','set'); // name of field and validation function to use
    $v->addField('last_name','Last Name');
    $v->addRule('last_name','set');
    $v->addField('email','E-Mail Address');
    $v->addRule('email','set');
    $v->addRule('email','email');
    if(
    $v->validate())
    {
       
    //Validated
    }
    else
    {
        
    // handle errors
    }

    // for client side
    $v = new validator($method);
    $v->addField('first_name','First Name'); // name of field and label to show on error
    $v->addRule('first_name','set'); // name of field and validation function to use
    $v->addField('last_name','Last Name');
    $v->addRule('last_name','set');
    $v->addField('email','E-Mail Address');
    $v->addRule('email','set');
    $v->addRule('email','email');
    /* the following call prints a .js file (or script tag content) that extends a form with the specified id attribute in Javascript with validation methods exactly the same as PHP. Using jQuery and some custom code of my own  on submit the validation is performed.*/
    $v->render($formid); 
    The is a validation class with a "fields" member that holds all field objects, a field class (that represents each field value specified for validation) and a class that holds all of the validation methods. This is somewhat different than having a separate class for each validation type, which is what Zend validation does, but it seems to work well for me, and keeps the number of files down to a minimum.
    Visit my blog
    PHP && Life
    for technology articles and musings.

  23. #23
    SitePoint Enthusiast
    Join Date
    Jul 2005
    Posts
    36
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It's amazing to me how, given a relatively short timeline, ANY general forum discussion degrades into an argument about something completely unrelated to the actual topic at hand. Way to go guys. Let's spend all our time discussing whether this guy is a good programmer or not.

    Anyway, that said, I noticed that no one has mentioned anything about the relatively new filter_var function in PHP5. Built in email, url, etc. validation. I was just recently turned onto the function, and plan on writing a new Holy Grail Form Validator for myself. It seems worth looking into anyway. So I thought I would mention it.

  24. #24
    SitePoint Wizard Hammer65's Avatar
    Join Date
    Nov 2004
    Location
    Lincoln Nebraska
    Posts
    1,161
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lusus View Post
    It's amazing to me how, given a relatively short timeline, ANY general forum discussion degrades into an argument about something completely unrelated to the actual topic at hand. Way to go guys. Let's spend all our time discussing whether this guy is a good programmer or not.
    Well the OP asked for a discussion on the approach to use for validation to make the code reusable and easy to implement. That implies a need to write it once and use it often with minimum amount of time to modify/improve the functionality. That does not just mean paying attention to class structure, but also basic programming best practices. I wouldn't word things quite the way some have, but dividing up functionality among class methods in a logical manner is crucial if you want to make your code a time saving useful tool. As was mentioned, line length and the number of lines used in a method is a rule of thumb. Readability, and maintainability is the goal, not a hard number.

    Anyway, that said, I noticed that no one has mentioned anything about the relatively new filter_var function in PHP5. Built in email, url, etc. validation. I was just recently turned onto the function, and plan on writing a new Holy Grail Form Validator for myself. It seems worth looking into anyway. So I thought I would mention it.
    Those functions are certainly useful, but due to the fact that they are relatively new, they may not be suitable for code that is meant to be portable from one PHP 5 distro to another.
    Visit my blog
    PHP && Life
    for technology articles and musings.

  25. #25
    SitePoint Enthusiast
    Join Date
    Jul 2005
    Posts
    36
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    See what I mean.

    Good input about it being new. Anyone else?

    Any other ideas about a good solution to form validation?


Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •