Did you get or post me?

Extracting form variables when programming in Perl is a real task. The variables can be extracted fairly painlessly using the CGI.pm modules, but there is a lot of work going on under the hood. In PHP form variables just spring to life. If a form has an input statement

<input type="text" name="FirstName">

we can just simply use $FirstName in our script. However, this wonderful shortcut is of no value if we don't know the contents of the name clauses from the submitted form. In a generalized form handler, we must deal with $FirstName even though we don't know the name of the variable.

Fortunately, PHP has an associative array containing all the name/values pairs contained in a form submission. Actually PHP has two arrays, $HTTP_POST_VARS and $HTTP_GET_VARS. As you might expect, the first is populated with a form submission using the post method while the latter is populated with get method submissions.

The $REQUEST_METHOD environment variable normally contains a value of either get or post if the script was called from a form. However, some older servers may not set this variable so we'll detect which associative array is loaded to determine the form's submission method.

The function GetFormData performs two tasks. It returns the appropriate value Post or Get as the first positional parameter. The second parameter is an associative array containing the submitted data, including hidden fields. Once the method determination is ascertained, this scheme frees the script from any additional get/post consideration.

function GetFormData(&$Method,&$FormVariables) {
# Determine if the form used the post or get method and return in $Method
# Return the form's variables as an associative array containing the
# set of Name - Value pairs.
global $HTTP_POST_VARS, $HTTP_GET_VARS;
# POST or GET method used when submitting the form?
$Method = (isset($HTTP_POST_VARS)) ? "Post" : "Get";
# Load the $FormVariables associative array from appropriate array
$FormVariables = ($Method == "Post") ?
$HTTP_POST_VARS : # Post Method Used
$HTTP_GET_VARS; # Get Method Used
} # End of function GetFormData

The two parameters are passed by reference, note the & before the $ used for both variables. The function call would use the template:

GetFormData($Method, $FormVariables);

You will also notice the Phanatic's penchant for the ternary conditional format.

$ReceivingVariable = (Condition) ? TrueAssignment : FalseAssignment;

A form element by any other name

Displaying form values presents a three-fold problem:

traversing the $FormVariables array;

traversing any form element having multiple values; and

culling out HIDDEN form values.

We'll cover these in turn.

Let's initially explore the first two problems. An associative array is a set of key/value pairs. The key portion of the $FormVariables array represents the form component's name clause. Conversely, the value portion represents what the user inputs or the value clause in a hidden field.

As demonstrated in the Dump GLOBALS script, PHP has a foreach array traversal function. The foreach construct can be used for associative or indexed arrays. Our form mailer needs a function to take an associative array as input, traverse the array -- formatting the display of the array on the fly, and finally, return the formatted HTML. The following is the code snippet for dumping the $FormVariables, which is an image of either the $HTTP_GET-VARS or $HTTP_POST_VARS array. The same function can be employed to display other associative arrays variables such as environment values.

Both of the function's required parameters are called by reference. The first parameter is the associative array to be displayed while the second parameter returns the formatted HTML.

Hidden fields

The soul of a generic form handler is the script's ability to perform a variety of optional tasks as selected by the designer of the form. The various options and parameters are passed to the script as hidden fields. Quite simply, a hidden field has a predetermined value assigned by the form's designer, but the end-user of the form never sees the hidden fields unless they look at the document's source code.

The form handler has only one required hidden field: the e-mail address of the designated recipient receiving the formatted output. The HTML code might be

<input type="hidden" name="Recipient" value="urb@usats.com">

The hidden fields must appear between the <form> and </form> tags. As you might suspect, once we're in the script, the variable $Recipient contains the value urb@usats.com.

Once arriving in the CGI script, the name/value pairs from any hidden fields are indistinguishable from user-supplied data. We need a method to determine which of the form's supplied field are control variables and which are user variables. To distinguish between the two types, let's call them system variables and user variables. System variables and values are created by the form designer. User values are those entered into the form by the user.

Separating the system and user data is a three-part process. First, select a group of names than can only be used for system variables. Second, build an associative array containing name(key) parts representing possible system variable names. Additionally, default values for those keys, if any, are then initialized. The Phanatic has his own naming conventions as you can see from the scripts. He prefers running variable names together and starting each name portion with a capital letter, something like FirstName. However, even the Phanatic is willing to recognize that others may have different naming preferences. Use whatever convention you like, just be consistent. How about this range of name values:

all caps;

all ;ower case;

proper Case (First letter of each word capitalized);

words separated by a space, dash, or underscore.

In other words, FirsName, FIRSTNAME, firstname, first name, First-Name, First Name, and First_Name should all be recognized as the same system variable name, namely firstname. Here is a snippet from the StartUp function:

To accomplish the required naming flexibility, the keys of the associated array are all specified as lower case with spaces, dashes, and underscores squeezed out. Now onto the second part, separating the system and user variables.

To peek ahead a little, the allownamealias field is set to either true or false indicating whether name aliases are to be allowed. Maybe you don't want FirstName and first-name to be the same field.

In an earlier function we placed the form's output into an associative array called $FormVariables. What we want to do now is traverse the $FormVariable array and transfer any system variables into the $SystemVariable array. In addition, we want to delete the system variable information from the $FormVariables array. Since we're now experts at traversing an associative array, let jump in.

foreach ($FormVariables as $Name=>$Value)

Remember, the $Name value of a system variable can be based on several different conventions. First, we have to convert the contents to conform to the values loaded in the StartUp function. Then we test the converted name by seeing if the converted value is a key value in the $SystemVariables array. The next two statements perform the conversion. The first uses a Perl regular expression to replace blanks, dashes, and underscores with a null value. The second converts the result to all lower case.

The remainder of the function then determines if $TestKey (the converted value) resides in the $SystemVariables array. If so, it inserts the passed value into the array, overwriting any default value. If it is a system variable the name/value pair in the $FormVariable array are removed.

if (isset($SystemVariables[$TestKey])) { # Is it a system variable?
$SystemVariables[$TestKey] = $Value; # Use it's value if yes
unset($FormVariables[$Name]); # Remove it from $FormVariables
} # End of if (isset($SystemVariables[$TestKey]))

Summary

We're well on our way with our generic form process script but, alas, were running out of space. Let's wrap it up for now and add the bells and whistles next time. We'll also add some field validation in the next episode.

There are two scripts for you to try, demo-form.php is a test form with some of the field building routines from a previous article. The second script, process-form.php has the complete code to do all the things discussed in this article. In addition, it dumps some additional useful information.

As usual, please let me know what types of things you would like to see in these articles.

Urb LeJeune
is a 25-year programming veteran with over 10 years of Internet experience thrown in for good measure.