PHP Form Handling

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.

1. Use $_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.

2. Put [] 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.

3. Test for form submission with a hidden element.

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_checkelement 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.

4. Divide your form handling into three parts: showing, validating, and processing.

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.

5. Validate numbers with 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.';
}
6. Entity-escape form data before printing it.

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 athttp://www.owasp.org/documentation/topten/a4.html.

7. Print form elements’ defaults with helper functions.

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.

8. Investigate HTML_QuickForm for advanced form processing.

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.

 

http://onlamp.com/pub/a/php/2004/08/26/PHPformhandling.html

Leave a comment