Полезная информация

Chapter 8

Using Existing CGI Libraries


CONTENTS

Welcome to Hump Day in the afternoon. It really is a lovely day outside, and every lesson series should have an early day off. You should be able to read through this chapter relatively quickly and catch your breath today. Expect to return to this chapter on a regular basis, however, because it contains reference material to what I think are some of the best CGI library resources available.

The Internet is a vast sea of resources. You can find almost anything within the Internet Information sea, but how do you find the real pearls in all those vast waters? Well, that's what you do in this chapter-you examine a couple of Perl gems and one C library. They will save you vast amounts of programming time. Make good use of these libraries and don't be like the average programmer and reinvent the wheel each time you build a new cart. Read through the libraries to be sure you understand what they do and, with cgi-lib.pl, how they do it. Decide which library or libraries best suit your needs and then download them from the resources identified. Usually, you will want to install them in your cgi-bin directory. Make sure that you check with your Webmaster to see whether these libraries already are installed on your server.

Be lazy like me, and make good use of these libraries so that you can concentrate on whatever is today's real problem. And that's what this afternoon's lesson is about. In this chapter, you will learn about several existing libraries on the Net.

In particular, you will learn about the following:

Using the cgi-lib.pl Library

The cgi-lib.pl version 1.14 library is the smallest library you will learn about in this chapter. Don't discard it from your toolbox just because it is small, though. Many of your CGI programs will be small applications that don't require a large library with a large amount of code to interpret. Some of the advantages of a small library are ease of understanding, ease of use, and improved efficiency. The smaller cgi-lib.pl library also takes less time to load than the other, larger libraries. I particularly like the cgi-lib.pl library because of its simplicity. For lots of small applications, it's just perfect. The cgi-lib.pl library is written and copyrighted by Steven E. Brenner (S.E.Brenner@bioc.cam.ac.uk) and is included here with his permission. You can find the latest copy of this library at

http://www.bio.cam.ac.uk/web/form.html

As you look through this library, take a close look at the first few lines of the PrintVariables function. Steve uses the special Perl global variable $*. The $* variable enables multiple-line pattern matching. But in addition to that, Steve illustrates good programming practice by saving the value of the $* variable before his subroutine changes it for its own use. This way, before his subroutine exits, it can restore the original value of the $* variable. Saving the values of any variables you need to use inside your subroutines and then restoring them before you exit the subroutine saves you many hours hunting for strange and hard-to-find bugs. This means that you can go out and party at night instead of having an all-night affair with your computer.

Determining the Requesting Method

The MethGet function determines which HTTP request method was used to call your CGI program. The function returns True if the request method was Get. The complete function is only one statement long. Sometimes it seems silly or not worth the effort to create a function that is only a couple of lines long. If you are going to use the same code several times, however, it makes sense to make that code into a subroutine. I like to use the three-or-greater rule: If the same code is going to be used in three or more places, it should be made into a subroutine. Listing 8.1 shows the MethGet function in its entirety.


Listing 8.1. The MethGet function.

1: sub MethGet {
2:   return ($ENV{'REQUEST_METHOD'} eq "GET");
3: }

Decoding Incoming CGI Data

The ReadParse() function reads in Get or Post data, converts it to unescaped text, and puts one key=value in each member of the list @in. The ReadParse function also creates key/value pairs in %in, using '\0' to separate multiple selections. If a parameter (*cgi_input, for example) is passed to ReadParse, the parsed data is stored there, rather than in $in, @in, and %in. Listing 8.2 shows the ReadParse function.


Listing 8.2. The ReadParse function.

01: sub ReadParse {
02:     local (*in) = @_ if @_;
03:   local ($i, $loc, $key, $val);
04:   # Read in text
05:   if ($ENV{'REQUEST_METHOD'} eq "GET") {
06:     $in = $ENV{'QUERY_STRING'};
07:   } elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
08:     read(STDIN,$in,$ENV{'CONTENT_LENGTH'});
09:   }
10:   @in = split(/&/,$in);
11:
12:   foreach $i (0 .. $#in) {
13:     # Convert pluses to spaces
14:     $in[$i] =~ s/\+/ /g;
15:     # Split into key and value.
16:     ($key, $val) = split(/=/,$in[$i],2); # splits on the first =.
17:     # Convert %XX from HEX numbers to alphanumeric
18:     $key =~ s/%(..)/pack("c",hex($1))/ge;
19:     $val =~ s/%(..)/pack("c",hex($1))/ge;
20:     # Associate key and value
21:     $in{$key} .= "\0" if (defined($in{$key}));
 # \0 is the multiple separator
22:     $in{$key} .= $val;
23:   }
24:   return 1; # just for fun
25: }

Printing the Magic HTTP Content Header

The function PrintHeader returns the content-type: text/html HTTP response header for HTML documents with the correct number of newline characters (\n\n). Listing 8.3 shows the PrintHeader function.


Listing 8.3. The PrintHeader function.

1: sub PrintHeader {
2:   return "content-type: text/html\n\n";
3: }

Printing the Variables Passed to Your CGI Program

The function PrintVariables, shown in Listing 8.4, formats an input variable list that is an associative array and returns an HTML string formatted as a definition list (<DL>) made up of the keyword represented as a definition term (<DT>) and the keyword value as a definition description (<DD>).


Listing 8.4. The PrintVariables function.

01: sub PrintVariables {
02:   local (%in) = @_;
03:   local ($old, $out, $output);
04:   $old = $*;  $* =1;
05:   $output .=  "<DL COMPACT>";
06:   foreach $key (sort keys(%in)) {
07:     foreach (split("\0", $in{$key})) {
08:       ($out = $_) =~ s/\n/<BR>/g;
09:       $output .=  "<DT><B>$key</B><DD><I>$out</I><BR>";
10:     }
11:   }
12:   $output .=  "</DL>";
13:   $* = $old;
14:   return $output;
15: }

Printing the Variables Passed to Your CGI Program in a Compact Format

The function PrintVariablesShort, shown in Listing 8.5, formats an input variable list
that is an associative array and returns an HTML string formatted as one line per keyword/value pair.


Listing 8.5. The PrintVariablesShort function.

01: sub PrintVariablesShort {
02:   local (%in) = @_;
03:   local ($old, $out, $output);
04:   $old = $*;  $* =1;
05:   foreach $key (sort keys(%in)) {
06:     foreach (split("\0", $in{$key})) {
07:       ($out = $_) =~ s/\n/<BR>/g;
08:       $output .= "<B>$key</B> is <I>$out</I><BR>";
09:     }
10:   }
11:   $* = $old;
12:   return $output;
13: }

Using CGI.pm for Creating and Reading Web Forms

The Perl 5 library CGI.pm uses objects to create Web forms on-the-fly and to parse their contents. It is similar to cgi-lib.pl in some respects. Perl 5 is an object-oriented version of the standard Perl language. It provides a simple interface for parsing and interpreting query strings passed to CGI scripts. It also offers a rich set of functions for creating fill-out forms, however. Instead of remembering the syntax for HTML form elements, you just make a series of Perl function calls. An important fringe benefit of this is that the value of the previous query is used to initialize the form, so the state of the form is preserved from invocation to invocation. The CGI.pm library is included in this chapter with the permission of Mr. Lincoln Stein, MD, Ph.D. and is available at

http://www-genome.wi.mit.edu/WWW/tools/scripting/CGIperl

Everything is done through a CGI object. When you create one of these objects, it examines the environment for a query string, parses it, and stores the results. You then can ask the CGI object to return or modify the query values. CGI objects handle Post and Get methods and distinguish between scripts called from Isindex documents and form-based documents. In fact, you can debug your script from the command line without worrying about setting up environment variables.

A script to create a fill-out form that remembers its state each time it's invoked is very easy to write with CGI.pm. Listing 8.6 shows an example of such a script.


Listing 8.6. Creating a fill-out form using CGI.pm.

01: use CGI;
02: $query = new CGI;
03: print $query->header;
04:
05: print $query->startform;
06: print "What's your name? ",$query->textfield('name');
07: print "<P>What's the combination? ",
08:         $query->checkbox_group('words',['eenie','meenie','minie','moe']);
09: print "<P>What's your favorite color? ",
10:         $query->popup_menu('color',['red','green','blue','chartreuse']);
11: print "<P>",$query->submit;
12: print $query->endform;
13:
14: print "<HR>\n";
15: if ($query->param) {
16:     print "Your name is <EM>",$query->param('name'),"</EM>\n";
17:     print "<P>The keywords are: <EM>",join(", ",$query->param('words')),
 "</EM>\n";
18:     print "<P>Your favorite color is <EM>",$query->param('color'),"</EM>\n";
19: }

Installing CGI.pm

To use this package, install it in your Perl library path. On most systems, this will be /usr/local/lib/perl5, but check with your System Administrator to be sure. Then place the following statement at the top of your Perl CGI scripts:

Use CGI;

If you do not have sufficient privileges to install into /usr/local/lib/perl5, you still can use CGI.pm. Place it in a convenient place-for example, in /usr/local/etc/httpd/cgi-bin-and preface your CGI scripts with a preamble something like this:

BEGIN {
     push(@Inc,'/usr/local/etc/httpd/cgi-bin');
}
Use CGI;

Be sure to replace /usr/local/etc/httpd/cgi-bin with the location of CGI.pm on your server.

Reading Input Data

You can use two methods in the CGI.pm library to read data passed to your CGI program:

Saving Your Incoming Data

Your incoming data should be saved to an object such as the $query object. The following methods are available for decoding and modifying the object data; these methods assume that you have named that object $query.

Getting a List of Keywords from the Query Object

If your CGI program was invoked as the result of an Isindex search, the parsed keywords of the Isindex input search string can be obtained with the keywords() method. This method returns the keywords as a Perl array. Use this code:

@keywords = $query->keywords

Getting the Names of All Parameters Passed to Your Script

If your CGI program was invoked with a parameter list such as

name1=value1&amp;name2=value2&amp;name3=value3"

the param() method returns the parameter names as a list. For backward compatibility, this method works even if the script was invoked as an Isindex script; in this case, a single parameter name is returned named 'keywords'. Use this code:

@names = $query->param

Getting the Value(s) of a Named Parameter

You pass the param('NAME') method a single argument to fetch the value of the named parameter. If the parameter is multivalued (from multiple selections in a scrolling list, for example), you can ask to receive an array. Otherwise, the method returns a single value. Use this code:

@values = $query->param('foo');

or

$value = $query->param('foo');

As of version 1.50 of this library, the array of parameter names returned is in the same order in which the browser sent them. Although this is not guaranteed to be identical to the order in which the parameters were defined in the fill-out form, this is usually the case.

Setting the Value(s) of a Named Parameter

The method

param('NAME' 'NEW-VALUES')

sets the value for the named parameter 'foo' to one or more values. These values are used to initialize form elements, if you so desire. Note that this is the correct way to change the value of a form field from its current setting. Use this code:

$query->param('foo','an','array','of','values');

Deleting a Named Parameter

The method

delete('NAME')

deletes a named parameter entirely. This is useful when you want to reset the value of the parameter so that it isn't passed down between invocations of the script. Use this code:

$query->delete('foo');

Importing Parameters into a Namespace

The method

import_names('NAME_SPACE')

imports all parameters into the given namespace. If there were parameters named 'foo1', 'foo2', and 'foo3', for example, after executing $query->import('R'), the variables @R::foo1, $R::foo1, @R::foo2, $R::foo2, and so on would conveniently spring into existence. Because CGI has no way of knowing whether you expect a multi- or single-valued parameter, it creates two variables for each parameter. One variable is an array and contains all the values, and the other is a scalar containing the first member of the array. Use whichever variable is appropriate. For keyword (a+b+c+d) lists, the variable @R::keywords is created. Use this code:

$query->import_names('R')

If you don't specify a namespace, this method assumes namespace "Q". Use this code:

$query->import_names('R');
print "Your name is $R::name\n"
print "Your favorite colors are @R::colors\n";

Warning
Do not import into namespace 'main'. This represents a major security risk, because evil people then could use this feature to redefine central variables such as @Inc. If you try to do this, CGI.pm exits with an error.

Saving the Current State of a Form

As you have seen throughout this book, saving the state of your CGI program is one of the harder things to do in the CGI environment. The CGI.pm library addresses that need with the following two methods. These two methods enable you to save object state information so that you can use it the next time your CGI program is called.

Saving the State to a File

The method

save(FILEHANDLE)

writes the current query object out to the filehandle of your choice. The filehandle already must be open and writable but, other than that, it can point to a file, a socket, a pipe, or whatever. The contents of the form are written out as tag=value pairs, which can be reloaded with the new() method later. Use this code:

$query->save(FILEHANDLE)

Saving the State in a Self-Referencing URL

The method

self_url()

returns a URL that, when selected, reinvokes your CGI program with all its state information intact. This is most useful when you want to jump around within a script-generated document using internal anchors but don't want to disrupt the current contents of the form(s). Use this code:

$my_url=$query->self_url;

Creating the HTTP Headers

Every CGI program needs to print the correct HTTP headers. The following methods perform this task for you with a minimum amount of programming effort.

Creating the Standard Header for a Virtual Document

The header('CONTENT-TYPE/SUBTYPE') method prints the required HTTP content-type header and the requisite blank line below it. If no parameter is specified, it defaults to 'text/html'. Use this code:

print $query->header('image/gif');

An extended form of this method enables you to specify a status code and a message to pass back to the browser. Use this code:

print $query->header('text/html',204,'No response');

This method presents the browser with a status code of 204 (no response). Properly behaved browsers will take no action and simply remain on the current page. (This is appropriate for a script that does some processing but doesn't need to display any results, or for a script called after a user clicks on an empty part of a clickable imagemap.)

Creating the Header for a Redirection Request

The method

redirect('Absolute-URI')

generates a redirection request for the remote browser. It immediately goes to the indicated URI. Your CGI program should exit soon after this. Nothing else is displayed. Use this code:

print $query->redirect('http://somewhere.else/in/the/world');

Creating an HTML Header

The method

start_html('TITLE', 'EMAIL-ADDRESS', 'BASE-TAG','ATTRIBUTE-LIST')

generates the header tags for your HTML page. The input parameters are the title, your e-mail address, the Base tag, and an arbitrary list of attributes, such as the background color or keywords. The method returns a canned HTML header and the opening Body tag. Use this code:

print $query->start_html('Secrets of the Pyramids',
                                       'fred@capricorn.org',
                                       'true',
                                       'BGCOLOR="#00A0A0"')

Table 8.1 explains the parameters of the start_html method; these are optional.

Table 8.1. The start_html parameters.

NameMeaning
TITLE The title string to use for the HTML header.
EMAIL-ADDRESS The author's e-mail address (creates a <LINK REV="MADE"> tag).
BASE-TAG Set to True if you want to include a Base tag in the header. This helps resolve relative addresses to absolute ones when the document is moved but makes the document hierarchy non-portable. Use this with care!
ATTRIBUTE-LIST Any additional attributes you want to incorporate into the Head tag (as many as you want). This is a good way to incorporate Netscape-specific extensions, such as a background color and a wallpaper pattern. (The example in this section sets the page background to a vibrant blue.)

Ending an HTML Document

The end_html method ends an HTML document by printing the </BODY></HTML> tags. Use this code:

print $query->end_html

Creating Forms

The CGI.pm library provides a full set of methods for creating Web fill-out forms. The various form-creating methods all return strings to the caller. These strings contain the HTML code that creates the requested form element. You are responsible for actually printing these strings. It's set up this way so that you can place formatting tags around the form elements.

The default values that you specify for the forms are used only the first time the script is invoked. If values already are present in the query string, they are used, even if blank. If you want to change the value of a field from its previous value, call the param() method to set it.

To reset the fields to their defaults, you can do this:

The optional values of the Web fill-out form methods depend on their positions in the parameter list. You cannot leave out value two of a four-value parameter list and include values three and four, for example. If you want to include any value in a parameter list that is to the right of another optional parameter, you must include the earlier parameter, even if you want the default value from the earlier parameter.

You can put multiple forms on the same page if you want. Be warned that it isn't always easy to preserve state information for more than one form at a time, however.

By popular demand, the text and labels you provide for form elements are escaped according to HTML rules. This means that you can safely use "<CLICK ME>" as the label for a button. However, this behavior might interfere with the capability to incorporate special HTML character sequences-such as &amp;Aacute; (&Aacute;)-into your fields. If you want to turn off automatic escaping, call the autoEscape() method with a False value immediately after creating the CGI object, as outlined in this program fragment:

$query = new CGI;
$query->autoEscape(undef);

You can turn autoescaping back on at any time with

$query->autoEscape('yes')

Creating an Isindex Tag

The isindex() method called without any arguments returns an Isindex tag that designates your CGI program as the URI to call. If you want the browser to call a different URI to handle the search, pass isindex('TGT-URI') the URI you want to be called. Use this code:

print $query->isindex($action);

Starting a Form

The method

startform('HTTP-METHOD', 'TGT-URI')

returns a Form tag with the optional HTTP-METHOD and TGT-URI that you specify (Post and none assumed). Use this code:

print $query->startform($method,$action);

Table 8.2 explains the parameters of the startform() function.

Table 8.2. The startform() parameters.

NameMeaning
HTTP-METHOD The method the data sends to the server; it can be Get or Post. If this field is not supplied, the default method is Post.
TGT-URI The CGI program to invoke when the Web fill-out form is sent to the server. If this field is not supplied, the default is none.

Ending a Form

The endform() method returns a Form tag. Use this code:

print $query->endform;

Creating a Text Field

The method

textfield('NAME','INITIAL-VALUE','WINDOW-SIZE','MAX-chARACTERS')

returns a string that contains the HTML code for a text-input field. Use this code:

print $query->textfield('foo','starting value',50,80);

Table 8.3 explains the parameters of the textfield() function.

Table 8.3. The textfield() parameters.

NameMeaning
INITIAL-VALUE Initial value for the text-field contents. This parameter is optional.
MAX-chARACTERS Maximum number of characters the field accommodates. This parameter is optional.
NAME Name field. This parameter is required.
WINDOW-SIZE Size of the text-entry window, in characters. This parameter is optional.

As with all these methods, the field is initialized with its contents from earlier invocations of the script. When the form is processed, the value of the Text field can be retrieved with this code:

$value = $query->param('foo');

Creating a Textarea Field

The method

textarea('NAME','INITIAL-VALUE','ROWS','COLUMNS')

is just like the textfield() method, but it enables you to specify rows and columns for a multiline text-entry box. You can provide a starting value for the field, which can be long and contain multiple lines. Scrollbars for both horizontal and vertical scrolling are added automatically. Use this code:

print $query->textarea('foo','starting value',50,80);

Table 8.4 explains the parameters of the textarea() function.

Table 8.4. The textarea() parameters.

NameMeaning
COLUMNS Number of columns of the text area window. This parameter is optional.
INITIAL-VALUE Initial value for the text-area contents. This can be multiple lines. This parameter is optional.
NAME Text-area Name field. This parameter is required.
ROWS Number of rows of the text-area window. This parameter is optional.

Creating a Password Field

The method

password_field('NAME', 'INITIAL-VALUE', 'WINDOW-SIZE','MAX-chARACTERS')

is identical to textfield() except that its contents, when typed from the keyboard or from the Value field, are represented by asterisks on the Web page. Use this code:

print $query->password_field('foo','starting value',50,80);

Table 8.5 explains the parameters of the password_field() function.

Table 8.5. The password_field() parameters.

NameMeaning
INITIAL-VALUE Initial value for the Password field's contents. This parameter is optional.
MAX-chARACTERS Maximum number of characters the field accommodates. This parameter is optional.
NAME Password Name field. This parameter is required.
WINDOW-SIZE Size of the text-entry window, in characters. This parameter is optional.

Creating a Pop-Up Menu

The method

popup_menu('NAME', 'OPTION-NAMES', 'SELECTED-OPTION', 'OPTION-VALUES')
creates a selection menu, which also is referred to as a pull-down menu. Use this code:
print $query->popup_menu('menu_name',['eenie','meenie','minie'],'meenie');
or
print $query->popup_menu('menu_name',
                           ['one','two','three'],'two',
                           {'one'=>'eenie','two'=>'meenie','three'=>'minie'});

Table 8.6 explains the parameters of the popup_menu() function.

Table 8.6. The popup_menu() parameters.

NameMeaning
NAME Pop-up menu Name field. This parameter is required.
OPTION-NAMES An array reference containing the list of menu items in the menu. You can pass the method an anonymous array, as shown in the example, or a reference to a named array, such as @foo. This parameter is required.
OPTION-VALUES An array reference to an associative array containing user-visible labels for one or more of the menu items. You can use this when you want the user to see one menu string but have the browser return to your program a different string. Because this is an associative array and you must match the OPTION-NAMES with the OPTION-VALUES, the order of the associative array is not important. If this value is undefined, the OPTION-NAMES are sent as the OPTION-VALUES to your CGI program. This parameter is optional.
SELECTED-OPTION Name of the default menu choice. If not specified, the first item is the default. The value of the previous choice is maintained across queries. This parameter is optional.

When the form is processed, the selected value of the pop-up menu can be retrieved by using this code:

$popup_menu_value = $query->param('menu_name');

Creating a Scrolling List

The method

scrolling_list('NAME', 'OPTION-NAMES', 'SELECTED-OPTIONS', 'LIST-SIZE',
  'MULTIPLE-SELECTIONS', 'OPTION-VALUES')

creates a scrolling list that contains the items passed in the OPTION-NAMES parameter. The list can be set to select only one item or multiple items at a time. Use this code:

print $query->scrolling_list('list_name',
                               ['eenie','meenie','minie','moe'],
                               ['eenie','moe'],5,'true');

or

print $query->scrolling_list('list_name',
                               ['one','two','three','four'],
                               ['one','four'],5,'true',
                               {'one'=>'eenie','two'=>'meenie',
                                'three'=>'minie','four'=>'moe'});

Table 8.7 explains the parameters of the scrolling_list() function.

Table 8.7. The scrolling_list() parameters.

NameMeaning
LIST-SIZE Number of visible list items. If undefined, the default is 1. This parameter is optional.
MULTIPLE-SELECTIONS If True, multiple simultaneous selections are allowed. If undefined, only one selection is allowed at a time. This parameter is optional.
NAME Scrolling-list Name field. This parameter is required.
OPTION-NAMES An array reference containing the list of menu items in the menu. You can pass the method an anonymous array, as shown in the example, or a reference to a named array, such as @foo. This parameter is required.
OPTION-VALUES An array reference to an associative array containing user-visible labels for one or more of the menu items. You can use this when you want the user to see one menu string but have the browser return to your program a different string. Because this is an associative array and you must match the OPTION-NAMES with the OPTION-VALUES, the order of the associative array is not important. If this value is undefined, the OPTION-NAMES are sent as the OPTION-VALUES to your CGI program. This parameter is optional.
SELECTED-OPTIONS A reference to a list containing the values to be selected by default or a single value to select. If this argument is missing or undefined, nothing is selected when the list first appears. This parameter is optional.

When this form is processed, all selected list items are returned as a list under the parameter name 'list_name'. You can retrieve the values of the selected items with this code:

@selected = $query->param('list_name');

Creating a Group of Related Checkboxes

The method

checkbox_group('GROUP-NAME', 'BOX-NAMES', 'SELECTED-LIST', 'VERTICAL',
  'BOX-VALUES')

creates a list of checkboxes that are related by the same name, just as pop-up menus and scrolled lists are related by the same name. Use this code:

print $query->checkbox_group('group_name',
                               ['eenie','meenie','minie','moe'],
                               ['eenie','moe'],'true');

or

print $query->checkbox_group('group_name',
                             ['one','two','three','four'],
                             ['one','two'],'true',
                             {'one'=>'eenie','two'=>'meenie',
                              'three'=>'minie','four'=>'moe'});

Table 8.8 explains the parameters of the checkbox_group().

Table 8.8. The checkbox_group() parameters.

NameMeaning
BOX-NAMES An array reference to the names used for the user-readable labels printed next to the checkboxes, as well as for the values passed to your script in the query string. This parameter is required.
BOX-VALUES An array reference to an associative array containing user-visible labels for one or more of the checkbox items. You can use this when you want the user to see one visible string but have the browser return a different string to your program. Because this is an associative array, and you must match the OPTION-NAMES with the OPTION-VALUES, the order of the associative array is not important. If this value is undefined, the OPTION-NAMES are sent as the OPTION-VALUES to your CGI program. This parameter is optional.
GROUP-NAME The checkbox group_name field. This parameter is required.
SELECTED-LIST Either a reference to a list containing the values to be checked by default or a single value to be checked. If this argument is missing or undefined, nothing is selected when the list appears. This parameter is optional.
VERTICAL If True, places line breaks between the checkboxes so that they appear as a vertical list. If this argument is undefined or False, the checkboxes are strung together on a horizontal line. This parameter is optional.

You can retrieve the values of the enabled checkboxes (those that are turned on) with this code:

@turned_on = $query->param('group_name');

Creating a Standalone Checkbox

The method

checkbox('NAME', 'SELECTED', 'CGI-VALUE', 'VALUE')

is used to create an isolated checkbox that isn't logically related to any others. Use this code:

print $query->checkbox('checkbox_name',1,'TURNED ON','Turn me on');

Table 8.9 explains the parameters of the checkbox() function.

Table 8.9. The checkbox() parameters.

NameMeaning
CGI-VALUE The value passed to your CGI program when the checkbox is selected. If not provided, the word on is assumed. This parameter is optional.
NAME The checkbox Name field. This parameter is required.
SELECTED If True, the checkbox is selected. If the argument is missing or undefined, the checkbox is not selected. This parameter is optional.
VALUE Assigns a user-visible label to the button. If not provided, the checkbox's name is used. This parameter is optional.

You can retrieve the value of the checkbox by using this code:

$turned_on = $query->param('checkbox_name');

Creating a Radio Button Group

The method

radio_group('GROUP-NAME', 'BUTTON-NAMES','SELECTED','VERTICAL','BUTTON-VALUES')

creates a set of logically related radio buttons. Turning on one member of the group turns off the others. Use this code:

print $query->radio_group('group_name',['eenie','meenie','minie'],
                                         'meenie','true');

or

print $query->radio_group('group_name',['one','two','three'],
                                       'two','true',
                                       {'one'=>'eenie','two'=>'meenie'});

Table 8.10 explains the parameters of the radio_group() function.

Table 8.10. The radio_group() parameters.

NameMeaning
BUTTON-NAMES An array reference to the names used for the user-readable labels printed next to the radio buttons, as well as for the values passed to your script in the query string. This parameter is required.
BUTTON-VALUES An array reference to an associative array containing user-visible labels for one or more of the radio button items. You can use this when you want the user to see one visible string but have the browser return a different string to your program. Because this is an associative array and you must match the OPTION-NAMES with the OPTION-VALUES, the order of the associative array is not important. If this value is undefined, the OPTION-NAMES are sent as the OPTION-VALUES to your CGI program. This parameter is optional.
GROUP-NAME The radio button group_name field. This parameter is required.
SELECTED Name of the default button to turn on. If not specified, the first item is the default. Specify the minus sign (-) if you don't want any button to be turned on. This parameter is optional.
VERTICAL If True, places line breaks between the radio buttons so that they appear as a vertical list. If this argument is undefined or False, the radio buttons are strung together on a horizontal line.

When the form is processed, you can retrieve the selected radio button by using this code:

$which_radio_button = $query->param('group_name');

Creating a Submit Button

The method

submit('NAME', 'VALUE')

creates the Query Submission button. Every Web fill-out form that has more than one text-entry field or any other input type should have a Submit button. Use this code:

print $query->submit('button_name','value');

Table 8.11 explains the parameters of the submit() function.

Table 8.11. The submit() parameters.

NameMeaning
NAME You can give the button a name if you have several submission buttons on your form and you want to distinguish between them. The name also is used as the user-visible label. This parameter is optional.
VALUE This gives the button a value that is passed to your script in the query string. You can figure out which button was pressed by using different values for each button. This parameter is optional.

You can retrieve the value of the Submit button by using this code:

$which_one = $query->param('button_name');

Creating a Reset Button

The method

reset('LABEL')

creates the Reset button. It undoes whatever changes the user has recently made to the form, but it does not necessarily reset the form all the way to the defaults. (See the next section, "Creating a Defaults Button," for that.) This method takes an optional LABEL argument. If set, LABEL defines the visible name of the Reset button, which is Reset by default. Use this code:

print $query->reset

Creating a Defaults Button

The defaults('LABEL') method creates a Reset to Defaults button. It takes the optional label for the button, which is Default by default. When the user clicks this button, the form is set to the defaults you specify in your script, just as it was the first time it was called. Use this code:

print $query->defaults('button_label')

Creating a Hidden Field

The method

hidden('NAME', VALUE(1), ... VALUE(N))

produces a text field that can't be seen by the user. It is useful for passing state variable information from one invocation of the script to the next. Use this code:

print $query->hidden('hidden_name','hidden_value1','hidden_value2'...);

Table 8.12 explains the parameters of the hidden() function.

Table 8.12. The hidden() parameters.

NameMeaning
NAME The name of the hidden field. This parameter is required.
VALUE The second and subsequent arguments specify the value for the hidden field.

The hidden() method is a quick-and-dirty way of passing Perl arrays through forms

Note
As of version 1.52, the default values always override the current values in hidden variables. This is different from the behavior of all the other form fields, where the current value overrides the default value, but it seems to be the way that people expect things to work.

You can retrieve the value of a hidden field with this code:

$hidden_value = $query->param('hidden_name');

Or, for values created with arrays, you can use this code:

@hidden_values = $query->param('hidden_name');

Creating a Clickable Image Button

The method

image_button('NAME', 'SRC', 'ALIGN')

produces an inline image that acts as a Submission button. When selected, the form is submitted and the clicked (x,y) coordinates are submitted as well. Use this code:

print $query->image_button('button_name','/source/URL','MIDDLE');

Table 8.13 explains the parameters of the image_button() function.

Table 8.13. The image_button() parameters.

NameMeaning
ALIGN Alignment option: TOP, BOTTOM, or MIDDLE. This parameter is optional.
NAME Name of the image button. This parameter is required.
SRC Specifies the URI of the image to display. It must be one of the types supported by inline images (GIF, for example) but can be any local or remote URI. This parameter is required.

After the image is clicked, the results are passed to your script in two parameters named "button_name.x" and "button_name.y", where "button_name" is the name of the image button:

$x = $query->param('button_name.x');
$y = $query->param('button_name.y');

Controlling HTML Autoescaping

By default, if you use a special HTML character-such as >, <, or &amp-as the label or value of a button, it is escaped using the appropriate HTML escape sequence (for example, &amp;gt;). This process enables you to use anything at all for the text of a form field without worrying about breaking the HTML document. However, it also might interfere with the capability to use special characters-such as &Aacute;-as the default contents of fields. You can turn this feature on and off with the method autoEscape('ON/OFF'), as shown in this code:

$query->autoEscape(undef);  turns automatic HTML escaping OFF.
$query->autoEscape('true');   turns automatic HTML escaping ON.

Using the CGI Library for C Programmers: cgic

cgic is an ANSI C-language library for the creation of CGI-based World Wide Web applications. cgic is included in this chapter with the permission of Thomas Boutell (<boutell@boutell.com>), and can be found at

http://sunsite.unc.edu/boutell/cgic/

cgic performs these tasks:

cgic should be compatible with any CGI-compliant server environment.

Writing a cgic Application

Note
All cgic applications must be linked to the cgic.c module itself. How you do this depends on your operating system; under UNIX, just use the provided makefile as an example.

Because all CGI applications must perform certain initial tasks, such as parsing form data and examining environment variables, the cgic library provides its own main() function. When you write applications that use cgic, you begin your own programs by writing a cgiMain() function, which cgic invokes when the initial CGI work has been completed successfully. Your program also must be sure to include the file cgic.h.

Warning
If you write your own main() function, your program will not link properly. Your own code should begin with cgiMain(). The library provides main() for you.

Using String Functions

You can use this section as a quick-and-easy reference to learn about the various string functions.

cgiFormString

The cgiFormString() function retrieves the first argument (name) from the Web fill-out form and places the retrieved value into the result. Use this code:

cgiFormResultType cgiFormString(char *name, char *result, int max)

Table 8.14 explains the parameters of the cgiFormString function.

Table 8.14. The cgiFormString parameters.

ArgumentMeaning
max Maximum size of the result buffer. This size always should be one greater than the expected size of the input buffer, because a terminating null character is added to all result fields.
*name Name of the input field in the form. Usually, this is the Name attribute of the Web fill-out form input type.
*result Buffer for the requested form name. The text is copied into the buffer specified by result, up to but not exceeding max-1 bytes. A terminating null character then is added to complete the string.

Regardless of the newline format submitted by the browser, cgiFormString() always encodes each newline as a single line feed (ASCII decimal 10). As a result, the final string may be slightly shorter than indicated by a call to cgiFormStringSpaceNeeded but will never be longer.

cgiFormString() returns one of these status codes:

cgiFormStringMultiple

The cgiFormStringMultiple() function is useful in the unusual case in which several input elements in the form have the same name and, for whatever reason, the programmer does not want to use the checkbox, radio button, and selection menu functions. This is needed occasionally if the programmer cannot know in advance what values might appear in a multiple-selection list or group of checkboxes on a form. The value pointed to by the result is set to a pointer to an array of strings; the last entry in the array is a null pointer. This array is allocated by the CGI library. Use this code:

cgiFormResultType cgiFormStringMultiple(char *name, char ***ptrToStringArray)

Table 8.15 explains the parameters of the cgiFormStringMultiple() function.

Table 8.15. The cgiFormStringMultiple() parameters.

ArgumentMeaning
*name Name of the input field in the form. Usually, this is the Name attribute of the Web fill-out form input type; in this case, multiple fields with the same name value are expected.
***ptrToStringArray A pointer to an array of string pointers. This is the list of retrieved names. In all cases except when out of memory, ptrToStringArray is set to point to a valid array of strings, with the last element in the array being a null pointer; in the out-of-memory case, ptrToStringArray is set to a null pointer.

Warning
When you are done working with the array, you must call cgiStringArrayFree() with the array pointer as the argument; otherwise, you will have a memory leak.

cgiFormStringMultiple() returns one of these status codes:

cgiFormStringNoNewlines

The cgiFormStringNoNewlines() function is equivalent to cgiFormString(), except that any carriage returns or line feeds that occur in the input are stripped out. This function is recommended for single-line text input fields, because some browsers submit carriage returns and line feeds when they should not. See the section "cgiFormString," earlier in this chapter, for further information.

Use this code:

cgiFormResultType cgiFormStringNoNewlines(char *name, char *result, int max)

cgiFormStringSpaceNeeded

The cgiFormStringSpaceNeeded() function determines the length of the input text buffer needed to receive the contents of the specified input field. This is useful if the programmer wants to allocate sufficient memory for input of arbitrary length. The actual length of the string retrieved by a subsequent call to cgiFormString() may be slightly shorter but will never be longer than the returned *result parameter. Use this code:

cgiFormResultType cgiFormStringSpaceNeeded(char *name, int *length)

Table 8.16 explains the parameters of the cgiFormStringSpaceNeeded function.

Table 8.16. The cgiFormStringSpaceNeeded() parameters.

ArgumentMeaning
*length A pointer to the space allocated for the returned size of the input name.
*name Name of the input field in the form. Usually, this is the Name attribute of the Web fill-out form input type.

cgiFormStringSpaceNeeded() returns one of these status codes:

cgiStringArrayFree

The cgiStringArrayFree() function frees the memory associated with a string array created by cgiFormStringMultiple(). Use this code:

void cgiStringArrayFree(char **stringArray)

Note
**stringArray must be a pointer to an array of string pointers.

Using Numeric Functions

This section lists the various numeric functions. They are arranged in alphabetical order for easy reference.

cgiFormCheckboxMultiple

The cgiFormCheckboxMultiple() function determines which checkboxes among a group of checkboxes with the same name are checked. This is distinct from radio buttons (see the section "cgiFormRadio," later in this chapter). Use this code:

cgiFormResultType cgiFormCheckboxMultiple(char *name, char **valuesText,
  int valuesTotal, int *result, int *invalid)

Table 8.17 explains the parameters of the cgiFormCheckboxMultiple() function.

Table 8.17. The cgiFormCheckboxMultiple() parameters.

ArgumentMeaning
invalid Set to the number of invalid selections that were submitted, which should be 0 unless the form and the valuesText array do not agree.
*name Identifies the Name attribute of a group of commonly named checkbox elements.
*result Points to an array of integers with as many elements as there are strings in the valuesText array. For each choice in the valuesText array that is selected, the corresponding integer in the result array is set to 1; other entries in the result array are set to 0.
**valuesText Points to an array of strings identifying the Value attribute of each checkbox.
valuesTotal Indicates the total number of checkboxes.

cgiFormCheckboxMultiple() returns one of these status codes:

cgiFormCheckboxSingle

The cgiFormCheckboxSingle() function determines whether the checkbox with the specified name is checked. cgiFormCheckboxSingle() is intended for single checkboxes with a unique name. Use this code:

cgiFormResultType cgiFormCheckboxSingle(char *name)

cgiFormCheckboxSingle() returns one of these status codes:

cgiFormDouble

The cgiFormDouble() function attempts to retrieve the floating-point value sent for the specified input field. Use this code:

cgiFormResultType cgiFormDouble(char *name, double *result, double defaultV)

The value pointed to by result is set to the value submitted.

Table 8.18 explains the parameters of the cgiFormDouble() function.

Table 8.18. The cgiFormDouble() parameters.

ArgumentMeaning
defaultV When the status is empty, bad, or not found, the value stored in result is the value passed in the defaultV argument.
*name Name of the input field in the form. Usually, this is the Name attribute of the Web fill-out form input type.
*result A pointer to the location where the retrieved number should be stored.

cgiFormDouble() returns one of these status codes:

cgiFormDoubleBounded

The cgiFormDoubleBounded() function attempts to retrieve the number sent for the specified input field and constrains the result to be within the specified bounds. Use this code:

cgiFormResultType cgiFormDoubleBounded(char *name, double *result, double min,
  double max, double defaultV)

Table 8.19 lists the parameters of the cgiFormDoubleBounded() function.

Table 8.19. The cgiFormDoubleBounded() parameters.

ArgumentMeaning
defaultV When the status is empty, bad, or not found, the value stored in result is the value passed in the defaultV argument.
max The maximum value to be returned in result.
min The minimum value to be returned in result.
*name Name of the input field in the form. Usually, this is the Name attribute of the Web fill-out form input type.
*result A pointer to the location where the retrieved number should be stored.

cgiFormDoubleBounded() returns one of these status codes:

cgiFormInteger

The cgiFormInteger() function attempts to retrieve the integer sent for the specified input field. The value pointed to by the result is set to the value submitted. Use this code:

cgiFormResultType cgiFormInteger(char *name, int *result, int defaultV)

Table 8.20 explains the parameters of the cgiFormInteger() function.

Table 8.20. The cgiFormInteger() parameters.

ArgumentMeaning
defaultV When the status is not success, the value stored in result is the value passed in the defaultV argument.
*name Name of the input field in the form. Usually, this is the Name attribute of the Web fill-out form input type.
*result A pointer to the location where the retrieved integer should be stored.

cgiFormInteger() returns one of these status codes:

cgiFormIntegerBounded

The cgiFormIntegerBounded() function attempts to retrieve the integer sent for the specified input field and constrains the result to be within the specified bounds. Use this code:

cgiFormResultType cgiFormIntegerBounded(char *name, int *result, int min,
  int max, int defaultV)

Table 8.21 explains the parameters of the cgiFormIntegerBounded() function.

Table 8.21. The cgiFormIntegerBounded() parameters.

ArgumentMeaning
defaultV When the status is empty, bad, or not found, the value stored in result is the value passed in the defaultV argument.
max The maximum value to be returned in result.
min The minimum value to be returned in result.
*name Name of the input field in the form. Usually, this is the Name attribute of the Web fill-out form input type.
*result A pointer to the location where the retrieved integer should be stored.

cgiFormIntegerBounded() returns one of these status codes:

cgiFormRadio

The cgiFormRadio() function determines which, if any, of a group of radio buttons with the same name was selected. Use this code:

cgiFormResultType cgiFormRadio(char *name, char **valuesText, int valuesTotal,
  int *result, int defaultV)

Table 8.22 explains the parameters of the cgiFormRadio() function.

Table 8.22. The cgiFormRadio() parameters.

ArgumentMeaning
defaultV The value of result is set to the value of default if no radio button was checked or an invalid selection was made.
*name Identifies the Name attribute of a group of commonly named radio elements.
*result The value pointed to by result is set to the position of the actual choice selected within the valuesText array.
**valuesText Points to an array of strings identifying the Value attribute of each radio button.
valuesTotal Indicates the total number of radio buttons.

cgiFormRadio() returns one of these status codes:

cgiFormSelectMultiple

The cgiFormSelectMultiple() function retrieves the selection numbers associated with a Select element that allows multiple selections. Use this code:

cgiFormResultType cgiFormSelectMultiple(char *name, char **choicesText,
  int choicesTotal, int *result, int *invalid)

Table 8.23 explains the parameters of the cgiFormSelectMultiple() function.

Table 8.23. The cgiFormSelectMultiple() parameters.

ArgumentMeaning
**choicesText Points to an array of strings identifying each choice.
choicesTotal Indicates the total number of choices.
*invalid The integer pointed to by invalid is set to the number of invalid selections that were submitted, which should be 0 unless the form and the choicesText array do not agree.
*name Identifies the Name attribute of the Select element.
*result Points to an array of integers with as many elements as there are strings in the choicesText array. For each choice in the choicesText array that is selected, the corresponding integer in the result array is set to 1; other entries in the result array are set to 0.

cgiFormSelectMultiple() returns one of these status codes:

cgiFormSelectSingle

The function cgiFormSelectSingle() retrieves the selection number associated with a Select element that does not allow multiple selections. Use this code:

cgiFormResultType cgiFormSelectSingle(char *name, char **choicesText,
  int choicesTotal, int *result, int defaultV)

Table 8.24 explains the parameters of the cgiFormSelectSingle() function.

Table 8.24. The cgiFormSelectSingle() parameters.

ArgumentMeaning
**choicesText Points to an array of strings identifying each choice.
choicesTotal Indicates the total number of choices.
defaultV Result is set to the value of default if no selection was submitted or an invalid selection was made.
*name Identifies the Name attribute of the Select element.
*result Value pointed to by result is set to the position of the actual choice selected within the choicesText array.

cgiFormSelectSingle() returns one of these status codes:

Using Header Output Functions

Only one of the CGI Header functions-cgiHeaderLocation(), cgiHeaderStatus(), or cgiHeaderContentType()-should be invoked for each CGI transaction.

You call cgiHeaderLocation() to specify a new URI if the document request should be redirected. You call cgiHeaderStatus() if you want to respond to a request with an HTTP error status code and message; see the HTTP documentation for the legal codes. You usually call cgiHeaderContentType(), however, to specify the MIME type of the document (such as text/html); you then can output the actual document directly to cgiOut.

cgiHeaderContentType

The cgiHeaderContentType() function should be called if the programmer wants to output a new document in response to the user's request. This is the normal case. The single argument is the MIME document type of the response; typical values are text/html for HTML documents, text/plain for plain ASCII without HTML tags, image/gif for GIF images, and audio/basic for .au-format audio.

Use this code:

void cgiHeaderContentType(char *mimeType)

cgiHeaderLocation

The cgiHeaderLocation() function should be called if the programmer wants to redirect the user to a different URI. No further output is needed in this case. Use this code:

void cgiHeaderLocation(char *redirectUrl)

cgiHeaderStatus

The cgiHeaderStatus() function should be called if the programmer wants to output an HTTP error status message instead of a document. The status code is the first argument; the second argument is the status message to be displayed to the user. Use this code:

void cgiHeaderStatus(int status, char *statusMessage)

cgiMain

The programmer must write this function, which performs the unique task of the program and is invoked by the true main() function, found in the cgic library itself. The return value from cgiMain will be the return value of the program. It is expected that the user will make numerous calls to the cgiForm functions from within this function. See "Writing a cgic Application," earlier in this chapter, for details.

Use this code:

int cgiMain()

cgiSaferSystem

The cgiSaferSystem() function is a convenience function used to invoke the system() function less dangerously. That is, cgiSaferSystem() escapes the shell metacharacters ; and |, which can otherwise cause other programs to be invoked beyond the one intended by the programmer. However, understanding the shell commands you invoke and ensuring that you do not invoke the shell in ways that permit the Web user to run arbitrary programs is your responsibility. Use this code:

int cgiSaferSystem(char *command)

cgiWriteEnvironment and cgiReadEnvironment

These two functions are designed to work together:

The function cgiReadEnvironment() can be used to restore environments saved by the cgiWriteEnvironment() from the specified input file. Of course, these will work as expected only if you use the cgic copies of the CGI environment variables and cgiIn and cgiOut rather than STDIN and STDOUT. These functions are useful in order to capture real CGI situations while the Web server is running, and then to re-create them in a debugging environment.

Both functions return one of these status codes:

A cgic Variable Reference

This section provides a reference guide to the various global variables provided by cgic for the programmer to use. These variables always should be used in preference to STDIN, STDOUT, and calls to getenv() in order to ensure compatibility with the cgic CGI debugging features.

Most of these variables are equivalent to various CGI environment variables. The most important difference is that the cgic environment string variables are never null pointers. They always point to valid C strings of zero or more characters. Table 8.25 lists the environment string variables.

Table 8.25. cgic global environment string variables.

Name and FormatMeaning
char *cgiAccept Points to a space-separated list of MIME content types acceptable to the browser (see "cgiHeaderContentType") or an empty string. Unfortunately, this variable is not supplied by most current browsers. Programmers who want to make decisions based on the capabilities of the browser should check the cgiUserAgent variable against a list of browsers and capabilities instead.
char *cgiAuthType Points to the type of authorization used for the request, if any, or an empty string if none or unknown.
char *cgiContentType Points to the MIME content type of the information submitted by the user, if any; points to an empty string if no information was submitted. If this string is equal to application/x-www-form-urlencoded, the cgic library automatically examines the form data submitted. If this string has any other non-empty value, a different type of data has been submitted. This is currently very rare because most browsers can submit only forms, but if it is of interest to your application, the submitted data can be read from the cgiIn file pointer.
char *cgiGatewayInterface Points to the name of the gateway interface (usually CGI/1.1) or to an empty string, if unknown.
char *cgiPathInfo Most Web servers recognize any additional path information in the URI of the request beyond the name of the CGI program itself and pass that information on to the program. cgiPathInfo points to this additional path information.
char *cgiPathTranslated Points to additional path information translated by the server into a file system path on the local server.
char *cgiQueryString Contains any query information submitted by the user as a result of a Get method form or an Isindex tag. Note that this information does not need to be parsed directly unless an Isindex tag was used. It normally is parsed automatically by the cgic library. Use the cgiForm family of functions to retrieve the values associated with form input fields.
char *cgiRemoteAddr Points to the dotted-decimal IP address of the browser, if known, or an empty string if unknown.
char *cgiRemoteHost Points to the fully resolved host name of the browser, if known, or an empty string if unknown.
char *cgiRemoteIdent Points to the user name volunteered by the user via the user identification protocol; points to an empty string if unknown. This information is not secure. Identification daemons can be installed by users on unsecured systems such as Windows machines.
char *cgiRemoteUser Points to the user name under which the user has authenticated; points to an empty string if no authentication has taken place. The certainty of this information depends on the type of authorization in use; see char *cgi:AuthType.
char *cgiRequestMethod Points to the method used in the request (usually Get or Post) or an empty string if unknown (this should not happen).
char *cgiScriptName Points to the name under which the program was invoked.
char *cgiServerName Points to the name of the server or to an empty string if unknown.
char *cgiServerPort Points to the port number on which the server is listening for HTTP connections (usually 80) or an empty string if unknown.
char *cgiServerProtocol Points to the protocol in use (usually HTTP/1.0) or to an empty string if unknown.
char *cgiServerSoftware Points to the name of the server software or to an empty string if unknown.
char *cgiUserAgent Points to the name of the browser in use or an empty string if this information is not available.
FILE *cgiIn Points to CGI input. In 99 percent of cases, you will not need this. However, in future applications, documents other than form data are posted to the server, in which case this file pointer may be read from in order to retrieve the contents.
FILE *cgiOut Points to CGI output. The CGI Header functions, such as cgiHeaderContentType, should be used first to output the MIME headers. The output HTML page, GIF image, or other Web document then should be written to cgiOut by the programmer using standard C I/O functions such as fprintf() and fwrite(). cgiOut normally is equivalent to STDOUT. However, it is recommended that cgiOut be used to ensure compatibility with future versions of cgic for specialized environments.
int cgiContentLength The number of bytes of form or query data received. Note that if the submission is a form or query submission, the library reads and parses all the information directly from cgiIn and/or cgiQueryString. The programmer should not do so and, indeed, the cgiIn pointer will be at end-of-file in such cases.

Summary

In this chapter, you learned about three very useful existing libraries on the Net: cgi-lib.pl, CGI.pm, and cgic. You should be able to put these libraries to regular use, saving yourself countless hours of time reinventing existing applications. I hope that you have the opportunity to return to this chapter many times in the future for use as a valuable reference tool.


Listing 8.7. Using self-referencing URLs to jump to internal links.

01: #!/usr/local/bin/perl
02:
03: use CGI;
04: $query = new CGI;
05:
06: # We generate a regular HTML file containing a very long list
07: # and a pop-up menu that does nothing except to show that we
08: # don't lose the state information.
09: print $query->header;
10: print $query->start_html("Internal Links Example");
11: print "<H1>Internal Links Example</H1>\n";
12:
13: print "<A NAME=\"start\"></A>\n"; # an anchor point at the top
14:
15: # pick a default starting value;
16: $query->param('amenu','FOO1') unless $query->param('amenu');
17:
18: print $query->startform;
19: print $query->popup_menu('amenu',[('FOO1'..'FOO9')]);
20: print $query->submit,$query->endform;
21:
22: # We create a long boring list for the purposes of illustration.
23: $myself = $query->self_url;
24: print "<OL>\n";
25: for (1..100) {
26:     print qq{<LI>List item #$_<A HREF="$myself#start">Jump to top</A>\n};
27: }
28: print "</OL>\n";


Listing 8.8. Saving state information to a file.

01: use CGI;
02: $query = new CGI;
03:
04: print $query->header;
05: print $query->start_html("Save and Restore Example");
06: print "<;H1>Save and Restore Example<;/H1>\n";
07:
08: # Here's where we take action on the previous request
09: &save_parameters($query)              if $query->param('action') eq 'save';
10: $query = &restore_parameters($query)  if $query->param('action') eq
  'restore';
11:
12: # Here's where we create the form
13: print $query->startform;
14: print "Popup 1: ",$query->popup_menu('popup1',
 ['eenie','meenie','minie']),"\n";
15: print "Popup 2: ",$query->popup_menu('popup2',['et','lux','perpetua']),"\n";
16: print "<;P>";
17: print "Save/restore state from file: ",$query->textfield('savefile',
 'state.sav'),"\n";
18: print "<;P>";
19: print $query->submit('action','save'),$query->submit('action','restore');
20: print $query->submit('action','usual query');
21: print $query->endform;
22:
23: # Here we print out a bit at the end
24: print $query->end_html;
25:
26: sub save_parameters {
27:     local($query) = @_;
28:     local($filename) = &clean_name($query->param('savefile'));
29:     if (open(FILE,">$filename")) {
30:      $query->save(FILE);
31:      close FILE;
32:      print "<;STRONG>State has been saved to file $filename<;/STRONG>\n";
33:     } else {
34:      print "<;STRONG>Error:<;/STRONG>
  couldn't write to file $filename: $!\n";
35:     }
36: }
37:
38: sub restore_parameters {
39:     local($query) = @_;
40:     local($filename) = &clean_name($query->param('savefile'));
41:     if (open(FILE,$filename)) {
42:      $query = new CGI(FILE);
 # Throw out the old query, replace it with a new one
43:      close FILE;
44:      print "<;STRONG>State has been restored from file
  $filename<;/STRONG>\n";
45:     } else {
46:      print "<;STRONG>Error:<;/STRONG> 
 couldn't restore file $filename: $!\n";
47:     }
48:     return $query;
49: }
50:
51:
52: # Very important subroutine - get rid of all the naughty
53: # metacharacters from the file name. If there are, we
54: # complain bitterly and die.
55: sub clean_name {
56:    local($name) = @_;
57:    unless ($name=~/^[\w\.-]+$/) {
58:       print "<;STRONG>$name has naughty characters.  Only ";
59:       print "alphanumerics are allowed.  You can't use absolute
  names.<;/STRONG>";
60:       die "Attempt to use naughty characters";
61:    }
62:    return $name;
63: }

Q&A

Q
Are there other libraries?
A
Yes, of course. One set of libraries still is being developed, but it should be ready by the time you read this book. The libraries are Perl 5 modules called CGI::*. The current development set of modules are Base.pm, Request.pm, Form.pm, URL.pm, and MiniSrv.pm. You can learn more about these modules at
http://www-genome.wi.mit.edu/WWW/tools/scripting/CGIperl
Q
I can't maintain the state of my form because I have internal links that cause the state of my form to be reset. What should I do?
A
A partial solution is to use the self_url() method to generate a link that preserves state information. Try the script shown in Listing 8.7, which is distributed with the CGI.pm library.
Q
How do I save data to a form using the CGI.pm library and use it later?
A
This script is part of the CGI.pm distribution, and it is included here in Listing 8.8. It saves its state to a file of the user's choosing after the Save button is clicked and restores its state after the Restore button is clicked. Notice that it's very important to check the filename for shell metacharacters so that the script doesn't inadvertently open up a command or overwrite someone's file. In order for this to work, the script's current directory must be writable by
"nobody".#!/usr/local/bin/perl