Quick and Clean PHP Based Form Handling.
Introduction
As its name suggests, the PHP Extension and Application Repository (PEAR) library, HTML_QuickForm, allows you to quickly and cleanly produce validating HTML forms. In this tutorial, I will walk through a basic implementation of HTML_QuickForm to produce a common contact form and explore ways to get the most out of this library.
When is it appropriate to use HTML_QuickForm?
You may have inherited a legacy Web site that is entirely or mostly static that needs to have forms added to it, or you may want to build a dynamic site with a handful of forms that need to be processed flexibly. Maybe you are just mocking up some screens and want a quick way to make those screens operational. The wide availability of PHP and its low barrier of entry make it an ideal environment for adding dynamic functionality to sites that may be largely static otherwise, and libraries like HTML_QuickForm can make adding this functionality even easier.
Or maybe you are building a Web application in an established PHP framework but need to add form functionality that doesn’t fit well with the flow and design of the rest of the application. Or maybe because of your development philosophy, personal disposition, or level of experience you are skeptical of structured Web frameworks. You want to program the site yourself, your way, but you are open to taking advantage of third party libraries for solving specific challenges.
In any of these cases, the PEAR libraries offer standard and robust tools that can make PHP development easier, and the HTML_QuickForm library is a powerful example of such a tool. In a relatively small block of pure PHP code, you can create robust validating forms and plug in your own code for processing valid form submissions.
A contact form is a classic example of a form that gets tacked onto both static sites and complete Web applications alike. In the following section, I will implement a self-contained, pure PHP script that will display, validate and process a contact form, ultimately formatting the submitted data as an email message and sending it.
And it may be just as important to consider when not to use HTML_QuickForm. If you are developing a complex Web application that is heavily form driven, particularly if, like many Web applications, it is performing CRUD operations on your database, then you really should invest in learning a Web framework. In that case, I would recommend looking at CakePHP, which is a developer friendly PHP framework inspired by Ruby on Rails.
Implementing a contact form with HTML_QuickForm
Keith Edmunds wrote a very nice tutorial called “Getting Started with PHP’s HTML_QuickForm” that I will use as a jumping off point. In particular, I will start with his example code from the article which provides great examples of how to use HTML_QuickForm.
As you can see by this Keith’s code and its description, like any good library, HTML_QuickForm provides us with a convenient way of performing a well defined task, in this case authoring and validating forms. But as we integrate these libraries in our own code and do so with our own programming style, we typically want to start to use libraries at a higher level, more idiosyncratic way. In my case, I wanted to factor out as much duplicate code as possible to simplify HTML_QuickForm even further for how I planned to use it.
To begin, I decided that often, and perhaps always, I could write the name of a field in a conventional way such that it could be used to programatically generate a human friendly form label when displaying the form. I could also reuse this approach to format the field name for the email message in the same way. So, I decided that I would take a typical approach of naming fields in complete words, separated by underscores and then create a function that would replace the underscores with spaces and convert the resulting string to title case:
// replaces underscores with spaces and capitalizes words of field names
function createFieldLabel($field_name) {
return ucwords(ereg_replace('[_]', ' ', $field_name));
}
You have probably seen frameworks that do something similar; generating labels this way is not a terribly new idea.
I then wanted an even simpler way to specify the form elements, so I decided to populate a simple multi-dimensional array and then loop over that array to generate the form elements, thereby only coding the addElement() method once:
// create an array of form field names => form element type pairs
$fields = array(
array( 'name' => 'text' ),
array( 'address' => 'text' ),
array( 'email_address' => 'text' ),
array( 'home_phone' => 'text' ),
array( 'cell_phone' => 'text' ),
array( 'subject' => 'text' ),
array( 'message' => 'textarea' ),
array( 'submit' => 'submit' ),
);
foreach ($fields as $key=>$value) {
$form->addElement($value, $key, createFieldLabel($key));
}
OK, that may not have been an earth shattering optimization, but it eventually led in a fruitful direction. This approach was nice as far as it goes, but it didn’t account for the field validations, and when I tried to add these to the same basic multi-dimensional array approach, it began to break down quickly:
$fields = array( 'name' => array( 'field_type' => 'text',
'validation_method' => 'required',
'validation_message' => 'Please enter your name.',
),
...
);
The array syntax was getting unwieldy and the need to have known array keys like ‘field_type’ was fragile. A better way is do a real refactoring and wrap both addElement() and addRule() calls in methods that make the parameters explicit:
function addRule($form, $field_name, $validation_method, $validation_message) {
global $default_messages; // this seemed appropriate
if ($validation_method != '') {
if ($validation_message == '') {
$validation_message = sprintf($default_messages[$validation_method], ereg_replace('[_]', ' ', $field_name));
}
$form->addRule($field_name, $validation_message, $validation_method);
}
}
function createFormElement($form, $field_name, $field_type, $validation_method=", $validation_message=") {
$form->addElement($field_type, $field_name, createFieldLabel($field_name));
addRule($form, $field_name, $validation_method, $validation_message);
}
This approach also allowed me to order the form parameters in a way that is more intuitive to me than the order dictacted by the HTML_QuickForm API. This is still a pretty bare bones approach, and we could make it more robust by doing such things as verifying the availability of the validation method at the time its specified, and hooking into HTML_QuickForm’s ability to easily specify default field values. I did take the step of being able to specify default validation messages for the known validation methods, like ‘required’ and ‘email’ so that if no validation message is explicitly specified, an informative message that also takes advantage of the form field naming convention will be used automatically instead. Or to put it another way, the default messages are used unless explicitly overridden in the method call. The following are the default messages that I used in my form; they are then processed by the sprintf() function above:
$default_messages = array ('required' => 'Please enter your %s.',
'email' => 'Please enter a valid %s.'
);
Using these default messages, I avoid some duplication in specifying these messages and ensure that they are rendered consisently and further reuse my $field_name naming convention. In the final version of the contact form, I give examples of the default messages being used as well as an example of the default messages being overridden.
Ultimately, a file called HTML_QuickerForm.php contains all my reusable code to wrap the QuickForm library functionality and implement my own higher level methods for using HTML_QuickForms. It became clear that what I should really be doing is adding this functionality by subclassing HTML_QuickForm, which made the code that calls these methods cleaner still:
<?php
require_once('HTML/QuickForm.php');
class HTML_QuickerForm extends HTML_QuickForm {
function addDefaultMessages($default_messages) {
$this->default_messages = $default_messages;
}
// replaces underscores with spaces and capitalizes words of field names
function createFieldLabel($field_name) {
return ucwords(ereg_replace('[_]', ' ', $field_name));
}
function addRule2($field_name, $validation_methods, $validation_message) {
if ($validation_methods != ") {
$methods = split(',', $validation_methods);
foreach ($methods as $method) {
if ($validation_message == ") {
$validation_message = sprintf($this->default_messages[$method], ereg_replace('[_]', ' ', $field_name));
}
$this->addRule($field_name, $validation_message, $method);
}
}
}
function createFormElement($field_name, $field_type, $validation_methods=", $validation_message=") {
$this->addElement($field_type, $field_name, $this->createFieldLabel($field_name));
$this->addRule2($field_name, $validation_methods, $validation_message);
}
function executeForm() {
if ($this->validate()) {
# If the form validates, freeze and process the data
$this->freeze();
$this->process("process_data", false);
} else {
$this->display();
}
}
}
function createForm() {
$form = new HTML_QuickerForm('form', 'post');
$form->applyFilter('__ALL__', 'trim');
return $form;
}
?>
These methods can now be reused across multiple forms to make the HTML_QuickForms library even more convenient to use. Now, my contact_form.php looks like this:
<?php
require_once('HTML_QuickerForm.php');
$default_messages = array ('required' => 'Please enter your %s.',
'email' => 'Please enter a valid %s.'
);
$form = createForm();
$form->addDefaultMessages($default_messages);
$form->createFormElement('name', 'text', 'required', 'Hey! Enter your name!');
$form->createFormElement('address', 'text' );
$form->createFormElement('email_address', 'text', 'required,email');
$form->createFormElement('home_phone', 'text', 'required' );
$form->createFormElement('cell_phone', 'text' );
$form->createFormElement('subject', 'text' );
$form->createFormElement('message', 'textarea');
$form->createFormElement('submit', 'submit' );
$form->executeForm();
// For a validated form submission, email it.
// The various strings in this method should be specified outside this method,
// in a configuration mechanism.
function process_data ($values) {
global $form;
$email_message = '';
foreach ($values as $key=>$value) {
if ($key != 'submit') {
$email_message .= $form->createFieldLabel($key) . "\\\\r\\\\n";
if ($value == '') {
$value = '(nothing entered)';
}
$email_message .= $value . "\\\\r\\\\n\\\\r\\\\n";
}
}
$to='your_address@your_domain.com';
$subject = $values['subject'];
$success = mail($to, $subject, $email_message);
echo "Thank you, your message has been sent.";
}
?>
As you can see, the actual form functionality is pretty simple and clean now, and in this script, I only coded what is specific to the implementation of this particular contact form. The most involved piece of coding is actually the process_data function that emails the form data, although even there, I was able to reuse the createFieldLabel() method to consistently display user friendly field names in the email message just as I did in the HTML form. Notice that the new HTML_QuickerForm class now expects this method to be named “process_data” by convention. Also note that I added the ability to specify multiple validation methods as a comma delimited string.
There’s alot more to the HTML_QuickForm library than what I have implemented so far, and as you use more advanced features of the library, no doubt the approach that I have started here will evolve. Complete documentation can be found here, including this list of features from the opening HTML_QuickForm page on the PEAR site:
- More than 20 ready-to-use form elements.
- XHTML compliant generated code.
- Numerous mixable and extendable validation rules.
- Automatic server-side validation and filtering.
- On request javascript code generation for client-side validation.
- File uploads support.
- Total customization of form rendering.
- Support for external template engines (ITX, Sigma, Flexy, Smarty).
- Pluggable elements, rules and renderers extensions.
Additionally, there are links on this page to other PEAR packages that integrate with and extend the functionality of HTML_QuickForm in various ways including the creation of CAPTCHA elements, database integration, and the creation of multipage forms. In other words, its unlikely that using HTML_QuickForm will limit you in any way as your forms evolve into the future.
Deployment
HTML_QuickForm requires PHP4, the HTML_Common PEAR library and the PEAR base system.
When I do freelance work, I often don’t have detailed knowledge of the environment my code will ultimately be deployed on or how that environment will be configured. For example, I will know that a client is running Apache2 and PHP4, but I may not know if they have the appropriate PEAR libraries installed and on the include path. And if the code doesn’t work, I look bad, no matter the reason. So, I often bundle these PEAR libraries right alongside the scripts that use them so I can guarantee that all the dependencies will be met.
If you go to the HTML_QuickForm area of the PEAR site, you will see that it has been supersceded by HTML_QuickForm2, and you are urged to use that version. But if like many people, you are deploying onto a PHP 4.x installation, note that HTML_QuickForm2 requires PHP 5. And as the original HTML_QuickForm is still being maintained with bug fixes and security updates, this is likely to be the version you will want to use. HTML_QuickForm2 was originally just a rewrite of HTML_QuickForm to make it work with the PHP5 E_STRICT setting, so the HTML_QuickForm documentation and examples should also be applicable to HTML_QuickForm2 with minimal changes. New functionality is also being added to HTML_QuickForm2, but these features are not openly documented yet, so you can expect to read code to take advantage of any new features.
Conclusion
I hope this has introduced you to some of HTML_QuickForm’s features and given you ideas for how to incorporate it into your code. The library can be learned quickly, allowing you to start producing working forms in minutes. HTML_QuickForm admirably hides the tedious complexity of building HTML forms while remaining very flexible and extendable.
UPDATE
An updated version of this post is available on Onlamp.

I tried biulding one of these myself, it works good if you keep it fuctional rather that OOPing it.
Hello
Very interesting information! Thanks!
G’night
[...] a previous post, I talked about how to get the most out of the HTML_QuickForm PEAR library. I then did an improved [...]