PHP DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Autofilled PHP Forms

by Gavin Andresen
03/16/2006

I hate typing, but I like writing code. A while ago I started to dread all the rote typing required to handle forms in PHP, and began looking for a Better Way. This article describes how I used PHP's regular expression functions to do most of the heavy lifting required to process forms properly, saving lots of typing and giving me time to do stuff I don't hate, such as writing code (and playing NetHack).

The Problem

Jeff Cogswell described the general problem in his article User-Friendly Form Validation with PHP and CSS: you have to display the form, validate the input, and then either display some sort of thank-you page or, if validation fails, redisplay the form with any errors shown along with the values that the user entered. Because I generally code forms for clients who are paying lots of money for a snazzy-looking web site, the forms also have to look nice and match the appearance of the rest of the site.

The Tedious Typing Solution

The most straightforward way to solve the problem is to create a nice-looking form in your favorite WYSIWYG HTML editor and then insert bits of PHP code to display form values and error messages in all the right spots. For example, if the form has a required field named "email," I use PHP code like this to validate it:

$validationData          = array();
$validationData['email'] =
  array('isRequired', type='emailAddress');

$formErrors = validateForm($_POST, $validationData)

That's not too bad--I can write the validateForm() function once and use it over and over again, extending it whenever I need to deal with another type of value.

Redisplaying the form with errors and correct values is where things get messy. Some simple HTML like:

<td align="right">Email:</td>
<td><input name="email" value="" /></td>

becomes a maze of HTML and PHP:

<td align="right"
<?php if (isset($formErrors['email'])) {
          echo 'class="error"';
      } ?> >
Email:</td>
<td><input name="email"
<?php if (isset($_POST['email'])) {
          echo 'value="'.$_POST['email'].'"';
      } ?> /></td>

Repeating that for every field in the form is annoying. Repeating it for every <option> value in a 50-value Select Your State drop-down list is almost painful enough to make me give up coding and become a plumber.

The Problem, Restated

Start with an HTML form containing no PHP code. You have PHP arrays containing the values that should be shown and any form validation errors. You want a PHP function that takes the arrays and HTML, and returns the HTML modified a little bit so it shows all the right stuff--give it <input name="email"> and $_POST['email'] = "gavin@mailinator.com", and it should return <input name="email" value="gavin@mailinator.com">. After searching the PHP manual and the Web, I couldn't find a function that did that, so I wrote it myself and called it fillInFormValues().

fillInFormValues Details

fillInFormValues takes three arguments: fillInFormValues($html, $values, $errors)

  1. $html contains the HTML markup (in a PHP string) for the form. fillInFormValues isn't fussy about the HTML you pass in; it will handle HTML3, HTML4, or XHTML, and it doesn't care if you pass in an entire page's worth of HTML or just HTML fragments containing form input fields. fillInFormValues does require that you pass in valid HTML; it isn't as forgiving as some web browsers, so don't pass in HTML with missing </textarea> tags.
  2. $values is a PHP array containing the values that the form should show, where $values['fieldName'] = fieldValue. If you're redisplaying the form after a form validation error, you can just pass in $_POST or $_GET or $_REQUEST.
  3. $errors is a PHP array containing validation errors, where $errors['fieldName'] = "error message". fillInFormValues looks for a <ul class="error"></ul> element in the HTML and inserts the error message into it. Use HTML <label> tags to mark up your form text:

    <label for="address">Street Address:</label>
    <input name="address" id="address" />

    If $errors['address'] is set, fillInFormValues will add class="error" to the corresponding <label>. Defining a simple CSS rule like label.error: color: red; will then make erroneous input bright red. Using <label> tags also makes your forms more accessible to people using screen readers or other accessibility aids and also tells the web browser to put the cursor in the address field if the user clicks on the Street Address text, making the form easier to use for everybody. Note that labels match to input fields using the id attribute, not the name element (though I always give my forms the same name and ID so I don't confuse myself).

fillInFormValues returns a string that is $html modified as little as possible to display the $values and $errors. If you pass in empty arrays, it returns $html unchanged, which makes it easier to display the form the first time. Here's a complete working example:

<?php
ob_start();
?>
<html>
<head>
<title>fillInFormValues: short example</title>
<style>
.error { color: red; }
</style>
</head>
<body>
<h1>Sign up for our newsletters</h1>
<ul class="error"><li>PLACEHOLDER FOR FORM ERRORS</li></ul>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="GET">
<table border="0">
<tr>
 <td><label for="email">Your Email Address:</label></td>
 <td><input type="text" name="email" id="email"></td>
</tr>
<tr>
 <td><label for="newsletter">Sign up for these newsletters:</label></td>
 <td>
 <input type="checkbox" name="news" id="news">
  <label for="news">News</label><br />
 <input type="checkbox" name="security" id="security">
  <label for="security">Security Notices</label><br />
 <input type="checkbox" name="specials" id="specials">
  <label for="specials">Specials</label>
 </td>
</tr>
<tr><td> </td>
 <td><input type="submit" name="submit" value="Sign Up"></td>
</tr>
</table>
</form>
</body>
</html>

<?php
$html = ob_get_contents();
ob_end_clean();

require_once("fillInFormValues.php");
require_once("validateForm.php");

$request = (get_magic_quotes_gpc() ?
             array_map('stripslashes', $_REQUEST), $_REQUEST);

$validationData['email'] = array('isRequired', 'type' => 'email');
if (isset($request['submit'])) {
  $formErrors = validateForm($request, $validationData);
  if (count($formErrors) == 0) {
    // Normally there would be code here to process the form
    // and redirect to a thank you page...
    // ... but for this example, we just always re-display the form.
    $info = "No errors; got these values:".
      nl2br(htmlspecialchars(print_r($request, 1)));
    $html = preg_replace('/<body>/', "<body><p>$info</p>", $html);
  }
}
else {
  $formErrors = array();
}

echo fillInFormValues($html, $request, $formErrors);

?>

I used the PHP output buffering routines (ob_start/ob_get_contents/ob_end_clean) to get the page's HTML into a PHP string to then pass to fillInFormValues. Besides filling in the $validationData array, this same PHP code will work for any form, even the great big ugly ones on your insurance company's web site.

Pages: 1, 2, 3

Next Pagearrow




Valuable Online Certification Training

Online Certification for Your Career
Earn a Certificate for Professional Development from the University of Illinois Office of Continuing Education upon completion of each online certificate program.

PHP/SQL Programming Certificate — The PHP/SQL Programming Certificate series is comprised of four courses covering beginning to advanced PHP programming, beginning to advanced database programming using the SQL language, database theory, and integrated Web 2.0 programming using PHP and SQL on the Unix/Linux mySQL platform.

Enroll today!


Sponsored by: