Learning Perl on Win32 Systems

Learning Perl on Win32 SystemsSearch this book
Previous: 18.3 Simplest CGI ProgramChapter 18
CGI Programming
Next: 18.5 Creating a Guestbook Program
 

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 flavor parameter set to the value mint:

http://www.SOMEWHERE.org/cgi-bin/ice_cream.plx?flavor=mint

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 flavor=mint to the program. Now it's up to the program to read the argument string and pick it apart. Doing this properly is not as easy as you might think. Many programs try to wing it and parse the request on their own, but most hand-rolled algorithms only work some of the time. Given how hard it is to get it right in all cases, you probably shouldn't try to write your own code, especially when perfectly fine modules already handle the tricky parsing business for you.

Enter the CGI.pm module, which always parses the incoming CGI request correctly. To pull this module into your program, merely say:

use CGI;

somewhere near the top of your program.[5]

[5] All Perl modules end in the suffix .pm; in fact, the use statement assumes this suffix. You can learn how to build your own modules in Chapter 5 of Programming Perl or the perlmod documentation.

The use statement is somewhat like a #include statement in C programming in that it pulls in code from another file at compile time. But it also allows optional arguments specifying which functions and variables you'd like to access from that module. Put those in a list following the module name in the use statement. You can then access the named functions and variables as if they were your own.

In this case, all we need to use from CGI.pm is the param() function.[6]

[6] Some modules automatically export all their functions, but because CGI.pm is really an object module masquerading as a traditional module, we have to ask for its functions explicitly.

If given no arguments, param() returns a list of all the fields that were in the HTML form that this CGI script is responding to. (In the current example, this list contains the flavor field. In general, the list contains all the names in name=value strings received from the submitted form.) If given an argument naming a field, param() returns the value (or values) associated with that field. Therefore, param("flavor") returns "mint", because we passed in ?flavor=mint at the end of the URL.

Even though we have only one item in our import list for use, we'll employ the qw() notation; this way it will be easier to expand the list later:

# 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>
All_Done

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, header() returns a string containing the Content-type line with a following blank line, start_html(string) returns string as an HTML title, h1(string) returns string as a first-level HTML heading, and p(string) returns string as a new HTML paragraph.

We could list all these functions in the import list given with use, but that would eventually grow too unwieldy. However, CGI.pm, like many modules, provides you with import tags - labels that stand for groups of functions to import. You simply place the desired tags (each of which begins with a colon) at the beginning of your import list. The tags available with CGI.pm include these:

:cgi

Import all argument-handling methods, such as param().

:form

Import all fill-out form generating methods, such as textfield().

:html2

Import all methods that generate HTML 2.0 standard elements.

:html3

Import all methods that generate HTML 3.0 proposed elements (such as <table>, <super>, and <sub>).

:netscape

Import all methods that generate Netscape-specific HTML extensions.

:shortcuts

Import all HTML-generating shortcuts (that is, "html2" + "html3" + "netscape").

:standard

Import "standard" features: "html2," "form," and "cgi."

:all

Import all the available methods. For the full list, see the CGI.pm module, where the variable %TAGS is defined.

We'll just use :standard. (For more information about importing functions and variables from modules, see the Exporter module in Chapter 7 of Programming Perl.)

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 Generation

Perhaps 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:

[7] Some browsers allow you to leave out the submit button when the form has only a single input text field. When the user types a return in this field, it is treated as a submit request. But you should use proper HTML here.

<!-- 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>
</HTML>

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 ?whatever at the end of the URL), you'll see a screen like Figure 18.2.

Figure 18.2: Screen shot of ice_cream.plx (without input)

Figure 18.2

Now, fill in the flavor field and press Return. Figure 18.3 will appear.

Figure 18.3: Screen shot of ice_cream.plx with params (after input)

Figure 18.3

18.4.3 Other Form Elements

Now 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 popup_menu may perplex you until you've read the following section on "References." The textfield() function creates a text-input field with the indicated name. We'll give more details about this function when describing the guestbook program later in this chapter. Here's an example:

# 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 textfield function generates.

Figure 18.4: Screen shot of ice_cream.plx (final version)

Figure 18.4

As you'll recall, the param() function, when called without arguments, returns the names of all form-input fields that were filled out. As a result, you can tell whether or not the URL was called from a filled-out form. If you have parameters, then the user filled in some of the fields of an existing form, so respond to them. Otherwise, generate a new form, expecting to have this very same program called a second time.

18.4.4 References

You may have noticed that the popup_menu() functions in the previous example both have a strange kind of argument. Just what are ['mint', 'cherry','mocha'] and [ 1..3 ] doing there? The brackets create something you haven't seen before: a reference to an anonymous array. The popup_menu() function expects an array reference for an argument. Another way to create an array reference is to use a backslash in front of a named array, as in \@choices. So this:

@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 \@array and to anonymous arrays with [ list ], you can also create references to named hashes using \%hash and to anonymous hashes using:[8]

[8] Yes, braces now have quite a few meanings in Perl. The context in which you use them determines what they're doing.

{ 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 scrolling_list() function of CGI.pm can take an arbitrary number of argument pairs, each of which consists of a named parameter (beginning with -) and a value for the parameter.

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:

-NAME

The name of the widget. You can use the value of this later to retrieve user data from the form with param().

-VALUES

A reference to an anonymous array. The array consists of the keys of the hash referenced by -LABELS.

-LABELS

A reference to an anonymous hash. The values of the hash provide the labels (list items) seen by the form user. When a particular label is selected by the user, the corresponding hash key is what gets returned to the CGI program. That is, if the user selects the item given as Perfectly Peachy, the CGI program will receive the argument peach.

-SIZE

A number determining how many list items will be visible to the user at one time.

-MULTIPLE

A true or false value (in Perl's sense of true and false) indicating whether the form user will be allowed to choose more than one list item.

When you've set -MULTIPLE to true, you'll want to assign param()'s return list to an array:

@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 %flavors hash, which is itself passed in by reference using the backslash operator. Notice how the -VALUES parameter is still wrapped in square brackets? Passing in the result of keys as a list wouldn't work because the calling convention for the scrolling_list() function requires an array reference there, which the brackets happily provide. Think of the brackets as a convenient way to treat multiple values as a single value.


Previous: 18.3 Simplest CGI ProgramLearning Perl on Win32 SystemsNext: 18.5 Creating a Guestbook Program
18.3 Simplest CGI ProgramBook Index18.5 Creating a Guestbook Program