How to Validate a Form Using PHP Part 2: Streamline Using Arrays

errorpart2We’ve touched upon the basic elements of form validation and error messages in part 1 of this series, which outlines a relatively static method identifying errors and validating a form. In this edition we are going to make the elements we began with more dynamic and reduce the amount of script required to do so using arrays.

Setting Up the Form

First we’re going to want to create a form on a new .php document, mine is going to be called errorpart2.php. Below is my form complete with fields name, email, and comments.

<form id="commentform" method="post" action="errorpart2.php">
	<p>
	<label for="name">Name:</label>
	<br/>
	<input name="name" id="name" type="text"/>
	</p>
	<p>
	<label for="email">Email:</label> <br/>
	<input name="email" id="email" type="text"/>
	</p>
	<p>
	<label for="comments">Comment:</label>
	<br/>
	<textarea name="comments" id="comments" rows="4"></textarea>
	</p>
	<p>
	<input name="submit" id="submit" type="submit" value="Submit" />
	</p>
</form>

The next step is to put in place a check to see if the form is submitted, so the script knows to validate. For those that have read part 1 of this series I had used a hidden input to pass this check, I have since done some additional research on the matter and found an alternative more secure method.

if (array_key_exists('submit',$_POST)){
//Form has been submitted
}

This method checks the $_POST array for the key ’submit’, which is the array key for our Submit button, and would only be present if the form was submitted. We will be placing all of our validation related script within this IF statement, ensuring it only runs when required.

Laying Down Array Groundwork

We will need to define the arrays we will be using for this script, one containing all the field names on the form, one with all the mandatory fields, and one to store any errors we come across.

    // Fields that are on form
    $expected = array('name', 'email', 'comments');
    // Set required fields
    $required = array('name', 'comments');
    // Initialize array for errors
    $errors = array();

The $expected array serves to identify and process all  fields, mandatory or not. It also ensures that only the fields you specify are processed and prevents security issues from rogue $_POST values.


Making It Dynamic

The next part is where a big benefit of using arrays comes into play. Instead of typing out IF statements for each $_POST field, we can make use of the foreach statement to do this dynamically.

foreach ($_POST as $field => $value){
	// Make sure field was done correctly otherwise add error.
}

This snippet goes through each key and the corresponding value that the $_POST array holds. This means that each field submitted will be processed, which is especially useful when dealing with long forms.

From within this foreach we now want to do two things to each variable passed through it..
1. Clean up the variable by eliminating whitespace if it is not an array. I used shorthand for this conditional statement:

// Assign to $temp and trim spaces if not array
$temp = is_array($value) ? $value : trim($value);

2. If field is empty then make sure it is not required, otherwise add related error message to the $error array. For those unfamiliar with array_push, it can be used to append additional values into an existing array, in this case the one we defined before:

// If field is empty and required, tag onto $errors array
if (empty($temp) && in_array($field, $required)) {
      array_push($errors, $field);

}

Once these two steps are in place, we have finished the foreach statement.

Handling the Errors

Now that we have the $error array with the names of each required field not filled out, we need to either accept the form or show the error messages.

If the form is done correctly:

if (empty($errors)){
        //The form is completed properly to do with as you please
        unset($errors);
}

The unset(); function destroys the $errors array, so it does not cause incorrect error messages to be displayed.

To display error messages I placed the following lines of code next to the corresponding labels, only appearing when applicable:

<?php if (isset($errors) && in_array('name', $errors)){?>
<div class="red">Please enter name</div>
<?php } ?>

This checks the $errors array for the specified field name , in this case ‘name’, which would only be present if an error happened. The same lines must be placed next to each field you are displaying an error for. I included the error message with my CSS styles applied, they can be found in the complete script at the bottom of this page.

Prevent Inputs from Clearing After an Error

When a user submits the form after completing some of the mandatory fields but not all, they would currently be shown an error message and the form would be cleared. This is a frustrating usability problem that can drive users away. Luckily, now that we have implemented array based validation, it is also easy to fix.

This line of code checks if there are any errors and, if there are, it inserts value = “” containing the user input submitted. This puts the value of the input to whatever the user had it as prior to the error, so they don’t have to retype anything. It is important to enclose this echo statement in literal ‘ ‘ quotes as well as wrap the $_POST[] in htmlentities. To ensure quotes and other symbols inputted do not break your page htmlentities converts some symbols to their HTML equivalent (example:  ” to &quot; ).

<input name="name" id="name" type="text"
    <?php if (isset($errors)) { echo 'value="'.htmlentities($_POST['name']).'"'; } ?>
/>

The above will work for inputs, but the following tweak must be done to accommodate a textarea:

<textarea name="comments" id="comments" rows="4"><?php
	if (isset($errors)) { echo htmlentities($_POST['comments']); }
?></textarea>

It is important to note that in order to avoid white space, make the <?php tags touch the textarea tags.

Completed Tutorial

And that’s all there is to it. Brace yourself for part 3, coming soon, which will outline how to check formats such as email addresses and phone numbers.

  • Stumble It!
  • Bookmark It!
  • Tweet it!

About Sam Dunn

Sam is a designer and co-founder of One Mighty Roar from Massachusetts, USA. He takes particular interest in all things aesthetically pleasing. He can be found online at Vivalasam and Twitter.

 

Discussion

  1. rania

    December 11th, 2008 at 8:38 PM

    nice ..more user friendly ..
    uhm ..if the form is completed ..and i want to link it to another page thus submitting the data to database instead of displaying the green box ..how?

  2. Sam Dunn

    December 11th, 2008 at 9:13 PM

    @rania
    Assuming you have a mysql connection open and database created already you could put the following right above the green box code:
    $sql= “INSERT INTO entry (name, email, comments) VALUES (‘$_POST[name]‘, ‘$_POST[email]‘, ‘$_POST[comments]‘)”;
    mysql_query($sql) or die(‘Error: ‘ . mysql_error());

    Please let me know if that answers your question

    Thanks, Sam

  3. rania

    December 11th, 2008 at 10:44 PM

    im trying wth d code ..another thg ..when will part 3 will be posted?

  4. rania

    December 11th, 2008 at 10:46 PM

    the code is for submitting details to database ..what if i when user click submit and all details are filled. i want to link it to another page

  5. rania

    December 11th, 2008 at 10:54 PM

    do i replace this part ..
    if (empty($errors)){?>
    Thanks for the submission

    $sql= “INSERT INTO entry (name, email, comments) VALUES (’$_POST[name]‘, ‘$_POST[email]‘, ‘$_POST[comments]‘)”;
    mysql_query($sql) or die(’Error: ‘ . mysql_error());
    <?php
    unset($errors);
    }

  6. rania

    December 11th, 2008 at 10:56 PM

    with this code? ..
    if (empty($errors)){?>
    $sql= “INSERT INTO entry (name, email, comments) VALUES (’$_POST[name]‘, ‘$_POST[email]‘, ‘$_POST[comments]‘)”;
    mysql_query($sql) or die(’Error: ‘ . mysql_error());
    <?php
    unset($errors);
    }

  7. Christopher Hill

    December 12th, 2008 at 4:17 AM

    The idea behind this is okay, but the implementation is… lacking.

    #1 if (array_key_exists(’submit’,$_POST)){
    Big no-no. Under certain circumstances the submit button will not be submitted on IE6. Even if it did, array_key_exists() is the wrong function; you want isset().

    What you really want to do is
    if ($_SERVER['REQUEST_METHOD'] == ‘POST’) {

    #2 Not sure why you are using array_push($errors, $field); Using language constructs is far quicker for PHP so just do:
    $errors[] = $field;

    #3 You should really be giving htmlentities() a quote style and a charset, otherwise you can be susceptible to encoding attacks.

    #4 on your reply on December 11th, 2008 at 9:13 pm, your SQL query is not protected against SQL injection.

    Just a heads up.

  8. Matthew Knight

    December 12th, 2008 at 8:36 AM

    Further to Christopher Hill’s points, instead of using

    if ($_SERVER['REQUEST_METHOD'] == ‘POST’) {

    you can do it by including a hidden input in the form – useful if you want to have multiple forms on the same page for instance.

    Our framework uses a similar system to above, but we have a function wrapper to produce all the inputs (text, textarea, checkbox, radio, password, as well as some custom ones such as date, date-time, etc). The advantage of this system is that you don’t need to have lots of logic blocks down your page checking for errors, including existing content, etc – instead it’s all contained within the function and each call might read something like:

    This might, for argument’s sake, produce code such as:

    Please enter your address:
    My Address

    and also include any error messages, existing data, etc. Obviously that’s a simplified example, but you get the general idea…

  9. Matthew Knight

    December 12th, 2008 at 8:38 AM

    It’s wiped all my code….

    PHP:
    echo genInput(“textarea”,”Address”,”Please enter your address:”,$existingAddressFromDatabase,array(10,40));

    HTML: (swap {} for normal angle brackets)

    {label for=”Address”}Please enter your address:{/label}
    {textarea rows=”10″ cols=”40″ name=”Address” id=”Address”}My Address{/textarea}

  10. Sam Dunn

    December 12th, 2008 at 9:14 AM

    @rania
    I would encourage you to look into the header(); function of PHP

    @Christopher Hill
    #1 isset() will return false for arrays keys that have their value set to NULL, which can be inaccurate, while array_key_exists would return true. I would be interested to see some information regarding the IE6 problems, as I have never come across any. Also, thank you for the alternative.

    #2 You caught me, this is a stripped down version of my validation script that makes use of array_push, which seems to have slipped through the cracks, I’ll have to make that adjustment thank you.

    #3 For this script, the default quote style and charset both work for what I’m trying to do, ISO ISO-8859-1 and ENT_COMPAT.

    #4 @rania too, the purpose of that post was to show where a potential SQL query could go, nothing else. It is not secure and you should apply your own methods of protection to make it so.

    I plan on making a part to this series regarding form security, this tutorial was just laying down the groundwork for doing so.

    @Matthew Knight
    In part one of this series I made use of the hidden input on the form, but due to some very opinionated comments I decided to show an alternate method this time around.

    Your form generation technique is very interesting and is something I plan on exploring, thanks for showing me.

  11. Christopher Hill

    December 14th, 2008 at 7:48 AM

    @Sam Dunn
    #1 I’m not sure why a submit button would have a value of NULL, though. And feel free to test out the IE6 bug out on my test page: http://www.chrisjhill.co.uk/lab/ie6_no_submit_button/

  12. Sam Dunn

    December 14th, 2008 at 12:24 PM

    @Christopher Hill
    Thanks for that, interesting bug. I’ll take that into account for 1 input forms.

  13. Matt

    January 8th, 2009 at 10:07 AM

    I think this way of error processing is nice, but can you show me why your code is more sufficient than this:

    function print_errors($e)
    {
    // print out the errors in an un-ordered list.
    ?>
    Errors

    Sorry, an error has occured. This could be due to lack of required input, or a typo.
    The error(s) returned:

    <?php echo implode(”, $e);?>

    <?php
    }

    // if there were any errors with processing
    if( $_errors )
    {
    // print the errors
    print_errors($_errors);
    }

    if ($field['name'] == “NULL”) $errors[] = “missed some data”;

    Is your way more efficient, and does it have more flexibility?
    If so then I’m switching to your way, so write back.

  14. Sam Dunn

    January 8th, 2009 at 11:33 AM

    @Matt
    There are a few benefits of the way I outline above, that I don’t see offhand built into your way.
    1. The ability to specify mandatory fields versus optional.
    2. Because my method stores errors in an array by field name, rather than error message, you would be able to keep user input from clearing upon an error. You would also be able to display errors beside the related field.
    3. Your print_errors array seems like an redundant function, you don’t need a function to display errors onscreen.

  15. Darin Boyd / Braingerous

    January 9th, 2009 at 5:19 PM

    I like your site. You’ve done a good job of showing a basic validation technique for a web form. Your presentation looked very nice also.

    Validation is notoriously cumbersome. It is also a fairly repetitive task. These are scenarios where objects designed to handle these tasks would reduce a lot of the boiler plate work and separate those concerns from the form code.

    I come from a .Net background where we have frameworks like Enterprise Library and CSLA. I’m doing some PHP these days, so I still haven’t gotten to grips with best practices in the community. I began coding my own validation framework as a discussion on my blog, but recently also discovered a framework called Kohana. Have you tried anything like that?

  16. Zac

    January 22nd, 2009 at 5:10 PM

    One problem I found with this validation process is that is doesn’t handle check boxes or radio buttons very well. Check box and radio button values are only added to the $_POST array when checked/selected. So, the foreach statement around line 64 will ignore required check boxes/radio buttons if they aren’t checked.

  17. Adham

    February 6th, 2009 at 1:54 AM

    nice tutorial
    but what is the benefit of the following :-
    $temp = is_array($value) ? $value : trim($value);
    the question is can $value be an array ?
    $value have to be posted by the user how can it be an array ?

  18. MikeW

    February 7th, 2009 at 5:41 AM

    I’m totally new to php so all this conversation is very interesting. However, I have a very basic question (I think). When I use your technique of validation:

    <input name=”name” id=”name” type=”text”

    />

    the Expressions Web tool tells me that in XHTML 1.0 Strict the attribute above is not permitted for the tag. I’ve been unable to get the technique to work. I must be making a rookie mistake. Does the technique have to use imbedded php or can the checking be done in an external .php file?

  19. JacksonL

    February 22nd, 2009 at 5:29 AM

    Hi,
    I’m also fairly new to PHP, I’ve been searching around the internet for a tutorial exactly like this. Can i personally thank you, as this has helped me out alot. But i have two questions, one is how would i send this data in a email to myself? And second, instead of Thanks for the submission is their a way to make it go to a thankyou page?

    Thanks,
    Jackson – New Zealand

  20. Sam Parkinson

    February 22nd, 2009 at 5:09 PM

    Thanks man, I was having a few problems returning errors to the users and keeping the form data. Problem solved now, although I didn’t use that loop, not the most secure way of checking a forms validity (admittedly its a lots less typing that an if statement for each form input though :P ).

  21. Chris Benton

    February 26th, 2009 at 1:09 PM

    This is a great script. Helped me out immensely. Is it possible to modify it to cover checkboxes, lists, and radio buttons? I have a checkbox field listed in my “required” array, but the script doesn’t seem to notice it.

  22. kofi peprah

    March 2nd, 2009 at 4:56 AM

    I’m still working around my website when it is published i’ll let you know.

    Your code has really helped me, thanks so much. I have therefore decided to create a link to this site on my mine.

  23. Chris

    May 19th, 2009 at 12:29 PM

    How would this work with check boxes and lists?

  24. Jore

    May 21st, 2009 at 9:48 AM

    Hi…
    I really liked this application… but, how do i have to do to select values from a “dropdown form” and validate them aswell?

    thanks!

  25. Vladimir

    September 16th, 2009 at 11:40 PM

    Super.. Nice.. Very nice scripts.. Thanks :) This site the best! Agian thanks.

  26. Vladimir

    September 18th, 2009 at 2:28 AM

    Please add capcha with image or text from bots.. thanks :)
    or help from how add the capcha for this script :)
    My email you see.

  27. Sinan

    December 19th, 2009 at 11:47 PM

    @Adham

    Because you can, like this:

    then when the form is submitted, $_POST['options'] will be already an array ;) . Let the fun begin

  28. Sinan

    December 19th, 2009 at 11:49 PM

    OPS ! my code is gone :)
    @Adham

    Because you can, like this:

    input name=”options[]” type=”text”

    then when the form is submitted, $_POST['options'] will be already an array ;) . Let the fun begin

Join the Conversation!

Remember: Life's not all doom and gloom, so please keep it constructive. If we've made an error or missed something big, please let us know! Learning is revisions, after all.

CommentLuv is Enabled

 

Sponsors

Advertise on Build Internet!