Previous Page TOC Index Next Page See File


5

Decoding the Data Sent to Your CGI Program

In the last chapter, you saw how your Web page data was encoded and transferred from your browser/client software to the server software. It's good to know how the data gets to you, but you've got to be able to use that data once it gets to your CGI program. In this chapter, you continue learning about the HTML Form Input tag and focus on using the data sent to your CGI program.

You will learn the following in this chapter:

Using the Post Method

In the last chapter, all the examples used the Get method to send your data to the server. Because the Get method is the default method, if your HTML Form tag didn't include the method type, everything would still work. For example,

<FORM method=get action="/cgi-bin/first.cgi">

has the same results as

<FORM action="/cgi-bin/first.cgi">

and you still would have the same limitations of the Get method. You learned about the limitations of the Get method in the last chapter:

Actually it's mostly the limitation on how much data can be sent that has moved the Internet community toward the Post method.

In the summer of 1995, the Post method became the method of choice for sending data across the Net. There was no formal vote taken. Common sense and practical application chose Post. And HTMLers and CGIers started telling each other, "Hey, use the Post method!"

With the Post method, the data input on your Web page form is available for reading on the STDIN file handle.


Note: STDIN, STDOUT, and STDERR are part of Perl's special variables. Perl uses lots of special variables to make your programming tasks easier, and I will discuss most of the CGI relevant ones in this book. If you're familiar with C or almost any programming language that works with the Unix environment, STDIN, STDOUT, and STDERR are already well known to you. If not then, here is a brief introduction to them.

STDIN is read as standard in, STDOUT is read as standard out, and STDERR is read as standard error.

When you open a file for reading or writing, you assign the name of the file (file name) you are opening to a variable referred to as a file handle. Your program will reference the file handle instead of the actual file name whenever it wants to read from or write to that file. Unix/C/Perl treats every piece of the computer like a file. So once you learn how to work with files, you have a good start on leaning how to work with the other parts of the computer.

STDIN, STDOUT, and STDERR are three file handles that are preset for reading and writing from your computer terminal. The writing or output goes to your computer screen. Perl treats this just like another file. The reading or input comes from your computer keyboard.

STDOUT and STDERR are for writing. Both these file handles normally write to your computer screen.

STDIN normally is associated with keyboard input but, for CGI, when your data is passed to the server using the POST method, it is available for reading from STDIN.

You can adjust what STDIN, STDOUT, and STDERR write to or read from by assigning them new values in your program. This is how your POST data becomes available on STDIN.

You can change where the print function sends its output by setting STDOUT to a file handle you open earlier in your program.

There is no limit to the amount of data that can be passed to your CGI program on the STDIN file handle and no limits is what the Net is all about. Your program keeps reading data from this file handle until it has read everything defined by the content-length request header.

In the next section, you will examine how your data is read from the STDIN file handle.

After your CGI program reads the data from the STDIN file handle, it must decode those name/value pairs covered in Chapter 4, "Using Forms to Gather and Send Data." There are some marvelous existing functions for decoding data available on the Net. In this chapter, I use the ReadParse function, which is part of the cgi-lib.pl library, written by Steven E. Brenner, to fully discuss decoding URI-encoded data using Perl.

To send this data to your CGI program, I introduce the radio button and the checkbox. These Input types are useful in building professional-looking Web page forms.

Using Radio Buttons in Your Web Page Forms and Scripts

So far, your Web page forms have been relatively simple. Your Web page users have only been able to enter data in text-entry windows. It's amazing how powerful a user interface you can build with just the HTML Form tag and a few different Input types.

By just changing the input type to Radio, you get a working clickable button on your form. Radio buttons add more power to your Web page forms, providing an easy mechanism for your customers to make choices.

The HTML Radio Button Format

The radio button is designed to allow a choice among several mutually exclusive options. In other words, only one choice is valid at a time. Figure 5.1 is an example in which only one choice is valid among several possible options.


Figure 5.1. A computer selection example.

The radio button is part of the HTML INPUT tag. It is a field of the Type attribute.

The radio button INPUT type's syntax is similar to the Submit button:

<INPUT TYPE=RADIO NAME="computer" VALUE="Pentium 90">

Tip: The double quotation marks you may see around differing HTML tags are necessary only if there is more than one word on the right-hand side of the equal sign (=). So in this example, quotation marks are unnecessary except in the Value field. In the Value field, I use two words "Pentium 90" to define the value as shown here:

<INPUT TYPE=RADIO NAME="computer" VALUE="Pentium 90">

If the double quotation marks were not used, only the Pentium portion of the value would be associated with this radio button.

By the way, double quotation marks don't hurt. You can use them at all times if you want.

The Name Attribute

The Name/Value attributes of the radio button are not optional. Unlike the Submit button, this INPUT type just wont work without a name and a value.

The radio button is different from the Submit option because the Submit button's main function is initiating the data transfer. The radio button's function is sending the selected data to your CGI program.

You must include the Value field and assign data to the Value field. Otherwise, there would be no "value" to send along with the radio button Name field. This guarantees that your CGI program will receive data from a radio button group.

Notice in Figure 5.1 that there are two rows of radio buttons. Each row is a radio button group. A radio button group defines for your browser a set of radio buttons that work together. When one is selected, the others are unselected. So each new selection turns off the previous selection and selects the new "clicked" radio button.

A radio button group is defined based on the name given to each button. It's possible to have the same radio button group scattered all over your Web page form. This is possible, but not recommended. You want your radio buttons to be visually connected as well as programatically connected. Remember this when you design your form. If your form is very long and your radio buttons are in a list, some of the buttons might get scrolled off the screen and confuse your client.

To make your radio buttons work as a group, you must give each radio button in the group the same name. On the form shown in Figure 5.1, for example, all the name/value pairs that make up the monitor group have the same name, monitor. You can see this in Listing 5.1, which is the HTML for Figure 5.1.

<html>
01: <head>
02: <title>Custom Computer Systems for Austin, Texas by ACCN </title>
03: </head>
04: <body>
05: <center>
06: <form method="post" action="cgi-bin/accn_sys.cgi/systems/">
07: <table border=10>
08: <th> <h3> Choose from one of <br>our standard configurations </h3>
09: <tr> <td>
10: Pentium 100 <input type="radio"  name="system" value="P100" >
11: Pentium 75 <input type="radio" name="system" value="P75" checked >
12: Pentium 60 <input type="radio" name="system" value="P60" >
13: 486 DX2 66 <input type="radio" name="system" value="486d66" >
14: <tr> <td>
15: 17 Inch Monitor  <input type="radio" name="monitor" value="17inch" >
16: 15 Inch Monitor  <input type="radio" name="monitor" value="15inch" checked >
17: 14 Inch Monitor  <input type="radio" name="monitor" value="14inch" >
18: <tr> <td>
19: Multimedia? <input type="checkbox" name="sound" value="true" checked>
20: Modem? <input type="checkbox" name="modem" value="true" checked>
21: <tr> <td>
22: <input type="submit" value="Get Current Price">
23: <input type="reset">
24: <tr> </table> </form> </center>
25: <hr noshade>
26:  [ <A HREF="http://www.accn.com">
27:   <img alt="Austin Computer Center "
28:   src="home.gif" border=1 A>  |
29:   <A HREF="pindex.htm"> Parts Index   </A>   |
30: </body>
31: </html>

Lines 10 through 13 make up the first set of radio buttons. Notice that all the "names" are the same and that the value is something other than the visible HTML. The values are easy to remember and to perform comparisons against in your Perl code. Also notice that in line 11, the Pentium 75 is defaulted to Selected by the Checked attribute. With the selections shown in Figure 5.1, it returns the Web page shown in Figure 5.2.


Figure 5.2. A Web page returned from selections in Figure 5.1.

The Value Attribute

The Value attribute defines the data that will be sent to your CGI program. Only the selected radio button's Value field will be sent to your CGI program.

There is no reason to make what appears on your Web page as a selectable radio button and the Value field the same text strings. This gives you the freedom to make nice descriptive selectable radio button names on your Web page and more programatically useful radio button names in your Value fields. You can see examples of this in Listing 5.1.

Each Value field in a radio button group must be different. If any of the Value fields are the same in a radio name group, your CGI program will not be able to figure out which radio button was selected.

The Checked Attribute

The only optional attribute of the Input type Radio is the Checked attribute. The Checked attribute defines which radio button in a radio button group is the default radio button. The default radio button appears selected or colored in on your Web page form. One and only one of the radio buttons in each radio button group should be defined as the default radio button, by including the Checked attribute.

Radio Button Rules

The radio button follows a specific set of rules, as outlined here:

Finally, a bit of formatting advice for your radio buttons. If you use a table like the one in Figure 5.1, be careful how you place your radio buttons.

With radio buttons lined up in a row, it can be confusing which item is being selected. I like to place my radio buttons first, and then the text that describes the button. You don't have to follow this convention; just remember to be consistent in placing the button and then text or text and then button throughout your entire form.

Reading and Decoding Data in Your CGI Program

Let's use the Get method to send data to your CGI program one more time. Ignoring all of my previous complaints is okay, as long as it has a purpose, and, in this case, you need a good example to fully explain decoding your input data. Refer to Figure 5.2, which shows the returned Web page; later in this chapter, I'll repeat this example using the Post method.

Obviously, just to begin to return the data in Figure 5.2, I had to be able to decode the incoming data. Using the Get method, the data is available for my CGI program in the Environment variable QUERY_STRING.

However, all the incoming data is URI encoded, so before it can be used, it has to be decoded. "Eric," you say, "NO PROBLEM; I learned all about encoding data in the last chapter, so decoding data should be easy!" Well, actually you're right! Decoding is easy. But mostly because someone else already has figured out how to make it easy for you.

I don't like doing extra work! I usually have enough to do already. So I look for ways to save my time and effort. cgi-lib.pl, written by Steven E. Brenner, is one of those nice labor-saving devices. Using Steve's code—which he very kindly distributes freely on the Net—makes my coding tasks much easier. I can concentrate on writing the application and use Steve's code to do the decoding.

The code written by Steve E. Brenner is in a file called cgi-lib.pl, and often is referred to as a library of code, because it performs several useful functions. This library is covered again in Chapter 8, "Using CGI Libraries," where you will take a look at several useful Net libraries.

Inside the cgi-lib.pl Perl library is a very useful function called ReadParse. It does your decoding work for you. In the next section, you will learn how ReadParse decodes your data, and you will get a firm introduction to the Perl language that is used in ReadParse. You'll learn about Perl's variable-naming conventions. How the QUERY_STRING is separated into name/value pairs. Looping constructs and the $# variable. The Perl split function. The Perl substitute function. And even Perl's associative arrays. I can't give you all the details of a Perl book, but I can teach you enough to make you dangerous!

Using the ReadParse Function

The Perl code in Listing 5.2 is the ReadParse function of the very useful Perl library cgi-lib.pl. You can use most of the functions in cgi-lib.pl directly with just a little bit of effort and understanding. The ReadParse function is explained in detail here so you can learn about decoding incoming data. The ReadParse function separates the input form data into name/value pairs and decodes the URI-encoded data.

Not only is ReadParse an excellent tool for you to use in your CGI programs, but it also provides an excellent programming example for introducing several Perl-related topics.

Before you begin with ReadParse, I have included a program fragment that prints out Environment variables. The output from the program in Listing 5.2 is shown in Figure 5.3. This output is part of the input data to the ReadParse function and should help you follow along through the next examples.

This next program fragment does exactly the same thing as line 13 of the ReadParse function in Listing 5.3, but doesn't use the variable names $in and @in. This fragment is part of another program that returns Environment variables to the client. The output is displayed in the lower portion of Listing 5.3. It first prints one variable at a time, showing you how each name value pair has been placed in a different location in the array (@my_query_string). Then line 7 prints the entire array without any HTML formatting. Finally, the encoded QEURY_STRING is printed.

01: @my_query_string = split(/&/,$ENV{'QUERY_STRING'});
02: foreach $index (0..$#my_query_string)
03: {
04:     print "$my_query_string[$index] <br>";
05: }
06: print "<br>";
07: print @my_query_string;
08: print "<br>";
09: print $ENV{'QUERY_STRING'};


Figure 5.3. The name value pairs of the query string.

Line 1 splits the environment variable QUERY_STRING into name/value pairs. This step also creates the array @my_query_string. Each name/value pair is one element of the array.

Line 2 uses the Perl foreach statement to step through each element of the array. The foreach statement is a loop construct that begins and ends with the {} characters. Each time through the loop, the variable $index is set to the next array element.

Line 4 prints the next element in the array. The variable $index is used to index through the array in the traditional numeric manner. Line 4 also outputs the <BR> statement, which is the HTML CRLF tag.

Line 6 prints the HTML CRLF tag <BR> to separate the data from the loop statement from the data printed on line 7. Line 7 prints the entire array, @my_query_string, of name=value pairs, without the extra formatting performed in the loop. Line 9 prints the unformatted QUERY_STRING.

Notice that the only visible difference between the QUERY_STRING and @my_query_string is the missing & between the variable names. However, the my_query_string is now in the Perl array format. That format enables me to decode the passed-in form data one name/value pair at a time.

If you are new to Perl, this is where you might start to realize the power of Perl. Most languages will make you write some type of loop construct to build a similar array structure. Perl creates and loads the array in one simple assignment statement.

Calling ReadParse is really easy. You call it using the standard Perl calling syntax:

&subroutine_name, &ReadParse(*return_value)

You pass in the parameter list the name of the variable you want ReadParse to return your data in i.e. (*variable-name).

# ReadParse
# Reads in GET or POST data, converts it to unescaped text, and puts
# one key=value in each member of the list "@in"
# Also creates key/value pairs in %in, using '\0' to separate multiple
# selections
# If a variable-glob parameter (e.g., *cgi_input) is passed to ReadParse,
# information is stored there, rather than in $in, @in, and %in.
01: sub ReadParse {
02:     local (*in) = @_ if @_;
03:
04:   local ($i, $loc, $key, $val);
05:
06:   # Read in text
07:   if ($ENV{'REQUEST_METHOD'} eq "GET") {
08:     $in = $ENV{'QUERY_STRING'};
09:   } elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
10:     read(STDIN,$in,$ENV{'CONTENT_LENGTH'});
11:   }
12:
13:   @in = split(/&/,$in);
14:
15:   foreach $i (0 .. $#in) {
16:     # Convert pluses to spaces
17:     $in[$i] =~ s/\+/ /g;
18:
19:     # Split into key and value.
20:     ($key, $val) = split(/=/,$in[$i],2); # splits on the first =.
21:
22:     # Convert %XX from HEX numbers to alphanumeric
23:     $key =~ s/%(..)/pack("c",hex($1))/ge;
24:     $val =~ s/%(..)/pack("c",hex($1))/ge;
25:
26:     # Associate key and value
27:     $in{$key} .= "\0" if (defined($in{$key})); # \0 is the multiple separator
28:     $in{$key} .= $val;
29:
30:   }
31:
32:   return 1; # just for fun
33: }

How does this code work and what is it supposed to do? Well, it makes your life a lot easier, remember, by decoding the data and separating that data out into name/value pairs and then placing those name/value pairs into an associative array. After it's in an associative array, your program can access the data by using the name portion of the name/value pair as an array index.

So how does it do this? It starts by figuring out where to go to get the data. So line 7,

if ($ENV{'REQUEST_METHOD'} eq "GET") {

checks to see what type of method was used to request the data. You're going to use the Get method first and then talk about the Post method.

Because you're using the Get method, line 8 is executed next. The line

$in = $ENV{'QUERY_STRING'};

copies the entire QUERY_STRING into a local variable $in. Remember that the server has created a bunch of Environment variables for you. The QUERY_STRING Environment variable has the input data from the Get method.

Creating Name/Value Pairs from the Query String

Now that the data is in a variable, you can begin making the data easier for your CGI program to use. So, the next thing is to separate the data into name/value pairs. Remember that name/value pairs are separated by the ampersand (&). You can see this in the location field of Listing 5.3, line 13:

@in = split(/&/,$in);

This line uses the Perl split function to separate the name value pairs in the $in variable into the array @in.

I have problems with line 13, and I understand Perl! The variable $in and the variable @in are two different variables. One ($in) is a scalar or, in this case, a string of characters. The other is an array (@in).

This might be clearer if the line was rewritten as the following:

@in = split(/&/,$ENV{'QUERY_STRING'}; 

If this confuses you also, take a moment to read the next note.


Note: One of the confusing yet powerful features of Perl is its capability to distinguish between variable names based on the beginning character of the variable. All variables in Perl begin with a $, @, or %. You also can use the ampersand (&) to begin subroutine calls. The asterisk (*) is a wild card and refers to any variable. Definitions for these variables follow:

The dollar sign ($) refers to strings or numbers. Perl figures out whether it is a string or number for you most of the time. In fact, the same variable can be used as both a string and a number in different context. If I try to add two numbers together, Perl is smart enough to add them like numbers. If I try to use the same number at a later place in my code as character or string data, Perl treats the variable like a string. Pretty cool, huh?!

The "at" sign @ refers to arrays indexed by numbers. These are the traditional programming language arrays.

The percent sign (%) refers to arrays indexed by strings. Perl refers to these as associative arrays. They are used extensively by many Perl programs, and there are special built-in functions, like the key function, to help you manage associative arrays. I'll use the key function in an example later in Chapter 6, "Using Environment Variable in Your Program," and give a full explanation of it then.

Decoding the Name/Value Pairs

Decoding the URI-encoded data is done between lines 15 through 30 of the ReadParse function shown in Listing 5.3. Notice that once the code has reached this point, it doesn't matter whether the data was sent via the Get or the Post method. Everything is in the variable @in.

Line 15,

foreach $i (0 .. $#in) {

begins a new loop block. The variable $i will be set to each of the integer values between zero and the last index of the @in array.

The $#in variable is interpreted by Perl to calculate the maximum subscript of the array @in. The $#array_name is a special variable of Perl. It always returns the maximum subscript value of the array. The maximum subscript value is different than the total number of elements in the array. The first array element starts a zero. So in a 10-element array, the maximum subscript is nine.

The { is the beginning of the loop BLOCK. The loop BLOCK is all the statements that will be associated with the loop—in this case, lines 15 through 30. The loop BLOCK is closed with an ending }.

Separating the Name/Value Pairs

Line 20 of Listing 5.3,

($key, $val) = split(/=/,$in[$i],2); 

finds the first occurrence of the equal sign, splits that into two fields, and assigns the results to variables $key and $val. That's an awful lot for one line with lots of Perl special syntax in it. So here's a detailed breakdown of line 20:

  1. The split function searches for a pattern in an input string. The pattern is defined between the two forward slashes. In this case, the pattern is = and the input string is the variable $in[$i].

  2. $in[$i] references one of the name/value pairs that were separated from the QUERY_STRING into the @in array on line 13. Remember that [$I] actually is being converted to

    [0], [1], ... [last_array_index]

    The $in tells Perl you want the contents of the @in array.

  3. The last part of the split function—,2);—tells the split function to create only two fields, regardless of how many patterns it finds. This splits the array element on the first equal sign (=) it finds. The left-hand side of the pattern match is put into the first variable, $key, and whatever is left goes into $val.

The split function has the following syntax:

split(/pattern/,$variable,field_limit)
Decoding the URI-Encoded Strings

Lines 23 and 24 of Listing 5.3 decode the contents of $key and $val. The substitute function looks for any embedded HEX values and converts them into the correct ASCII values.

Consider line 23:

$key =~ s/%(..)/pack("c",hex($1))/ge;
  1. The syntax of the substitute function is as follows: s/search_pattern/replace_pattern/.

  2. The search_pattern is a percent sign (%), followed by any two characters.

  3. The replace_pattern is the expression pack("c",hex($1)). This pack function interprets the "c", field as "convert to a signed character, whatever follows next." The hex($1) converts to a HEX value the matched fields from the search_pattern.

  4. The g at the end of the s///ge; is used to apply the search-and-replace rule to the entire variable. Otherwise, the pattern would be matched and replaced only once.

  5. The e at the end of the s///ge; tells Perl to evaluate the replace_pattern. Without the e, the search_pattern (a HEX value) would be replaced with "pack("c",hex($1))" instead of the results of the pack function.

  6. Finally, =~ is a special symbol that makes the substitute function operate using the variable on the left of the =~ as both the input variable to search on and the output to replace into.

Creating the Associative Array

Lines 27 and 28 of Listing 5.3 create the associative array, %in. Each reference to $in{} creates a new element in the associative array or adds to an existing element in the array. The magic is performed by using the curly braces, {}, which, in Perl, are used only to reference or create associative array elements.

These two lines have lots of Perl magic in them:

27:     $in{$key} .= "\0" if (defined($in{$key})); # \0 is the multiple separator
28:     $in{$key} .= $val;

The curly braces of an associative array are used here to both create and reference the associative array elements.

The first time a new element is assigned to an associative array, the element is created. So each new $key used in the associative array $in{$key} creates a new element for that new $key. The next time the same $key is used in the array, the previously created array element is referenced.

The addition of the new value is handled by the .= operator. This operator is shorthand for the normal string concatenate operation (new_string = string1 . string2). It is similar to the += operator of C. It takes the contents of the variable on the right-hand side of the operator and appends it to the contents of the variable on the left-hand side of the operator.

The final trick here is in line 27. The "\0" string separator is added only if the element $in{$key} is not the first $key of the array. This is done in the

if (defined($in{$key}));

part of line 27. The next line creates and or appends the $key value, whether or not it is the first $key in the array.

Exercise 5.1. Renaming ReadParse variables.

Even with all that explanation, the small subroutine shown in Listing 5.3 can be hard to follow, and the main problem is the reuse of the variable name "in". It works just fine because Perl understands that $, @, %, $var[], and $var{} all reference completely different variables. But it would be a lot less confusing and no less efficient if three variables with different names were used. Perl understands the difference without any problem, but it sure confuses me. I have rewritten the offending lines, shown here in Listing 5.4. I don't mean any offense to the author; I use this code unmodified and love it.

04:   local ($i, $loc, $name, $val);
08:     $my_query_string = $ENV{'QUERY_STRING'};
13:     @name_value_pairs = split(/&/,$my_query_string);
17:     $name_value_pairs[$i] =~ s/\+/ /g;
20:     ($name, $val) = split(/=/,$name_value_pairs[$i],2); # splits on the first =.
23:     $name =~ s/%(..)/pack("c",hex($1))/ge;
27:     $final_name_value_pair{$name} .= "\0"
             if (defined($final_name_value_pair {$name}));
28:     $final_name_value_pair{$name} .= $val;

This should help you see how the data is moving from one variable to another. This is only illustrative. I would have to do a little more work to make this completely correct. I haven't handled the Post function in my renaming of the variables $in and @in. But for the purposes of clarity, I hope this example helps.

Using the Post Method

The Perl code uses the same ReadParse function of the cgi-lib.pl, shown previously in program Listing 5.3, for decoding POST data. ReadParse uses the same instructions to decode the data passed to the server, but it needs to determine where to read the data from before it can read the data into its "in" array.

ReadParse does this on lines 6 through 11 of program Listing 5.1., repeated here as a program fragment (see Listing 5.5), by reading the REQUEST_METHOD environment variable on line 7. Because there are only two methods right now, this code could have been written without the check for the Post method in line 9. If HTTP Request Method is not Get, then it must be Post. But this code is written so that more methods can be added without changing the format. If the REQUEST_METHOD is Post, the data will be passed as part of standard input, after any HTTP request headers. Line 10 uses the Perl read function to get the data.

6:   # Read in text
07:   if ($ENV{'REQUEST_METHOD'} eq "GET") {
08:     $in = $ENV{'QUERY_STRING'};
09:   } elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
10:     read(STDIN,$in,$ENV{'CONTENT_LENGTH'});
11:   }

Using the Perl read Function

In order to get any data that comes from outside your CGI program, you must understand the read function. In the Unix world, any device you send data to or receive data from is treated like a file. This means that once you learn the method to read and write file input/output, you will understand how to write to any device you use.

In this case, you treat the input file stream from your Web browser like a file. The data comes in on STDIN, and you read from that predefined file handle.

So the only difference between the Get and Post method as far as ReadParse is concerned is where it gets the data. If it's the Get method, it's in the QUERY_STRING. If it's the Post method, the data is at the STDIN file handle.

Either way, the data is placed into the $in variable for further processing.

The Perl read function reads from a file into a variable you define, for the length of the input string:

read(READ-FROM-FILE HANDLE, READ-INTO, LENGTH-TO-READ)

Line 10 uses one of the Perl-defined file handles, STDIN. So the READ-FROM-FILE HANDLE is STDIN. The READ-INTO variable is $in, and the LENGTH-TO-READ is given in the environment variable 'CONTENT_LENGTH'. environment variables are covered again in Chapter 6.

Finally! We've gotten the data into our program and we can start doing something with it! So what are we going to do next? Well, let's use it!

Of course, nothing is ever that easy. There is some setup code you should know about so that you can use other libraries and functions in your CGI code. Without understanding the Perl push function and the @INC array, you won't be able to add new functions and those neat free Internet libraries to your code.

But after that setup, you actually can begin using the data passed by the radio buttons, so you'll learn how to get that data out of the associative array. Next, you need to learn about checkboxes. The way in which Checkbox data is sent to your CGI program is different, so I want to be sure you understand that difference. Along the way, you also will learn about some more Perl constructs, including the if, elsif statements.

Listing 5.6 contains the Perl code for generating the Web page shown in Figure 5.4. I use this real-world example to explain the concepts outlined earlier. Notice in line 4 the call to the ReadParse function. The ReadParse function reads the input data and then returns it in the variable *input.

01: #!/usr/local/bin/perl
02: push(@INC, "/cgi-bin");
03: require("cgi-lib.pl");
04: &ReadParse(*input);
05: #Determine the base price based on the system variable
06: if ($input{'system'} eq "486d66") {
07:       #set 486 only variables
08:       $computer_name = "486DX2-66";
09:       $price = 1099;
10:       $memory = 4;
11:       $video = "VLB";
12:       }
13: else {
14:      #not a 486 must be pentium system
15:      $computer_name = "Pentium";
16:      $memory = 8;
17:      $video = "PCI";
18:      $cache = "256K Cache" ;
19:      if ($input{'system'} eq "P100"){$price = 1799 ;$ptype = 100}
20:      elsif ($input{'system'} eq "P75"){$price =1550 ;$ptype = 75}
21:      elsif ($input{'system'} eq "P60"){$price = 1450;$ptype = 60}
22:      }
23: #add extra price for monitors over 14inch
24: $monitor = $input{'monitor'};
25: if ($input{'monitor'} eq "17inch"){$price += 650 ;}
26: elsif ($input{'monitor'} eq "15inch"){$price +=200 ;}
27: #add multimedia system
28: if (defined($input{'sound'})) {
29:    $price += 190;
30:    $multimedia="MultiMedia System";
31: }
32: #add 14.4 modem price
33: if (defined($input{'modem'})) {
34:    $price += 69;
35:    $modem="14.4 modem";
36: }
37: print &PrintHeader;
38: print<<"print_tag";
39: <html>
40: <head>
41: <title>$computer_name Systems from Austin Computer Center North </title>
42: </head>
43: <body>
44: <h1 align=center> Austin Computer Center North <br>Austin Texas! </h1>
45: <center>
46: <img src="/accn.jpg" align=left>
47: <table border=5>
48: <th colspan=2 align=center> <h2>
49: ${computer_name} $ptype for only \$$price
50: </h2>
51: <tr><td> <ul>
52: <li>$memory megs of Ram
53: <li>$cache
54: <li>Enhanced IDE In/Out Controller
55: <li>$monitor NIL SVGA Monitor
56: <li>1 Meg $video SVGA Video Card
57: <li> $multimedia
58: </ul>
59: <td> <ul>
60: <li>1.44 Floppy Drive
61: <li>500+ meg Hard Drive
62: <li>Mouse
63: <li>Windows 95
64: <li> $modem
65: </ul>
66: <tr>
67: <td align=right colspan=2> <h2> 1 YEAR WARRANTY PARTS & LABOR! </h2>
68: <tr>
69: </table>
70: </center>
</body>
</html>
print_tag

Including Other Files and Functions in Your CGI Programs

How do you include new libraries like cgi-lib.pl into your CGI programs? Well, you could just append them onto the end of every program you write. But that seems like way too much work. There's got to be a better way. And, anyway, how come some of these libraries already are available to my code from my server's CGI directory? Well, one of Perl's special variables, the @INC array, tells the Perl interpreter/compiler where to look for functions required by your code.

In line 2 of Listing 5.6, the Perl push function is used to add the path to the cgi-bin directory (/cgi-bin) to the @INC array. The push function adds values onto the end of an array (like a stack). The array increases in length by the size of the item added to the list.

The @INC array contains the list of places to search for Perl programs. It always starts with the default Perl directory and the current directory as search paths, and line 2 adds the cgi-bin directory to the end of the list of paths to search. You can move your personal paths to the front of the search path by using the following command instead of the push command:

unshift(@INC,/cgi-bin);

If you use

unshift(@INC,/cgi-bin);

then Perl will search first in the /cgi-bin directory for your programs before looking in the system directories or the current directory. Why would you want to do this? Usually, you move your personal directory to the top of the search list to make sure Perl uses your code instead of someone else's. Or maybe you just downloaded the latest revision to one of the libraries that your server has in the default directory. You want your code to use the latest revisions. If you leave the @INC array in its normal setup, the old version of the library will be used. You have to put your direct first in the search list to force Perl to use the newer code you just downloaded.

Line 3,

require("cgi-lib.pl");

tells Perl that your CGI program requires the Perl code in cgi-lib.pl in order to run. Perl searches the paths in the @INC directory for the file cgi-lib.pl and includes it in your program, compiling only the functions your program uses.

Using the Data Passed with Radio Buttons

Now you are going to start using the data passed to your CGI program by the Web page in Figure 5.1. Listing 5.7 repeats a fragment of the HTML so you will have it to refer to here as you work with it.

08: <th> <h3> Choose from one of <br>our standard configurations </h3>
09: <tr> <td>
10: Pentium 100 <input type="radio"  name="system" value="P100" >
11: Pentium 75 <input type="radio" name="system" value="P75" checked >
12: Pentium 60 <input type="radio" name="system" value="P60" >
13: 486 DX2 66 <input type="radio" name="system" value="486d66" >
14: <tr> <td>
15: 17 Inch Monitor  <input type="radio" name="monitor" value="17inch" >
16: 15 Inch Monitor  <input type="radio" name="monitor" value="15inch" checked >
17: 14 Inch Monitor  <input type="radio" name="monitor" value="14inch" >
18: <tr> <td>
19: Multimedia? <input type="checkbox" name="sound" value="true" checked>
20: Modem? <input type="checkbox" name="modem" value="true" checked>
21: <tr> <td>

There are two radio button variables and two checkbox button variables that you must deal with for the form shown in Figure 5.1 to work. You'll start working with just one radio button group name for now. You can see the other Radio button group names in Listing 5.7. The first radio button's name is System. You can get the value of System after passing the data to ReadParse. It returns the name/value pairs in the variable declared in line 4 as "*input". Remember that an asterisk (*) defines any type of Perl variable.

The values of "system" are in the associative array "input". One way you can tell it is an associative array is because the name is used as a lookup key. Line 6,

if ($input{'system'} eq "486d66")

checks the value of system against the 486d66 value defined in the form in line 13 of Listing 5.7. I use the Perl string compare "eq" and the "" around 486d66 because I am comparing strings and not numbers. From looking at Figure 5.1, you can see the input values should be a Pentium 75, with a 15-inch monitor, Multimedia, and modem system.


Tip: If you want to check what your input is to see whether your CGI program is working correctly, use the Perl command print %array;. In this case, that would translate to print %input. This prints the entire associative array, so that you can see the data passed to your CGI program. This method doesn't put any spaces between the name value pairs, but it does print all your variables in one easy call.

Using Perl's If Elsif Block

Now you are still working with the Perl code shown in Listing 5.6 and the data passed to your program from the radio button form. You have determined that the system type is not a 486d66.

Because the value of name is not equal to 486d66, you fail the first if check in line 6 of Listing 5.6 and move to the else block—everything enclosed between the beginning curly brace ({) in line 13 to the ending brace (})in line 22. I have repeated those lines here in the fragment in Listing 5.8.

13: else {
14:      #not a 486 must be Pentium system
15:      $computer_name = "Pentium";
16:      $memory = 8;
17:      $video = "PCI";
18:      $cache = "256K Cache" ;
19:      if ($input{'system'} eq "P100"){$price = 1799 ;$ptype = 100}
20:      elsif ($input{'system'} eq "P75"){$price =1550 ;$ptype = 75}
21:      elsif ($input{'system'} eq "P60"){$price = 1450;$ptype = 60}
22:      }

Because I only have to choose between the 486 and Pentium models, and it isn't a 486, it must be a Pentium. So now I can set all my Pentium required variables: the computer name, minimum memory, video type, and cache. You can see these variables in the title, main heading, and the list on the returned Web page in Figure 5.4. You can see how I use these variables in the HTML in lines 41, 49, 52, 53, 55, 57, and 64. Actually, generating Web pages on-the-fly and using variables isn't that hard!

I then use the if, elsif statements to figure out what type of Pentium it is. You don't have to worry about not getting your input fields set with radio buttons the way you do text entry-fields. With radio buttons, the "name" always will be set to some value. In this case, the result is a P75, so I set the base price and define the $ptype variable for use in the HTML generated from my CGI. Notice that if it is a 486 system, $ptype is never set. This means that when it is interpreted in my HTML, nothing will print and the 486 $computer_name defined in line 8 will look just fine.

I now have the base price to work from and start adding in the "extras." My extras are the radio button with the name Monitor and the checkboxes.

Using the HTML Checkbox

You still are processing the input data from the Computer Selection example in Figure 5.2. All that's left to do is deal with the checkbox input. Checkbox values are not like radio buttons. The data is passed to the server only if the checkbox is selected. This means you can check the %input array to see whether the name/value pair was sent to the server. Remember that if a checkbox is not selected, nothing is sent to the server for that name/value pair. So, in line 28,

if (defined($input{'sound'}))

I use the Perl defined function to check the associative array %input for a sound key. If there is a sound key, then the checkbox was selected.

The defined function checks to see whether a variable has been set at least once or has been declared in some other manner, such as the Perl local statement. Add the price for a sound system in line 29,

$price += 190;

and create the list element in line 30,

$multimedia = "MultiMedia System";

used on line 57.

Figure 5.4 shows the form used without selecting checkboxes and using the 486 variables. Notice that the list has bullets for blank lines. These are the checkboxes that didn't get selected and the undefined cache variable. Take time to look at the CGI program and see where these variables are defined. This is a powerful Perl feature. You can reference variables that are never set. If they are not set, they do not print anything, and they do not create an error, as they would in most traditional programming languages.


Figure 5.4. A form input with a 486, and checkboxes not selected.

Using a Database with Your CGI Program

I have covered quite a bit in the last two chapters. You now should know how to encode and decode data, use variables, and read from a file. Now it's time to make your CGI program work with a simple database file.

Working with a database file means that your program doesn't have to change whenever the data changes. The program in Figure 5.6 has to be modified every time a price changes. That is a lot of extra unnecessary work.

You already know how to read files; all that's necessary is to add a file with the correct data in it. Then your program can send the correct data back to your client without ever being updated. In its basic form, that's all a database is—a file with some data that you read and/or write to.

In the next section, I use pull-down menus to build a custom computer for a Web client. The price of the computer is calculated by reading from a formatted file. I include the actual file data in this example so that you can see the working solution from beginning to end.

In the next section, you'll learn about the Select HTML tag, the Perl special input characters <>, and some tricks for using data inside your code.

Using Pull-Down Menus in your Web Page Forms and Scripts

A pull-down menu compacts lots of information into a small space. When your user clicks on the down arrow, he is presented with a menu of choices where only one was visible before. This lets you build a form with lots of information that doesn't have to crowd the data into one small screen.

Using the HTML Form Select Tag

You create pull-down menus by using the HTML Form Select tag. The Select tag has multiple options that act much like radio buttons. Like the radio button, the Select tag has a single name for all of its possible values. Unlike the radio button, you can select more than one item by adding the Multiple attribute to the Select tag.

The data passed to your CGI program from the Select pull-down menu is identical in format to the radio button. But the syntax of the Select tag is quite different. First, the Select tag is not part of the Input type group. Next, like other HTML tags, it has an opening Select tag and a closing /SELECT tag. What goes between those tags defines what appears on the pull-down menu.

The Select pull-down menu can operate just like a radio button, with only one menu item at a time being selectable. Or you can allow multiple items to be selectable by adding the Multiple attribute to the opening Select tag Select Multiple.

Using the Option Attribute

You can think of the Option field as similar to the Value field of the radio button. The Option field defines the visible items of the pull-down menu. Each new option makes a new item on the pull-down menu. Unlike the radio button, the visible item also can be used as the value sent to your program. You also have the option of giving each of your menu options a "value" that is different than the visible menu selection. To do this, just add the Value attribute to the Option field. If the Value attribute is not defined, then the text after the Option field becomes the "value" portion of the name/value pair passed to your CGI program.

Listing 5.9 summarizes the format of the Select tag.

01: <SELECT NAME="some_name"> 
<OPTION> name1 
<OPTION> name2 
</SELECT>
02: <SELECT MULTIPLE NAME="some_name"> 
<OPTION> name1 
<OPTION> name2 
</SELECT>

Listing 5.10 is the HTML required for the pull-down menus shown in Figure 5.5. Any one of these pull-down menus could be made into multiple selection pull-down menus by adding the Multiple attribute to the Select tag, as shown in line 2 of Listing 5.9.


Figure 5.5. A working pull-down menu.

01: <h3> Or Build your own  </h3>
02: <form method="post" action="/cgi-bin/accn_build.cgi">
03: <table>
04: <th> CPU <th> Memory <th> Hard Disk <th> Video Card <th> Monitor <th> CD ROM 01: 
05: <th> Modem
06: <tr>
07: <td>
08: <select name="cpu" >
09: <option value="P100"> Pentium 100
10: <option value="P75"> Pentium 75
11: <option value="P60"> Pentium 60
12: <option value="486d66"> 486 DX2 66
13: </select>
14: <td>
15: <select name="memory" >
16: <option value="32 MEG"> 32 Meg Memory
17: <option value="16 MEG"> 16 Meg Memory
18: <option value="8 MEG"> 8 Meg Memory
19: <option value="4 MEG" > 4 Meg Memory
20: </select>
21: <td>
22: <select name="disk" >
23: <option value="1 GIG IDE"> 1 Gig IDE
24: <option value="850 IDE"> 850 Meg  IDE
25: <option value="560 IDE" > 560 Meg IDE
26: </select>
27: <td>
28: <select name="video" >
29: <option value="4 MEG">  4 Meg  card
30: <option value="2 MEG">  2 Meg  card
31: <option value="1 MEG"> 1 Meg  card
32: </select>
33: <td>
34: <select name="monitor" >
35: <option value="17 INCH"> 17 .28 NI
36: <option value="15 INCH"> 15 .28 NI
37: <option value="14 INCH" > 14 .28 NI
38: </select>
39: <td>
40: <select name="CD-ROM" >
41: <option value="4X CDROM"> Quad Speed
42: <option value="2X CDROM"> Double Speed
43: <option value="NONE" > NONE
44: </select>
45: <td>
46: <select name="modem" >
47: <option value="28.8 MODEM"> 28.8
48: <option value="14.4 MODEM"> 14.4
49: <option value="NONE" > NONE
50: </select>
51: <tr>
52: </table>
53: <input type="submit" value="Get Current Price">
54: <input type="reset">
55: </form>
56: [ <A HREF="http://www.accn.com">
57:   <img alt="Austin Computer Center "
58:   src="home.gif" border=1 A>  |
59: <A HREF="pindex.htm"> Parts Index   </A>   |
60: </body>
61: </html>

Lines 8 through 13 define the pull-down menu for the computer choices of this form. The first option in the select list is the default option. However, you can chose a different option as the default displayed and the selected value by adding Selected to the Option field of the Select HTML tag. If you want the 8 MB memory to be the default option, even though it isn't at the top of the list, change line 18 to look like this:

18: <option value="8 MEG" SELECTED> 8 Meg Memory

The default option will be displayed when your client presses the Reset button or first loads your Web page. Just like with the radio buttons, it is an error to have more than one option selected for single-choice menus.

Also notice that I have given an explicit "value" to each of the options. This makes it easier for my CGI program. I use some shorthand for my program to check against and easy-to-understand text for the pull-down menu. If you do not use the Value attribute of the Option field, it is not an error. The text after closing the Option tag (the ">") will be displayed on your pull-down menu and used as the value sent to your CGI program.

Using File Data in Your CGI Program

This is where you get to learn how to work with a simple database. In this case, you will work with one file that has some data in it. But don't be underwhelmed by this. A database program does no more than work with one or more files. This is a foundation you can take as far as you want.

In this example, you will examine reading from a file and using the data passed from pull-down menus in a little bit more sophisticated manner. The CGI program in Listing 5.11 handles the data sent by pull-down menus. It is similar to the CGI program in program Listing 5.10, so I will just go over the new features.

01: #!/usr/local/bin/perl
02: push(@INC, "/cgi-bin");
03: require("cgi-lib.pl");
04: &ReadParse(*input);
05: open($PRICE_FILE, "../systems/sys2.txt");
06: while (<$PRICE_FILE>) {
07: chop;
08:($item, $price) = split(/:/,$_,2) ;
09: $price_list{$item} = $price ;
10: }
11: #Determine the base price based on the system variable
12: $price = $price_list{$input{'cpu'}};
13: if ($input{'cpu'} eq "486d66") {
14:    #set 486 only variables
15:    $computer_name = "486DX2-66";
16:    $video = "VLB";
17:    $price += $price_list{$input{'memory'}};
18:    $memory = $input{'memory'};
19:    }
20: else {
21:   #not a 486 must be Pentium system
22:   $computer_name = "Pentium";
23:   $video = "PCI";
24:    $cache = "256K Cache" ;
25:    if ($input{'memory'} ne "8 MEG"){
26:       $price += $price_list{$input{'memory'}};
27:       }
28:    if ($input{'memory'} eq "4 MEG"){
29:       $memory = "8 MEG";
30:       }
31:    else { $memory = $input{'memory'};}
32:    if ($input{'cpu'} eq "P100"){$ptype = 100}
33:    elsif ($input{'cpu'} eq "P75"){$ptype = 75}
34:    elsif ($input{'cpu'} eq "P60"){$ptype = 60}
35:    }
36: #add extra price for monitors over 14inch
37: $monitor = $input{'monitor'};
38: $price += $price_list{$input{'monitor'}};
39: #add multimedia system
40: if ($input{'CD-ROM'} ne "NONE") {
41:    $price += $price_list{$input{'CD-ROM'}};
42:    if ($input{'CD-ROM'} eq "2X CDROM") {
43:       $multimedia="Double Speed MultiMedia System";
44:       }
45    else {
46:        $multimedia="Quad Speed MultiMedia System";
47:       }
48:    }
49: #add 14.4 modem price
50: if ($input{'modem'} ne "NONE") {
51:    $price += $price_list{$input{'modem'}};
52:    $modem = $input{'modem'};
53:    }
54: #add disk price
55: $price += $price_list{$input{'disk'}};
56: $DISK = $input{'disk'};
57: #add video
58: $price += $price_list{$input{'video'}};
59: $VIDEO = $input{'video'};
60: print &PrintHeader;
61: #print <$in1>;
62: print<<"print_tag";
63: <html>
64: <head>
65: <title>$computer_name Systems from Austin Computer Center North </title>
66: </head>
67: <body>
68: <h1 align=center> Austin Computer Center North <br>Austin Texas! </h1>
69: <center>
70: <img src="/accn.jpg" align=left>
71: <table border=5>
72: <th colspan=2 align=center> <h2>
73: ${computer_name} $ptype for only \$$price
74: </h2>
75: <tr><td> <ul>
76: <li>$memory of Ram
77: <li>$cache
78: <li>Enhanced IDE In/Out Controller
79: <li>$monitor NIL SVGA Monitor
80: <li>$VIDEO $video SVGA Video Card
81: <li>$multimedia
82: </ul>
83: <td> <ul>
84: <li>1.44 Floppy Drive
85: <li>$DISK Hard Drive
86: <li>Mouse
87: <li>Windows 95
88: <li>$modem
89: </ul>
90: <tr>
91: <td align=right colspan=2> <h2> 1 YEAR WARRANTY PARTS & LABOR! </h2>
92: <tr>
93: </table>
94: </center>
95: </body>
96: </html>
97: print_tag

Opening a File

In line 5 of Listing 5.12,

open($PRICE_FILE, "../systems/sys2.txt");

the file that contains the current prices of computer systems at ACCN is opened for reading.

You can open a file for reading, appending to, or writing. Be careful, though: opening a file for writing destroys the contents of any old file with the same file name. Think of opening a file for writing as if you were creating a new file. The default is to open for reading, so the read symbol (<) is not required. The write symbol (>) opens a file for writing and destroys any data that was previously in the file. If you want to add data to a file, open it for appending (>>). This will add any data you write to the end of the file. These symbols go just before the file name; in this example, it could have been written as

open($PRICE_FILE, "<../systems/sys2.txt");

Use the following statement to write to a file:

format printf(FILE-TO-WRITE-TO FORMAT-STATEMENTS, DATA);

Reading Formatted Data

When you read from a database you are reading from some type of formatted data. In this simple model, you read in one line of data at a time and then interpret that line.

Line 6 of Listing 5.11,

while (<$PRICE_FILE>) {

reads one line at a time from the file. The <> symbols are used to read input until and EOF character is read. The line of data is read into the special Perl symbol $_. The next lines operate on the $_ symbol.

The $_ is another of Perl's special variables. The $_ is the default variable for data input and pattern-matching functions. When you look at other Perl programs and you can't figure out what variable the code is operating on, it's probably $_. The Perl chop function uses the $_ by default.

The chop function is one of Perl's handy built-in functions. It removes the last character of a string. You'll find it used in all kinds of Perl functions to get rid of the CRLF (newline) character at the end of reading an input line.

Using Formatted File Data

Line 8 of Listing 5.11,

$item, $price) = split(/:/,$_,2) ;

uses the $_ explicitly as the input expression. This line looks a lot like the split function in the ReadParse function of the cgi-lib.pl library. One difference is the split pattern ":". I use this to allow formatting of the file data. The file data is formatted to work with the name/value pairs coming from the form page, and to be displayable as the data displayed on the Web page, which is generated on-the-fly from the CGI program.

Line 9,

$price_list{$item} = $price ;

builds an associative array. This array is indexed by the variable $item and contains the value of the $price variable. Listing 5.12 contains the data in the file. The $price and $item variables are set from reading the file data on line 8. This is really the crux of making the file, your CGI code, and your Web page form work together.

If you look at this closely, you will see that the data to the left of the colon (:) matches up with the input form values from the pull-down menus. And, it matches up with most of the data displayed back to the client, when the CGI generates the HTML in lines 63 through 97 of Listing 5.12. It should be clearer now why it is so crucial to design your form at the same time you are designing your CGI program. It all has to fit together, and it can make your CGI work a lot easier.

P100:1799
P75:1550
P60:1450
486d66:1099
32 MEG:800
16 MEG:300
8 MEG:160
4 MEG:0
1 GIG IDE:175
850 IDE:110
560 IDE:0
4 MEG:320
2 MEG:120
1 MEG:0
17 INCH:650
15 INCH:200
14 INCH:0
4X CDROM:290
2X CDROM:190
NONE:0
28.8 MODEM:139
14.4 MODEM:69
NONE:0

Using Data to Make Your CGI Programming Easier

Notice in line 12 of Listing 5.12,

$price = $price_list{$input{'cpu'}};

I set the base price of the computer. I used several lines to do this in the first program. This time, my form passes a name/value pair that matched the data I read in from a file. The "value" of the name "cpu" will be one of (P100, P75, P60, or 486d66). The data that contains the price is identical: P100:1799. The P100 in the file matches the P100 passed as part of the name/value pair (cpu/P100). The ReadParse function has placed the P100 value in the input array matched up to its name "cpu".

Taken one step at a time, line 12 works like this:

  1. You read code inside braces or parenthesis "{}[]()" from "inside out," so you start with $input{'cpu'}. $input{'cpu'} returns the value associated with the name cpu P100, in this case.

  2. So now, line 12 can be read as

    $price = $price_list{P100}

    The $price_list file was built from line 9. The P100 value read from the file was 1799.

  3. So now, line 12 can be read as $price = 1799.

I use this format (whenever I can) throughout this program. It means a lot less code for me, and when I want to change prices, I just change the file instead of the Perl code. I also use the values passed from my form as part of the HTML generated by my CGI program. Line 18,

$memory = $input{'memory'};

is a good example. I just take the value passed to me with the "memory" name/value pair and redisplay it in line 76, <li>$memory of Ram. Figure 5.6 is the Web page generated by this CGI program and this input data.


Figure 5.6. The Results from the pull-down menu program.

So there you have it. A few simple tricks and your code becomes data driven. This will be easier to maintain, because the data that makes your code work isn't scattered all over your code. It's located in one easy-to-maintain file.

Summary

In this chapter, you learned how to decode data, work with formatted files, and build Web page forms with radio buttons and pull-down menus. I have included the major topics of discussion in the following list. You can use this list in the future to refresh your memory on each of the rules discussed in this chapter:

The basic rules of radio buttons follow:

Here are some other things you might want to keep in mind:

read(READ-FROM-FILE HANDLE, READ-INTO, LENGTH-TO-READ)

Q&A

Q: You never mentioned the Reset button in Listing 5.11 and Listing 5.1. How does it work?

A: The Reset button is really a special case for Form elements. All other Form elements in some way are designed to send data entered by your Web client to your CGI program. The Reset button's job is not to send data but to change all the values on a form back to their default conditions.

In particular, for the radio button, the individual radio button that has the Checked attribute will become selected. With pull-down menus, the pull-down option that has the Select attribute will be selected. For text fields, the field first will be cleared and then if there is any default data, it will be displayed in the text window.

The same is true for all the other input types of the form that have default values. The Reset button sets the value back to whatever is defined as the default value for each form element. If the form is submitted after the Reset button is selected and before any other changes have occurred on the form, only the default data will be transferred to the CGI program identified in the Action field.


Tip: Don't rename the Reset button. It's common to want to customize your menus to make them unique and show off your skills. But in this case, it's bad style to relabel the Reset button. Notice that the programs you are used to and comfortable with have a similar layout as you move from window to window. The Reset button is one of those buttons that gives your clients some level of familiarity and comfort with your Web site. This button always should be labeled Reset and always should perform the default action.

Q: Why is the radio button called a radio button?

A: Picture your car radio. Imagine that you press one of the preset radio station buttons on the tuner. What happens? A new radio station is selected and the previous radio station is deselected. Any noise or stations between the new radio station and the old radio station is ignored. You only get the what you selected and none of the garbage between.

Now think of how the radio buttons works on your HTML form. You only get what you allow your Web page client to select. And whenever a selection is made, the previous selection is deselected. Just like your car radio.

By the way, the term radio button did not begin with HTML forms. Radio buttons and pull-down menus are terms that have been used by Human Control Interface (HCI) designers for years. HCI designers also are called Graphical User Interface (GUI) designers. They are responsible for the look and feel of a program's interface with the human user.

Q: What does creating Web pages on-the-fly mean?

A: This is one of those Internet terms that just doesn't seem to be defined anywhere. But it sure does get used a lot. Creating Web pages on-the-fly simply means that some of the data returned when a client clicks on a link or submits a form is generated when the called URI is returned. This can be as little as adding the current date to your Web page or as complex as generating a completely new Web page full of variable data and different HTML based on what data was sent with the form.

Q: How do I use the data sent by a multiple pull-down menu selection?

A: You might think that you would have to go to a lot of extra effort to get at the multiple name/value pairs sent to your CGI program from a pull-down menu with the Multiple attribute. Or you might think that you could lose information, because all of the names of a pull-down selection will be the name in the name/value pairs sent to your CGI program.

Happily for everyone who uses the ReadParse function, ReadParse deals with name/value pairs where the names are the same—cleanly and simply.

Line 27 of Listing 5.3 does all the magic for you:

27:     $in{$key} .= "\0" if (defined($in{$key})); # \0 is the multiple separator

This line was discussed when you were stepping though the code of ReadParse. Each time a name is parsed by ReadParse, it is checked against the other names in the %in array. If the name already is defined (exists) in the %in array, then the value is placed into the array, but only after the special string terminator "\0" is inserted.

For multiple selections, each selection will be available using the Select element's Name attribute. Each value of the Option field will be separated by an "\0". So, if you had a pull-down menu made up of fruit, such as the one in the HTML fragment shown in Listing 5.14, and all the options were chosen, then referencing the %in array as $in{'fruit'} would yield the string

"tomato\0banana\0avocado\0pomegranate"

You could extract each of the values of the fruit string by using the split function with a pattern of "\0". This would split the string into an array of separate fruits, which you then could access one at a time.

<select name="fruit" >
<option value="tomato"> Tomato
<option value="banana"> Banana
<option value="avocado"> Avocado
<option value="pomegranate"> Pomegranate

</select>

Previous Page TOC Index Next Page See File