18.4 Passing Parameters via CGI
You don't need a form to pass a parameter to (most) CGI programs. This feature is convenient because it lets programs be called via simple links, not just by full-blown forms. To test this out, take the original URL and add a question mark followed by the parameter name, an equal sign, and the value desired. For example, the following URL would call the
ice_cream
script with the
When you point your browser at this URL, the browser not only requests the web server to invoke the
ice_cream.plx
program, but it also passes the string Enter the CGI.pm module, which always parses the incoming CGI request correctly. To pull this module into your program, merely say:
somewhere near the top of your program.[ 5 ]
The
In this case, all we need to use from
CGI.pm
is the
If given no arguments,
Even though we have only one item in our import list for
# ice_cream.plx: program to answer ice cream
# favorite flavor form (version 1)
use CGI qw(param);
print <<END_of_Start;
Content-type: text/html
<HTML>
<HEAD>
<TITLE>Hello World</TITLE>
</HEAD>
<BODY>
<H1>Greetings, Terrans!</H1>
END_of_Start
my $favorite = param("flavor");
print "<P>Your favorite flavor is $favorite.";
print <<All_Done;
</BODY>
</HTML>
18.4.1 Less Typing
That's still a lot of typing. Luckily,
CGI.pm
includes a whole slew of convenience functions for simplifying this. Each of these routines returns a string for you to output. For example,
We could list all these functions in the import list given with
We'll just use Here's our program using all the shortcuts CGI.pm provides: # cgi-bin/ice_cream.plx: program to answer ice cream # favorite flavor form (version 2) use CGI qw(:standard); print header(), start_html("Hello World"), h1("Hello World"); my $favorite = param("flavor"); print p("Your favorite flavor is $favorite."); print end_html(); See how much easier that is? You don't have to worry about form decoding, headers, or HTML if you don't want to. 18.4.2 Form GenerationPerhaps you're tired of typing your program's parameter to your browser. Just make a fill-out form instead, which is what most folks are used to. The parts of the form that accept user input are typically called widgets , a much handier term than graphical input devices. Form widgets include single- and multiline textfields, pop-up menus, scrolling lists, and various kinds of buttons and checkboxes. Create the following HTML page, which includes a form with one textfield widget and a submit button. When the user clicks on the submit button,[ 7 ] the ice_cream script specified in the ACTION tag will be called:
<!-- ice_cream.html -->
<HTML>
<HEAD>
<TITLE>Hello Ice Cream</TITLE>
</HEAD>
<BODY>
<H1>Hello Ice Cream</H1>
<FORM ACTION="http://www.SOMEWHERE.org/cgi-bin/ice_cream.plx">
What's your flavor? <INPUT NAME="favorite" VALUE="mint">
<P>
<INPUT TYPE="submit">
</FORM>
</BODY>
Remember that a CGI program can generate any HTML output that you want, which will then be passed to any browser that fetches the program's URL. A CGI program can, therefore, produce the HTML page with the form on it, just as a CGI program can respond to the user's form input. Moreover, the same program can perform both tasks, one after the other. All you need to do is divide the program into two parts, which do different things depending on whether or not the program was invoked with arguments. If no arguments were received, then the program sends the empty form to the browser; otherwise, the arguments contain a user's input to the previously sent form, and the program returns a response to the browser based on that input. Keeping everything in a single CGI file this way eases maintenance. The cost is a little more processing time when loading the original page. Here's how it works:
# ice_cream.plx: program to answer *and generate* ice cream
# favorite flavor form (version 3)
use CGI qw(:standard);
my $favorite = param("flavor");
print header, start_html("Hello Ice Cream"),
h1("Hello Ice Cream");
if ($favorite) {
print p("Your favorite flavor is $favorite.");
} else {
# hr() emits horizontal rule: <HR>
print hr(), start_form();
print p("Please select a flavor: ",
textfield("flavor","mint"));
print end_form(), hr();
If, while using your browser, you click on a link that points to this program (and if the link does not specify Figure 18.2: Screen shot of ice_cream.plx (without input)
Now, fill in the Figure 18.3: Screen shot of ice_cream.plx with params (after input)18.4.3 Other Form ElementsNow that you know how to create simple text fields in your form and respond to them, you're probably wondering how to make the other kinds of widgets you've seen, like buttons, checkboxes, and menus.
Here's a more elaborate version of our program. We've thrown in some new widgets: pop-up menus, a submit button (named "order"), and a button to reset the entire form and erase all user input. Pop-up menus are pretty much just what they say they are, but the arguments given to # ice_cream.plx: program to answer and generate ice cream # order form (version 4) use strict; # enforce variable declarations and quoting use CGI qw(:standard); print header, start_html("Ice Cream Stand"), h1("Ice Cream Stand"); if (param()) { # the form has already been filled out my $who = param("name"); my $flavor = param("flavor"); my $scoops = param("scoops"); my $taxrate = 1.0743; my $cost = sprintf("%.2f", $taxrate * (1.00 + $scoops * 0.25)); print p("Ok, $who, have $scoops scoops of $flavor for \$$cost."); } else { # first time through, so present clean form print hr(); # draw a horizontal rule before the form print start_form(); print p("What's your name? ", textfield("name")); # FOR EXPLANATION OF FOLLOWING TWO LINES, SEE NEXT SECTION print p("What flavor: ", popup_menu("flavor", ['mint','cherry','mocha'])); print p("How many scoops? ", popup_menu("scoops", [ 1..3 ])); print p(submit("order"), reset("clear")); print end_form(), hr(); } print end_html;
Figure 18.4
shows the initial screen the Figure 18.4: Screen shot of ice_cream.plx (final version)
As you'll recall, the 18.4.4 References
You may have noticed that the @choices = ('mint','cherry','mocha'); print p("What flavor: ", popup_menu("flavor", \@choices)); works just as well as this: print p("What flavor: ", popup_menu("flavor", ['mint','cherry','mocha'])); References behave somewhat as pointers do in other languages, but with less danger of error. They're values that refer to other values (or variables). Perl references are very strongly typed (and uncastable), and they can never cause general protection faults. Even better, the memory storage pointed to by references is automatically reclaimed when it's no longer used. References play a central role in object-oriented programming. They're also used in traditional programming, forming the basis for data structures more complex than simple one-dimensional arrays and hashes. Perl supports references to both named and anonymous scalars, arrays, hashes, and functions.
Just as you can create references to named arrays with
{ key1, value1, key2, value2, ... } You can learn more about references in Chapter 4 of Programming Perl , or the perlref documentation. 18.4.5 Fancier Calling Sequences
We'll round out the discussion of form widgets by creating a really fancy widget - one that allows the user to select any number of its items. The To add a scrolling list to a form, here's all you need to do: print scrolling_list( -NAME => "flavors", -VALUES => [ qw(mint chocolate cherry vanilla peach) ], -LABELS => { mint => "Mighty Mint", chocolate => "Cherished Chocolate", cherry => "Cheery Cherry", vanilla => "Very Vanilla", peach => "Perfectly Peachy", }, -SIZE => 3, -MULTIPLE => 1, # 1 for true, 0 for false ); The parameter values have meanings as follows:
When you've set @choices = param("flavors"); Here's another way to create the same scrolling list, passing a reference to an existing hash instead of creating one on the fly: %flavors = ( mint => "Mighty Mint", chocolate => "Cherished Chocolate", cherry => "Cheery Cherry", vanilla => "Very Vanilla", peach => "Perfectly Peachy", ); print scrolling_list( -NAME => "flavors", -LABELS => \%flavors, -VALUES => [ keys %flavors ], -SIZE => 3, -MULTIPLE => 1, # 1 for true, 0 for false );
This time we send in values computed from the keys of the |
|