This article addresses some of the missing items from the simple form introduced in Part I. The reader is assumed to have read Part I and a basic knowledge of PHP.
I did a bad thing when I created the form in Part I; I used a global variable to share information between the ShowForm() and ValidateForm() functions. If you're an experienced programmer, then I've probably lost some credibility with you. If you're new to programming, then you're probably wondering what's so bad about global variables; after all most of the code you've written so far is full of them, right? You'll just have to take this on faith, but global variables are worse than brain-eating zombies and the flesh-eating virus combined. If you can't take it on faith, then use your favorite search engine to perform some research on the topic; I'm sure it's out there.
In order to eliminate the global variable $errors, I'm going to perform a little code shuffling:
Try the form or view the full source.
If you aren't aware what is meant by the phrase “duplicate submissions,” then you need to perform a little experiment using the existing form. Go ahead and submit the form and then refresh the web page; your browser should warn you about sending post data.
Browser warnings for sending post data:
If a user happens to refresh a page that was the result of a form submission, the browser will resubmit the form. These messages are disruptive and can be confusing to the average user. In addition, whatever your form does as the ProcessForm() step will be repeated for each submission; this means a user could place duplicate and unwanted orders at an e-commerce site. You certainly do not want that to happen.
To prevent this from happening, you simply redirect the user with a call to header(). Be warned that all post data will be lost when you perform the redirect; in order to access the post data on the landing page, you will need to preserve it in persistent storage, such as a session.
Please note the following method relies on your ProcessForm() method being able to finish executing before the user has a chance to refresh their browser. If you are running a busy e-commerce site you will need to expand upon this solution to eliminate accidental submission of duplicate orders.
For most intents and purposes, it is sufficient to redirect as the final step of the ProcessForm() function. This behavior can be added to our existing form with a couple minor changes:
Also, since the script is now using sessions, you must remember to call session_start() at the top of the script.
Go ahead and try the form again. This time when the form reaches the processing page, refresh the browser; instead of the warning about post data you will see the empty form.
If you haven't done so already, try submitting our form with an empty name field. You will see two error messages:
While sometimes this behavior is preferable, in most cases it makes sense to display a single error per field. This change can be accomplished with a very minor code change to ValidateForm():
Technically, the only requirement to accomplish this was to assign both error messages to the same index in the $errors array. However, since the conditions are trivial I combined the if-statements into a single code block as well.
Test the form again and confirm that this works.
In order to retrieve post values without receiving 'index undefined' errors, I use the following code in ShowForm();
$name = isset($_POST['name']) ? $_POST['name'] : '';
This is fine for small forms with only a few fields. However as you create many forms or large forms with many fields, you will find that you type this code quite frequently. Should you later decide to grab values from $_POST in a different manner, you will have lots of code to update! I therefore recommend wrapping up this functionality in a small function:
function GetPostValue( $index ) {
return isset($_POST[$index]) ? $_POST[$index] : '';
}
You can then call this function in ShowForm() and ValidateForm() using:
$name = GetPostValue( 'name' );
Variable variables are best explained with a small code example:
<?php
$name = 'Steve'; // Creates $name
${'foo'} = 'bar'; // Creates $foo
${'as' . 'df'} = 42; // Creates $asdf
${$foo} = 'Hello, World!'; // Creates $bar
?>
Essentially you can create variables whose name depends on an expression evaluated at run time. This can come in handy while creating a form because we often create variables named after the form fields. Combined with the GetPostValue() function above, you could easily create defaults for all of your form fields:
<?php
$fields = array( 'name', 'addr', 'city', 'state', 'zip' );
foreach($fields as $field){
${$field} = GetPostValue($field);
}
// Creates $name, $addr, $city, $state, $zip and each
// is populated by $_POST['name'], $_POST['addr'],
// $_POST['city'], $_POST['state'], and $_POST['zip']
// (or an empty string if $_POST is empty)
?>
Variable variables are convenient but should be used sparingly and only when it makes sense. Your IDE will not be able to detect variable variables and if you're not careful you may accidentally overwrite existing variables.
Magic Quotes is one of those things that sounds great in theory but is undesirable in practice. Magic Quotes will automatically escape incoming data, which is to say:
That's Steve's!
will be escaped to:
That\'s Steve\'s!
I will not go into any great detail as to the purpose behind Magic Quotes, but I will say the following:
Between this article and Part I, most readers should have a fundamental understanding of how to develop web forms. I've purposefully ignored the finer details of form handling, such as the different types of inputs or advanced validation techniques; I will cover those topics in the near future. However, you should feel confident that you could research those topics and use what you discover in the groundwork I've provided thus far.
Comments
Hi
Just want to thank you for very informative post, regards Ed
Nice snippets for form processing
Nice snippets for form processing.
Saved me a heap of time!
Works like a charm!
Post new comment