The text and programs here are from the first edition of CGI Programming 101. This has been replaced by the 2nd edition; please click here to view the updated material from the 2nd edition.

Chapter 5: Advanced Forms


In the last chapter you learned how to decode form data, and mail it to yourself. However, one problem with the previous script is that it doesn't have any error-checking or specialized processing. You might not want to get blank forms, or you may want to require certain fields to be filled out. You might also want to write a quiz or questionnaire, and have your script take different actions depending on the answers. All of these things require some more advanced processing of the form data.

All that's required here is to know how to test conditions in Perl. Probably the main one you'll use in a form-handling script is the if-elsif condition:

The elsif and else blocks are optional; if you are only testing whether a particular variable is true or not, you can just use a single if block:

In Perl there are different conditional test operators, depending on whether the variable you want to test is a string or a number:

TestNumbersStrings
$x is equal to $y$x == $y$x eq $y
$x is not equal to $y$x != $y$x ne $y
$x is greater than $y$x > $y$x gt $y
$x is greater than or equal to $y$x >= $y$x ge $y
$x is less than $y$x < $y$x lt $y
$x is less than or equal to $y$x <= $y$x le $y

Basically, if it's a string test, you use the letter operators (eq, ne, lt, etc.), and if it's a numeric test, you use the symbols (==, !=, etc.). Also, if you are doing numeric tests, keep in mind that $x >= $y is not the same as $x => $y. Be sure to use the correct operator!

Let's try it. Copy your mail.cgi to a new script called mail2.cgi, and insert this conditional test before the open(MAIL) statement:

This condition takes advantage of the dienice subroutine we wrote before. Now, if you submit a blank form, you'll get the error message.

You can extend this to test for multiple fields at the same time:

The above code will return an error if any of the name, email, or age fields are left blank. The conditions are separated by the or operator (which may also be written as ||) - if any of (test1 or test2 or test3) is true, then the condition is met.

Handling Checkboxes

You may want to include checkboxes in your form, to allow the viewer to select one or more options. But how do you decode these inside your CGI?

If you just want to display them in your email message, you can just print them like you would any text field; each checkbox has a different name. Open a new HTML file, and call it colors.html. Enter the following form:

Source code: http://www.cgi101.com/class/ch5/colors.html

Here's how it looks on the screen:

This example lets the visitor pick as many options as they want - or none, if they prefer. While you can set the value="whatever" part of the checkbox field to any value you want, if you use integers, it will mean less code inside the CGI.

Now let's write the CGI to process the above form. Call it colors.cgi:

Source code: http://www.cgi101.com/class/ch5/colors.txt

NOTE: if you used value=1 in your form, then your CGI can test it with "if ($FORM{$x} == 1)". But if you put quotes around the 1, such as value="1", then your CGI will not work unless you change the == operator to an eq:

Handling Radio Buttons

Radio buttons differ from checkboxes in that you can have several buttons that share the same field name in the form itself - thus allowing the viewer to only select one of a series of options. To distinguish each option, the buttons themselves must have different values.

Let's try it. Take your colors.html file, and copy it to colors2.html. Then edit it and replace the checkbox fields with the following:

Source code: http://www.cgi101.com/class/ch5/colors2.html

Here's how it looks on the screen:

This is similar to the checkboxes form. However, in this case, each radio button has the same field name, but a different value. It's easiest to set the value to be relevant to the name of the thing being picked - in this case the values are set to the name of the colors themselves. Radio buttons can be handled in Perl fairly simply. Copy your colors.cgi to colors2.cgi, and replace the foreach loop with the following line:

Source code: http://www.cgi101.com/class/ch5/colors2.txt

You see here why it is best to set the value to something meaningful - this lets you just print out the radio button and its value, without having to also store another list inside your CGI to show what each button means.

Let's take this one step further. Say you not only want to tell the viewer what color they picked, but you also want to show it to them. Edit your colors2.cgi and replace the existing print statements with the following code:

Source code: http://www.cgi101.com/class/ch5/colors2a.txt

The above actually sets the background color to whatever color you picked. It's using a hash called %colors, whose keys are the same as the data value of the radio buttons in the form itself. The values of the hash are hex codes for those colors.

Handling SELECT Fields

Select fields may be handled almost exactly the same as radio buttons. A select field, in your HTML page, is a pull-down menu like this:

The HTML to generate the above is as follows:

As with radio buttons, you can print out the selection just as it was made in the form:

This will only work if your select statement is a single-value select (that is, your visitor can't select more than one item from the selection list). For handling multi-value selects, see below.

Multiple-choice Selects

The reason our above form-handling code doesn't handle multi-choice selects is that we're assigning a single $value to each field name from the form:

If you have a multiple select, like this:

This code allows the user to pick more than one city from the list:

Then when your form data is passed on to the CGI, you have several instances of cities="cityname". So if $FORM{'cities'} already exists and has a value in it, and you send another value, the old value just gets overwritten by the new one.

The solution to this is to handle the multi-selects differently, by storing them in their own array, rather than in the $FORM hash. Here's how you might do it:

Source code: http://www.cgi101.com/class/ch5/mform.txt
Working example: http://www.cgi101.com/class/ch5/mform.html

Now you can use the @cities array for any special processing of the multi-field city data. Everything else is stored in %FORM.

Survey Form and CGI

Let's take what you've learned so far and put it to practical use: a survey form and its corresponding CGI. This type of form adds interactivity to your site, whether you're doing a one question poll-of-the-day, or a lengthy survey of your site's readers.

Create a new HTML form, and name it survey.html. Enter the following form:

Source code: http://www.cgi101.com/class/ch5/survey.html

Save it. Now create survey.cgi:

Source code: http://www.cgi101.com/class/ch5/survey.txt
Working example: http://www.cgi101.com/class/ch5/survey.html

Save and chmod it, and try filling out the survey in your browser. This example posts the results to the page, but you can just as easily email yourself a copy of the results, using the mail code in chapter 4. In this case all you need to change, after the MAIL handle is open, is the print <<EndHTML statements, to:

This will redirect the subsequent text to the mail message, rather than standard output.

It's more likely you'll want to write the data to a file, however, so you can analyze the results later. We'll cover reading and writing files next.

Resources

Visit http://www.cgi101.com/class/ch5/ for source code and links from this chapter.


Copyright © 2000 by Jacqueline D. Hamilton.
Chapter 4 Table of Contents Chapter6