PHP Functional Validation

AlexanderREnterprise Web Developer
CERTIFIED EXPERT
Published:
Updated:
DISCLAIMER:
The article has been written prior to good programming practices being established in the PHP ecosystem.  This article is meant to be viewed for historical purposes to see the types of mistakes that were made in that era that are now labeled as "unmaintainable legacy spaghetti". If you are reading it, do not follow the practices; instead, view it as a collection of mistakes to learn from and not repeat.

ABSTRACT:
I've answered few questions about how best to validate an HTML form or how to fix/improve existing one. Each time i just linked to the question where i first answered this question by utilizing this technique.  Since it works every time for many cases, I created this article so i can answer this common question once and for all.  I will not just give the code and explain how it works. Instead, i will show step by step how to build it for better understanding of how it works.

NOTE: How to validate FOR something is beyond this article.

PROS:
*a simple solution
*preserves what the user has typed in the fields
*displays errors
*add validators easily

CONS:
*cannot be split between files (except for the individual validators) so cannot be easily modularized
*not applicable for complex sites where code duplication is an issue should use a proper validator system, like Zend_form and Zend_validate from Zend framework.

BTW, it's called "Functional", because every section is isolated in a function and some logic at the top of the execution figures out which function to call.

Lets begin:
 

1. Start off with


a typical HTML form
 
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
                        User name:<input type="text" name="user_name"><p>
                        Email: <input type="text" name="user_email"><p>
                        Language: 
                          <input type="radio" name="language" value="php">PHP
                          <input type="radio" name="language" value="python">Python
                        <p>
                        Application type: 
                          <select name="type">
                            <option value="">Select</option>
                            <option value="desktop">Desktop</option>
                            <option value="web">Web</option>
                            <option value="network">Network</option>
                          </select>
                        <input type="hidden" name="submit" value="1">
                        <input type="Submit" value="Go">
                      </form>
                      

Open in new window

Note the hidden input type.  Its value will be used to decide if the user submitted the form or not.  This way is safer and easier than testing for input type submit.
Also note that the form submits to the same page it is located on.

 

2. Create the skeleton for the the page


Now we put the form (along with any other html you want to go with it) in a separate function.  Also create body for all other functions we need.
<?php
                      
                      function inputData(){?>
                      <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
                        User name:<input type="text" name="user_name"><p>
                        Email: <input type="text" name="user_email"><p>
                        Language: 
                          <input type="radio" name="language" value="php">PHP
                          <input type="radio" name="language" value="python">Python
                        <p>
                        Application type: 
                          <select name="type">
                            <option value="">Select</option>
                            <option value="desktop">Desktop</option>
                            <option value="web">Web</option>
                            <option value="network">Network</option>
                          </select>
                        <input type="hidden" name="submit" value="1">
                        <input type="Submit" value="Go">
                      </form>
                      <?php
                      }
                      
                      function processData(){
                      
                      }
                      
                      function validateData($data){
                      
                      }
                      ?>
                      

Open in new window

 

3. Add execution logic


Add this code above inputData() function:
 
if($_POST["submit"]){
                         $data = $_POST;
                         if (validateData($data)){
                            inputData();
                         } else {
                            processData();
                         }
                      } else {
                         inputData();
                      }
                      

Open in new window

Nothing out of an ordinary here (yet).  If variable $_POST[]"submit"], which comes from that hidden field in the form, is true then it will try to validate the input (which is now in $data array). If validation succeeds (next step) it will go to process the data, if not  - display the form again.
For this tutorial I just put all of $_POST into $data.  However, I recommend that you manually put each submitted value into $data like:
$data[]'user_name'] = $_POST'[user_name'];
for additional security.
 

4. Validate


Now we add validators to validateData() function.
 
function validateData($data){
                        if(trim($data['user_name']) == ""){
                          $errors[] = "User name cannot be empty";
                        }
                      
                        if(!trim(eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $data['user_email']))){
                          $errors[] = "Invalid email format";
                        }
                      
                        if(!isset($data['language'])){
                          $errors[] = "No language was chosen";
                        }
                        if($data['type'] == "0"){
                          $errors[] = "Select type of application";
                        }
                        return $errors;
                      }
                      

Open in new window


and modify the execution logic from step 3:
 
if($_POST["submit"]){
                         $data = $_POST;
                         if ($errors = validateData($data)){
                            inputData($errors);
                         } else {
                            processData();
                         }
                      } else {
                         inputData();
                      }
                      

Open in new window

What's happening is that for every error it detects a message is recorded into $errors array.  So if there is at least one error, $errors = validateData($data) will return true and go to inputData. If array is empty it will return false and processData instead.
Of course you can check for anything else, like if the data is numeric or the user is unique (see tip2)
 

5. Show errors


At this point validation should work, but the user does not know what errors he made when the form is returned.  Modify first lines of inputData() function like so:
 
function inputData($errors = ''){
                         if($errors != ""){
                            echo "There were problems with your input:<ul>";
                            foreach($errors as $error){
                               echo "<li>".$error."</li>";
                            }
                            echo "</ul>";
                         }?>
                      <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
                      

Open in new window

Now you should see why I assign the output of validateData in the if statement: $errors = validateData($data).  I pass the error messages as a parameter to inputData function, which is empty by default.  If there are any errors they are displayed in UL/LI list.  Format them as you wish.
 

6. Keep user input


Just because user made one mistake, does not mean he has to enter the entire from scratch.  In this step, we will make another use of $data array. But first, need to modify the form.  Put $data[]'fieldname'] as a value for each field. For radio buttons and select menus have to do an if statement.
 
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
                        User name:<input type="text" name="user_name" value="<?php echo $data['user_name']; ?>"><p>
                        Email: <input type="text" name="user_email" value="<?php echo $data['user_email']; ?>"><p>
                        Language: 
                          <input type="radio" name="language" value="php" <?php if($data['language']=='php'){ echo 'checked'; }?> >PHP
                          <input type="radio" name="language" value="python" <?php if($data['language']=='python'){ echo 'checked'; }?> >Python
                        <p>
                        Application type: 
                          <select name="type">
                            <option value="0">Select</option>
                            <option value="desktop" <?php if($data['type']=='desktop'){ echo 'selected'; }?> >Desktop</option>
                            <option value="web" <?php if($data['type']=='web'){ echo 'selected'; }?> >Web</option>
                            <option value="network" <?php if($data['type']=='network'){ echo 'selected'; }?> >Network</option>
                          </select>
                        <input type="hidden" name="submit" value="1">
                        <input type="Submit" value="Go">
                      </form>
                      

Open in new window

$data has to come from somewhere, so just add it as another parameter in function declaration:
function inputData($errors = '',$data = ''){
and function call.
inputData($errors,$data);

Bunch of if statements may look ugly right now, but most of the time the actual values from SELECT input are usually an ID from the DB or such so you would iterate through them in foreach or for loop.  Then you just need a single if statement.
 

7. Process


Thats basically it for validation.  You can now do whatever you want with validated data in processData() function. Just don't forget to pass it $data array up in the top of the page and make it a parameter in the function declaration.
For this example I'll just output the $data array:
function processData($data){
                      print_r($data);
                      }
                      

Open in new window

 

8. Tip1: modularize validators


If you need to use this technique on a number of pages, to avoid copy/pasting validators (copy/paste any part of your code is considered as bad practice) you can put each validator's if statement in a separate function and put them all in a separate file.  Then you can just include the file with validators anywhere:
file validators.php:
 
function notEmpty($field){
                      	if(trim($field) == ""){
                        		return 1;
                      	} else {
                      		return 0;
                      	}
                      }
                      
                      function isNumeric(){
                      
                      }
                      

Open in new window


Back to main file:
include('validators.php');
                      function validateData($data){
                        if(notEmpty($data['user_name'])){
                          $errors[] = "User name cannot be empty";
                        }
                      

Open in new window

 

9. Tip2: unique user


Even though I said that validating FOR something is beyond the scope of this tutorial, I still feel its necessarily to include this because it may not be very obvious how to do it.
In this example I will check that user_name is unique in the table users in column user_name.  Also, I will only do this validation if the user_name input field in the form is not empty so I do not waste database resources.   Therefore, I will put the whole thing in the else part of the user_name check:

 
  if(notEmpty($data['user_name'])){
                          $errors[] = "User name cannot be empty";
                        } else {
                          $sqlCheckUser = "SELECT COUNT(*) FROM users WHERE user_name = '".$data['user_name']."'";
                          $rsCheckUser = mysqli_query($dblink,$sqlCheckUser);
                          $user_num = mysqli_fetch_row($rsCheckUser);
                          $user_num = $user_num[0];
                          if($user_num > 0){
                            $errors[] = "User name already taken";
                          }
                        }
                      

Open in new window


Thats it!
2
3,422 Views
AlexanderREnterprise Web Developer
CERTIFIED EXPERT

Comments (2)

Commented:
Hey! nice...

Except eregi has just been deprecated on php 5.3; You could rewrite your code for preg_match!

Cool article!
Email validation can easily be done by using filter_var:

filter_var('e@mail.com', FILTER_VALIDATE_EMAIL);

Open in new window

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.