PHP Form Handling
by David
Sklar,author of
Learning
PHP 5
08/26/2004
If your PHP program is a dynamic web page (and it probably is) and your PHP program is dealing with user input (and it probably is), then you need to work with HTML forms. Here are some tips for simplifying, securing, and organizing your form-handling PHP code.
$_SERVER['PHP_SELF']
as a form action.The $_SERVER
auto-global array holds various useful
server- and request-specific info. The PHP_SELF
element
of $_SERVER
holds the filename of the currently
executing script (relative to your web site's document root
directory). So, supplying $_SERVER['PHP_SELF']
as the
action
attribute of the form tag makes the form submit
to the same page that displayed it. This lets you put the logic to
handle the form in the same page as the logic that displays it. For
many simple forms, this keeps things easy to manage.
[]
at the end of the name of a multivalued
form parameter.When you've got a form element like <select multiple>
that can submit multiple values to the server, put []
at
the end of the form element name so that the PHP interpreter knows to
accept multiple values.
For example, consider this form:
<form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>"> Pick some desserts: <select name="sweet[]" multiple> <option value="puff"> Sesame Seed Puff</option> <option value="square"> Coconut Milk Gelatin Square</option> <option value="cake"> Brown Sugar Cake</option> <option value="ricemeat"> Sweet Rice and Meat</option> </select> <input type="submit" name="Order"> </form>
If you pick Sesame Seed Puff
and Brown Sugar Cake
and submit the form, then $_POST['sweet']
is itself an
array. $_POST['sweet'][0]
is puff
and
$_POST['sweet'][1]
is cake
. That's because
the name
attribute of the <select>
element is sweet[]
. If the name was just sweet
,
then $_POST['sweet']
would be a string, holding only one
of the selected values.
Include a hidden variable named, say, _submit_check
in your forms like this:
<input type="hidden" name="_submit_check" value="1"/>
Then, to test whether the form has been submitted, look for the
_submit_check
element in $_POST
:
if (array_key_exists('_submit_check', $_POST)) { /* ... do something with the form parameters ... */ }
Testing for the presence of a hidden element avoids problems that can result from browsers' varying behaviors when a user submits a form by pressing the Enter key instead of clicking a submit button.
Logically, the life cycle of a web form usually comprises three steps: showing the form, validating the submitted form parameters, and then processing the submitted form parameters to generate appropriate output.
Dedicate a function to each of these steps: showing, validating, and processing. With this modular design, deciding when each step needs to happen is straightforward.
On many pages, the logical flow goes like this:
If the request isn't a form submission, show the form.
If the request is a form submission, validate the submitted parameters.
If the submitted parameters are valid, process them.
If the submitted parameters are invalid, show the form.
With a function-based structure, the code to accomplish this looks something like:
if (array_key_exists('_submit_check',$_POST)) { // If validate_form() returns errors, pass them to show_form() if ($form_errors = validate_form()) { show_form($form_errors); } else { // The submitted data is valid, so process it process_form(); } } else { // The form wasn't submitted, so display show_form(); }
The page either displays the form (possibly with error messages) or displays the results of processing the form.
On other pages, particularly search pages, the logical flow goes like this instead:
If the request is a form submission, validate the submitted parameters.
Display the form.
If the request is a form submission, process the submitted parameters.
With a function-based structure, the code to accomplish this looks something like:
// Check for errors if the form was submitted $form_errors = array_key_exists('_submit_check',$_POST) ? validate_form() : null; // Always display the form show_form($form_errors); // Display results if the form was submitted if (array_key_exists('_submit_check', $_POST)) { process_form(); }
Displaying the form above the processing output is useful for pages where users might want to adjust the form parameters based on the results. For example, if a product search for toasters that cost between $150 and $300 reveals only two choices, a user can adjust the price range and resubmit the form for a new search without going to a separate page.
strval()
and intval()
or floatval()
.Usually, the ability to switch a variable smoothly between holding
a string or a number is a great convenience in your PHP programs.
However, that makes form validation a little harder. To check whether
a submitted form parameter is a valid integer, use strval()
and intval()
together like this:
if ($_POST['age'] != strval(intval($_POST['age'])) { $errors[] = 'Please enter a valid age.'; }
If $_POST['age']
isn't an integer, then intval()
changes its value to something else. Adding strval()
to
the mix ensures that the comparison using the !=
operator doesn't do any silent, behind-the-scenes conversion.
Similarly, to check whether a submitted form parameter is a valid
floating-point number, use floatval()
instead of
intval()
:
if ($_POST['price'] != strval(floatval($_POST['price']))) { $errors[] = 'Please enter a valid price.'; }
Printing data that comes from an external source (like form input) without properly encoding it leaves you vulnerable to the common, devastating, and embarrassing "cross-site scripting attack."
Pass external data through htmlentities()
before
printing it, like this:
print "Your monkey's name is: " . htmlentities($_POST['monkey_name']);
Read more about cross-site scripting at http://www.owasp.org/documentation/topten/a4.html.
Printing out appropriate HTML for individual form elements is boring and repetitive. Fortunately, computers are quite good at boring and repetitive tasks. Encapsulate logic for printing HTML form elements in functions. Then, call those functions whenever you need to print a form element. Chapter 6 of Learning PHP 5 includes functions for a number of form elements. Here are a few samples:
// print a single-line text box function input_text($element_name, $values) { print '<input type="text" name="' . $element_name .'" value="'; print htmlentities($values[$element_name]) . '">'; } //print a textarea function input_textarea($element_name, $values) { print '<textarea name="' . $element_name .'">'; print htmlentities($values[$element_name]) . '</textarea>'; } //print a radio button or checkbox function input_radiocheck($type, $element_name, $values, $element_value) { print '<input type="' . $type . '" name="' . $element_name .'" value="' . $element_value . '" '; if ($element_value == $values[$element_name]) { print ' checked="checked"'; } print '/>'; } //print a submit button function input_submit($element_name, $label) { print '<input type="submit" name="' . $element_name .'" value="'; print htmlentities($label) .'"/>'; }
These functions are called like this:
print '<form method="POST" action=" . $_SERVER['PHP_SELF'] . '">'; print 'Name: '; input_text('name', $_POST); print '<br/>'; print 'Description: '; input_textarea('description', $_POST); print '<br/>'; print 'Advanced?'; input_radiocheck('check','editor', $_POST, 'yes'); print '<br/>'; print 'Size: Big '; input_radiocheck('radio','size', $_POST, 'big'); print ' Small '; input_radiocheck('radio','size', $_POST, 'small'); print '<br/>'; input_submit('submit', 'Save');
The functions are easily extendable to add your own layout or support for arbitrary attributes for each element.
For more advanced form handling, check out the PEAR module HTML_QuickForm. It provides methods for the flexible and structured creation, validation, and display of HTML forms. HTML_QuickForm frees you from doing the grunt work of displaying defaults for form elements, encoding HTML entities, and duplicating validation code. Its built-in layout engine is customizable, and you can integrate with template engines like Smarty.
David Sklar is an independent consultant in New York City, the author of O'Reilly's Learning PHP 5, and a coauthor of PHP Cookbook.
In June 2004, O'Reilly Media, Inc., released Learning PHP 5.
Sample Chapter 8, "Remembering Users with Cookies and Sessions," is available free online.
You can also look at the Table of Contents, the Index, and the full description of the book.
For more information, or to order the book, click here.
Return to the PHP DevCenter
Copyright © 2005 O'Reilly Media, Inc.