Previous Page TOC Index Next Page See File


8

Using Existing CGI Libraries

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 on which library or libraries best suit your needs and then download them from the resources identified. Usually, you will want to install them into your cgi-bin directory. Make sure that you check with your Web Master 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 library is the smallest library you will learn about in this chapter. However, don't discard it from your toolbox just because it is small. 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 with 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 by 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. The MethGet function in its entirety is shown in Listing 8.1.

sub MethGet {
  return ($ENV{'REQUEST_METHOD'} eq "GET");
}

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. The ReadParse function is included in Listing 8.2.

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) and is included in Listing 8.3.

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

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>).

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.

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 correctly, and correctly 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 and is included in Listing 8.6.

use CGI;
$query = new CGI;
print $query->header;
print $query->startform;
print "What's your name? ",$query->textfield('name');
print "<P>What's the combination? ",
        $query->checkbox_group('words',['eenie','meenie','minie','moe']);
print "<P>What's your favorite color? ",
        $query->popup_menu('color',['red','green','blue','chartreuse']);
print "<P>",$query->submit;
print $query->endform;
print "<HR>\n";
if ($query->param) {
    print "Your name is <EM>",$query->param('name'),"</EM>\n";
    print "<P>The keywords are: <EM>",join(", ",$query->param('words')),"</EM>\n";
    print "<P>Your favorite color is <EM>",$query->param('color'),"</EM>\n";
}

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 the following:

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

There are two methods in the CGI.pm library that can be used for reading data passed to your CGI program:

Saving Your Incoming Data

Your incoming data should be saved into 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 backwards 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 name space. 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 name space, 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, as evil people then could use this feature to redefine central variables such as @INC. CGI.pm exits with an error if you try to do this.

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 provide means for saving 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 file handle of your choice. The file handle already must be open and be 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 at a later time. 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, simply remaining 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 when a user clicks on an empty part of a clickable image map.)

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 URL. 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 lists all the parameters of the start_html method, which are optional.

Name

Meaning

ATTRIBUTE-LIST

Any additional attributes you want to incorporate into the HEAD tag (as many as you like). This is a good way to incorporate Netscape-specific extensions, such as background color and wallpaper pattern. (The example in this section sets the page background to a vibrant blue.)

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 with care!

EMAIL-ADDRESS

The author's e-mail address (creates a <LINK REV="MADE"> tag).

TITLE

The title string to use for the HTML header.

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.

If you want to reset the fields to their defaults, you can do the following:

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 your ability 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 the following 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 URL to call. If you want the browser to call a different URL to handle the search, pass isindex('TGT-URI') the URL 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 lists the parameters of the startform() function.

Name

Meaning

HTTP-METHOD

The method the data sends to the server; it can be either 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 lists the parameters of the textfield() function.

Name

Meaning

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 Text-Area 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. Scroll bars for both the horizontal and vertical scrolling are added automatically. Use this code:

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

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

Name

Meaning

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->pasword_field('foo','starting value',50,80);

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

Name

Meaning

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 lists the parameters of the popup-menu() function.

Name

Meaning

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 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-VALUE 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 the following 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 lists the parameters of the scrolling_list() function.

Name

Meaning

LIST-SIZE

Number of visible list items. If undefined, the default is one. This parameter is optional.

MULTIPLE-SELECTIONS

If True, then 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 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-VALUE 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, then 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'. The values of the selected items can be retrieved with the following 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 lists the parameters of the checkbox_group().

Name

Meaning

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 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-VALUE 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, then nothing is selected when the list first appears. This parameter is optional.

VERTICAL

If True, then place 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.

The values of the "on" checkboxes can be retrieved 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 lists the parameters of the checkbox() function.

Name

Meaning

CGI-VALUE

Value passed to your CGI program when the checkbox is selected. If not provided, the word "on" is assumed. This parameter is optional.

NAME

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.

The value of the checkbox can be retrieved by using the following 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 lists the parameters of the radio_group() function.

Name

Meaning

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 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 is sent as the OPTION-VALUE 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 "-" if you don't want any button to be turned on. This parameter is optional.

VERTICAL

If True, then place 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, the selected radio button can be retrieved by using the following 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 lists the parameters of the submit() function.

Name

Meaning

NAME

You can give the button a name if you have several submission buttons in 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 one. This parameter is optional.

The value of the Submit button can be retrieved 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 section "Creating a Defaults Button" for that.) It 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 lists the parameters of the hidden() function.

Name

Meaning

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 "sticky" 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.

Fetch the value of a hidden field this way:

    $hidden_value = $query->param('hidden_name');
            -or (for values created with arrays)-
    @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 lists the parameters of the image_button() function.

Name

Meaning

ALIGN

Alignment option: TOP, BOTTOM, or MIDDLE. This parameter is optional.

NAME

Name of the image button. This parameter is required.

SRC

Specifies the URL 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 URL. This parameter is required.

When 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 (&amp;gt;, for example). 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 your ability 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 the following 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 lists the parameters of the cgiFormString function.

Argument

Meaning

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 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[ms]1 bytes. A terminating null 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.

The function cgiFormString() returns the following 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 lists the parameters of the cgiFormStringMultiple() function.

Argument

Meaning

*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.

The function cgiFormStringMultiple() returns the following status codes:

cgiFormStringNoNewlines

The cgiFormStringNoNewlines() function is exactly equivalent to cgiFormString(), except that any carriage returns or line feeds that occur in the input are stripped out. The use of 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 for further information. Use this code:

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

The cgiFormStringSpaceNeeded() function is used to determine 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 returned *result parameter. Use this code:

cgiFormResultType cgiFormStringSpaceNeeded(char *name, int *length)

Table 8.16 lists the parameters of the cgiFormStringSpaceNeeded function.

Argument

Meaning

*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.

The function cgiFormStringSpaceNeeded() returns the following status codes:

cgiStringArrayFree

The cgiStringArrayFree() function is used to free 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"). Use this code:

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

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

Argument

Meaning

invalid

Set to the number of invalid selections that were submitted, which should be zero 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.

The function cgiFormCheckboxMultiple() returns the following status codes:

cgiFormCheckboxSingle

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

cgiFormResultType cgiFormCheckboxSingle(char *name)

The function cgiFormCheckboxSingle() returns the following 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 lists the parameters of the cgiFormDouble() function.

Argument

Meaning

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.

The function cgiFormDouble() returns the following 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.

Argument

Meaning

defaultV

When the status is empty, bad, or not found, the value stored in result is the value passed in the defaultV argument.

max

Maximum value to be returned in result.

min

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.

The function cgiFormDoubleBounded() returns the following 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 lists the parameters of the cgiFormInteger() function.

Argument

Meaning

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 the following 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 lists the parameters of the cgiFormIntegerBounded() function.

Argument

Meaning

defaultV

When the status is empty, bad, or not found, the value stored in result is the value passed in the defaultV argument.

max

Maximum value to be returned in result.

min

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.

The function cgiFormIntegerBounded() returns the following status codes:

cgiFormRadio

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

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

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

Argument

Meaning

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.

The function cgiFormRadio() returns the following 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 lists the parameters of the cgiFormSelectMultiple() function.

Argument

Meaning

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 zero 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.

The function cgiFormSelectMultiple() returns the following 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 lists the parameters of the cgiFormSelectSingle() function.

Argument

Meaning

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.

The function cgiFormSelectSingle() returns the following status codes:

Using Header Output Functions

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

Call the first function, cgiHeaderLocation(), to specify a new URL if the document request should be redirected. Call the second function, 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. Call the third function, cgiHeaderContentType(), in the normal case, in order 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 a GIF image, 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 URL. 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 code 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 how to write a cgic application 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 meta characters ";" 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 own 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 re-create them in a debugging environment.

Both functions return the following:

A cgic Variable Reference

This section provides a reference guide to the various global variables provided by cgic for the programmer to utilize. 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.

Name and Format

Meaning

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 are advised to 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; 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 URL 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 need not 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; an empty string if unknown. This information is not secure. Identification daemons can be installed by users on insecure systems such as Windows machines.

char *cgiRemoteUser

Points to the user name under which the user has authenticated; an empty string if no authentication has taken place. The certainty of this information depends on the type of authorization in use; see "cgiAuthType()".

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

Pointer 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

Pointer 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 you have the opportunity to return to this chapter many times in the future for use as a valuable reference tool.

Q&A

Q: Are there other libraries?

A: Yes, of course. One set of libraries is still being developed but they should be ready by the time you read this book. They 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.

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";

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 is included here in Listing 8.8. It saves its state to a file of the user's choosing when the Save button is clicked and restores its state when the Restore button is clicked. Notice that it's very important to check the file name for shell meta characters so that the script doesn't inadvertently open up a command or overwrite someone's file. For this to work, the script's current directory must be writable by

"nobody".#!/usr/local/bin/perl
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: }

Previous Page TOC Index Next Page See File