JavaScript by Example (2nd Edition)

Processing user input is one of the most common reasons for using a CGI script. This is normally done with forms. The form offers you a number of methods , called virtual input devices , with which to accept input. These include radio buttons , checkboxes, pop-up menus , and text boxes. All forms are in HTML documents and begin with a <FORM> tag and end with a </FORM> tag. A method attribute may be assigned. The method attribute indicates how the form will be processed . The GET method is the default and the POST method is the most commonly used alternative. The GET method is preferable for operations that will not affect the state of the server; that is, simple document retrieval and database lookups, etc., whereas the POST method is preferred for handing operations that may change the state of the server, such as adding or deleting records from a database. These methods will be described in the next section. The ACTION attribute is assigned the URL of the CGI script that will be executed when the data is submitted by pressing the Submit button.

The browser gets input from the user by displaying fields that can be edited. The fields are created by the HTML <INPUT TYPE=key/value> tag. These fields might take the form of checkboxes, text boxes, radio buttons, etc. The data that is entered into the form is sent to the server in an encoded string format in a name /value pair scheme. The value represents the actual input data. The CGI programmer must understand how this input is encoded in order to parse it and use it effectively. First let's see how input gets into the browser by looking at a simple document and the HTML code used to produce it. The user will be able to click on a button or enter data in the text box. The input in this example won't be processed, thereby causing an error to be sent to the server's error log when the Submit button is selected. Nothing will be displayed by the browser. The default for obtaining input is the GET method.

A summary of the steps in producing a form is

  1. START : Start the form with the HTML <FORM> tag.

  2. ACTION : The ACTION attribute of the <FORM> tag is the URL of the CGI script that will process the data input from the form.

  3. METHOD : Provide a method on how to process the data input. The default is the GET method.

  4. CREATE : Create the form with buttons and boxes and whatever looks nice using HTML tags and fields.

  5. SUBMIT : Create a Submit button so that the form can be processed. This will launch the CGI script listed in the ACTION attribute.

  6. END : End the form and the HTML document.

C.8.1 Input Types for Forms

Table C.9. Form input types.

Input Type

Attributes

Description

CHECKBOX

NAME, VALUE

Displays a square box that can be checked. Creates name/value pairs from user input. Multiple boxes can be checked.

FILE

NAME

Specifies files to be uploaded to the server. MIME type must be multipart/form-data.

HIDDEN

NAME, VALUE

Provides name/value pair without displaying an object on the screen.

IMAGE

SRC, VALUE, ALIGN

Same as the Submit button, but displays an image instead of text. The image is in a file found at SRC.

PASSWORD

NAME, VALUE

Like a text box but input is hidden. Asterisks appear in the box to replace characters typed.

RADIO

NAME, VALUE

Like checkboxes, except only one box (or circle) can be checked at a time.

RESET

NAME, VALUE

Resets the form to its original position; clears all input fields.

SELECT

NAME, OPTION SIZE, MULTIPLE

Provides pop-up menus and scrollable lists. Only one can be selected. Attribute MULTIPLE creates a visibly scrollable list. A SIZE of 1 creates a pop-up menu with only one visible box.

SUBMIT

NAME, VALUE

When pressed, executes the form; launches CGI.

TEXT

NAME

SIZE, MAXLENGTH

Creates a text box for user input.

SIZE specifies the size of the text box. MAXLENGTH specifies the maximum number of characters allowed.

TEXTAREA

NAME, SIZE

ROWS, COLS

Creates a text area that can take input spanning multiple lines. ROWS and COLUMNS specify the size of the box.

C.8.2 Creating an HTML Form

A Simple Form with Text Fields, Radio Buttons, Checkboxes, and Pop-up Menus

First let's see how input gets into the browser by looking at a simple document and the HTML code used to produce it. The user will be able to click on a button, or enter data in the text box. The input in this example won't be processed, thus causing an error to be sent to the server's error log when the Submit button is selected. Nothing will be displayed by the browser. The HTML file is normally stored under the server's root in a directory called htdocs . If the HTML file is created on the local machine, then the file:/// protocol is used in the Location box with the full pathname of the HTML file, which would normally end with an .html or .htm extension.

Figure C.7. A form as it is initially displayed.

Figure C.8. A form filled with user input.

Example C.12

(The HTML Form Source File) 1 <HTML><HEAD> 2 <TITLE>First CGI Form</TITLE></HEAD> <HR> 3 <FORM ACTION="/cgi-bin/bookstuff/form1.cgi" > 4 <P><B> Type your name here: 5 <INPUT TYPE="text" NAME="namestring" SIZE=50> 6 <P><BR> Talk about yourself here: <BR> 7 <TEXTAREA NAME="comments" ROWS=5 COLS=50>I was born... </TEXTAREA> </B> 8 <P> Choose your food: 9 <INPUT TYPE="radio" NAME="choice" VALUE="burger">Hamburger <INPUT TYPE="radio" NAME="choice" VALUE="fish">Fish <INPUT TYPE="radio" NAME="choice" VALUE="steak">Steak <INPUT TYPE="radio" NAME="choice" VALUE="yogurt">Yogurt <P> <B>Choose a work place:</B> <BR> 10 <INPUT TYPE="checkbox" NAME="place" VALUE="LA">Los Angeles <BR> <INPUT TYPE="checkbox" NAME="place" VALUE="SJ">San Jose <BR> <INPUT TYPE="checkbox" NAME="place" VALUE="SF" Checked> San Francisco <P> 11 <B>Choose a vacation spot:</B> 12 <SELECT NAME="location"> <OPTION SELECTED VALUE="hawaii"> Hawaii <OPTION VALUE="bali">Bali <OPTION VALUE="maine">Maine <OPTION VALUE="paris">Paris </SELECT> <P> 13 <INPUT TYPE="SUBMIT" VALUE="Submit"> 14 <INPUT TYPE="RESET" VALUE="Clear"> </FORM> </HTML>

EXPLANATION

  1. This tag says that this is the start of an HTML document.

  2. The <TITLE> tag; the title appears outside of the browser's main window.

  3. The beginning of a <FORM> tag, which specifies where the browser will send the input data and the method that will be used to process it. The default method is the GET method. When the data is submitted, the CGI script will be executed by the server. The CGI script is located under the server's root directory in the cgi-bin directory, the directory where CGI scripts are normally stored. In this example, the CGI script is stored in a directory called bookstuff, below the cgi-bin directory.

  4. The <P> tag starts a new paragraph. The <B> tag says the text that follows will be in bold type. The user is asked for input.

  5. The input type is a text box that will hold up to 50 characters. When the user types text into the text box, that text will be stored in the user-defined NAME value, namestring . For example, if the user types Stefan Lundstom , the browser will assign namestring=Stefan Lundstrom to the query string. If assigned a VALUE attribute, the text field can take a default; i.e., text that appears in the text box when it is initially displayed by the browser.

  6. The user is asked for input.

  7. The text area is similar to the text field, but will allow input that scans multiple lines. The <TEXTAREA> tag will produce a rectangle (name comments) with dimensions in rows and columns (5 rows by 50 columns) and an optional default value ( I was born...) .

  8. The user is asked to pick from a series of menu items.

  9. The first input type is a list of radio buttons. Only one button can be selected. The input type has two attributes: a TYPE and a NAME . The value of the NAME attribute choice , for example, will be assigned burger if the user clicks on the Hamburger option. choice=burger is passed onto the CGI program. And if the user selects Fish, choice=fish will be assigned to the query string, and so on. These key/value pairs are used to build a query string to pass onto the CGI program after the Submit button is pressed.

  10. The input type this time is in the form of checkboxes. More than one checkbox may be selected. The optional default box is already checked. When the user selects one of the checkboxes, the value of the NAME attribute will be assigned one of the values from the VALUE attribute such as place=LA if Los Angeles is checked.

  11. The user is asked for input.

  12. The <SELECT> tag is used to produce a pop-up menu (also called a drop-down list) or a scrollable list. The NAME option is required. It is used to define the name for the set of options. For a pop-up menu, the SIZE attribute is not necessary; it defaults to 1. The pop-up menu initially displays one option and expands to a menu when that option is clicked. Only one selection can be made from the menu. If a SIZE attribute is given, that many items will be displayed. If the MULTIPLE attribute is given (e.g., SELECT MULTIPLE NAME=whatever ), the menu appears as a scrollable list, displaying all of the options.

  13. If the user clicks the Submit button, the CGI script listed in the form's ACTION attribute will be launched. In this example, the script wasn't programmed to do anything. An error message is sent to the server's error log and to the browser.

  14. If the Clear button is clicked, all of the input boxes are reset back to their defaults.

C.8.3 The GET Method

The simplest and most widely supported type of form is created with what is called the GET method. It is used every time the browser requests a document. If a method is not supplied, the GET method is the default. It is the only method used for retrieving static HTML files and images.

Since HTML is an object-oriented language, you may recall that a method is a name for an object-oriented subroutine.The GET method passes data to the CGI program by appending the input to the program's URL, usually as a URL-encoded string. The QUERY_STRING environment variable is assigned the value of the encoded string.

Servers often have size limitations on the length of the URL. For example, the UNIX size is limited to 1240 bytes. If a lot of information is being passed to the server, the POST method should be used.

Figure C.9. The HTML form created in the following Example C.13.

Example C.13

HTML Source File with a Form Tag and ACTION Attribute --------------------------------------------------------------------- <HTML><HEAD><TITLE>First CGI Form</TITLE></HEAD> <HR> 1 <FORM ACTION="/cgi-bin/form1.cgi" METHOD=GET> <! When user presses "submit", cgi script is called to process input > 2 Please enter your name: <BR> 3 <INPUT TYPE="text" SIZE=50 NAME="Name"> <P> Please enter your phone number: <BR> 4 <INPUT TYPE="text" SIZE=30 NAME="Phone"> <P> 5 <INPUT TYPE=SUBMIT VALUE="Send"> <INPUT TYPE=RESET VALUE="Clear"> 6 </FORM> </HTML>

EXPLANATION

  1. The <FORM> tag specifies the URL and method that will be used to process a form. When a user submits the form, the browser will send all the data it has obtained from the browser to the Web server. The ACTION attribute tells the server to call a CGI script at the location designated in the URL and send the data on to that program to be processed. The METHOD attribute tells the browser how the input data is to be sent to the server. The GET method is the default, so it does not need to be assigned here. The CGI program can do whatever it wants to with the data and, when finished, will send it back to the server. The server will then relay the information back to the browser for display.

  2. The user is asked for input.

  3. The input type is a text box that will hold up to 50 characters. The NAME attribute is assigned the string Name . This will be the key part of the key/value pair. The user will type something in the text box. The value entered by the user will be assigned to the NAME key. This NAME=VALUE pair will be sent to the CGI script in that format; for example, Name=Christian .

  4. The NAME attribute for the input type is Phone . Whatever the user types in the text box will be sent to the CGI program as Phone=VALUE ; for example, Phone=510-456-1234

  5. The SUBMIT attribute for the input type causes a Submit button to appear with the string Send written on the button. If this box is selected, the CGI program will be executed. The input is sent to the CGI program. The RESET attribute allows the user to clear all the input devices by clicking on the Clear button.

  6. The </FORM> tag ends the form.

Figure C.10. Filling out the form from Example C.13.

Example C.14

(The CGI Script) 1 #!/bin/perl # The CGI script that will process the form information sent # from the server 2 print "Content-type: text/html\n\n"; print "First CGI form :\n\n"; # Print out only the QUERY_STRING environment variable 3 while(($key, $value)=each(%ENV)){ 4 print "<H3> $key = <I> $value </I></H3><BR>" if $key eq "QUERY_STRING"; }

EXPLANATION

  1. The #! line tells the server where to find the Perl interpreter.

  2. Perl's output goes to the browser rather than the screen. The content type (also called the MIME type) is text/html text since there are HTML tags in the text.

  3. Perl's input comes from the server. The while loop is used to loop through all of the environment variables in the %ENV hash. These variables were passed into the Perl script from the Web server.

  4. This line will be printed only when the value of the QUERY_STRING environment variable is found. It wasn't really necessary to loop through the entire list. It would have been sufficient to just type print "$ENV{QUERY_STRING}<BR>" ;.

C.8.4 Processing the Form

The Encoded Query String

When using the GET method, information is sent to the CGI program in the environment variable, QUERY_STRING . [4] The string is URL-encoded. In fact, all data contained in an HTML form is sent from the browser to the server in an encoded format. When the GET method is used, this encoded data can be seen on the URL line in your browser preceded by a question mark. The string following the ? will be sent to the CGI program in the QUERY_STRING environment variable. Each key/value pair is separated by an ampersand ( & ) and spaces are replaced with plus signs ( + ). Any non- alphanumeric values are replaced with their hexadecimal equivalent, preceded by a percent sign ( % ). After pressing the Submit button in the previous example, you would see the input strings in your browser's Location box (Netscape), appended to the URL line and preceded by a question mark. The highlighted part in the following example is the part that will be assigned to the environment variable, QUERY_STRING . The QUERY_STRING environment variable will be passed to your Perl script in the %ENV hash. To access the key/value pair in your Perl script, add a print statement: print $ENV{QUERY_STRING};

[4] When using the POST method, input is assigned to a variable from STDIN and encoded the same way.

Example C.15

1 What you see in the Location box of the browser: http://servername/cgi-bin/ form1.cgi?Name=Christian+Dobbins&Phone=543-123-4567 2 What the server sends to the browser in the ENV hash value, QUERY_STRING: QUERY_STRING=Name=Christian+Dobbins&Phone=543-123-4567

Figure C.11. Output of the CGI script from Example C.13.

Decoding the Query String with Perl

Decoding the query string is not a difficult task because Perl has such a large number of string manipulation functions, such as tr, s, split, substr, pack, etc. Once you get the query string from the server into your Perl program, you can parse it and do whatever you want with the data. For removing &, + , and = signs from a query string, use the substitution command, s , the split function, or the translate function, tr. To deal with the hexadecimal-to-character conversion of those characters preceded by a % sign, the pack function is normally used.

Table C.10. Encoding symbols in a query string.

Symbol

Function

&

Separates key/value pairs.

+

Replaces spaces.

%xy

Represents any ASCII character with a value of less than 21 hexadecimal (33 decimal), or greater than 7f (127 decimal) and special characters ?, &, %, + , and = . These characters must be escaped with a % , followed by the hexadecimal equivalence (xy) of that character, e.g., %2F represents a forward slash, and %2c represents a comma.

Table C.11. URL hex-encoded characters.

Character

Value

Tab

%09

Space

%20

!

%21

"

%22

#

%23

$

%24

%

%25

&

%26

(

%28

)

%29

,

%2C

.

%2E

/

%2F

:

%3A

;

%3B

<

%3C

=

%3D

>

%3E

?

%3F

@

%40

[

%5B

\

%5C

]

%5D

^

%5E

'

%60

{

%7B

%7C

}

%7D

~

%7E

Parsing the Form's Input with Perl

After the Perl CGI script gets the input from the form, it will be decoded. This is done by splitting up the key/value pairs and replacing special characters with regular text. Once parsed, the information can be used to create a guest book, a database, send e-mail to the user, and so on.

The routines for parsing the encoded string can be stored in subroutines and saved in your personal library, or you can take advantage of the CGI .pm library module, part of Perl's standard distribution, which eliminates all the bother.

Decoding the Query String

Steps to decode are handled with Perl functions. The following shows a URL-encoded string assigned to $ENV{QUERY_STRING} .

Name=Christian+Dobbins&Phone=510-456-1234&Sign=Virgo

The key/pair values show that the URL has three pieces of information separated by the ampersand ( & ): Name, Phone , and Sign :

Name=Christian+Dobbins & Phone=510-456-1234 & Sign=Virgo

The first thing to do would be to split up the line and create an array (see step 1 below). After splitting up the string by ampersands, remove the + with the tr or s functions and split the remaining string into key/value pairs with the split function using the = as the split delimiter (see step 2 below).

1. @key_value = split(/&/, $ENV{QUERY_STRING}) ; print "@key_value\n"; 2. Output: Name=Christian+Dobbins Phone=510-456-1234 Sign=Virgo

The @key_value array created by splitting the query string:

Name=Christian+Dobbins

Phone=510-456-1234

Sign=Virgo

3. foreach $pair ( @key_value){ $pair =~ tr/+/ /; ($key, $value) = split(/=/, $pair); print "\t$key: $value\n"; } 4. Output: Name: Christian Dobbins Phone: 510-456-1234 Sign: Virgo

Example C.16

(Another URL-Encoded String assigned to $ENV{QUERY_STRING}) 1 $input="string=Joe+Smith%3A%2450%2c000%3A02%2F03%2F77"; 2 $input=~s/%(..)/pack("c", hex())/ge; 3 print $input,"\n"; Output: string=Joe+Smith:,000:02/03/77

EXPLANATION

  1. This string contains ASCII characters that are less than 33 decimal and greater than 127, the colon , the dollar sign, the comma, and the forward slash.

  2. The pack function is used to convert hexadecimal-coded characters back into character format.

  3. The search side of the substitution, / %(..) /, is a regular expression that contains a literal percent sign followed by any two characters (each dot represents one character) enclosed in parentheses. The parentheses are used so that Perl can store the two characters it finds in the special scalar, $1 .

    On the replacement side of the substitution, the pack function will first use the hex function to convert the two hexadecimal characters stored in $1 to their corresponding decimal values and then pack the resulting decimal values into an unsigned character. The result of this execution is assigned to the scalar, $input .

    Now you will have to remove the + sign.

C.8.5 Putting It All Together

The GET Method

Now it is time to put together a form that will be processed by a Perl CGI program using the GET method. The CGI program will decode the query string and display the final results on the HTML page that is returned after the form was filled out and the Submit button pressed.

The following examples demonstrate

  1. The HTML fillout form

  2. The HTML source file that produced the form

  3. The form after it has been processed by the CGI script

  4. The Perl CGI script that processed the form

Example C.17

(The HTML source file) <HTML><HEAD><TITLE>CGI Form</TITLE></HEAD><BODY> <HR> 1 <FORM ACTION="http://127.0.0.1/cgi-bin/getmethod.cgi" METHOD=GET> <!When user presses "submit", cgi script is called to process input > 2 Please enter your name: <BR> 3 <INPUT TYPE="text" SIZE=50 NAME=Name> <P> Plese enter your salary ($####.##): <BR> <INPUT TYPE="text" SIZE=30 NAME=Salary> <P> Plese enter your birth date (mm/dd/yy): <BR> <INPUT TYPE="text" SIZE=30 NAME=Birthdate> <P> 4 <INPUT TYPE=SUBMIT VALUE="Submit Query"> <INPUT TYPE=RESET VALUE="Reset"> 5 </FORM> </BODY></HTML>

EXPLANATION

  1. The form is started with the < FORM> tag. When the user presses the Submit button on the form, the ACTION attribute is triggers the HTTP server on this machine (local host is IP address 127.0.0.1) to start up the script called getmethod.cgi found under the server's root in the cgi-bin directory.

  2. The user is asked for information.

  3. The user will fill in the text boxes with his name, salary, etc.

  4. When the user presses the Submit button, the CGI script assigned to the ACTION attribute will be activated.

  5. This is the end of the form tag.

Figure C.12. The HTML form from Example C.17.

Example C.18

#!/usr/bin/perl # The CGI script that processes the form shown in Figure C.12. 1 print "Content-type: text/html\n\n"; print "<H2><U>Decoding the query string</U></H2>"; # Getting the input 2 $inputstring=$ENV{QUERY_STRING}; print "<B>Before decoding:</B><BR>"; print "<H3>$inputstring</H3>"; # Translate + signs to space 3 $inputstring =~ tr/+/ /; # Decoding the hexadecimal characters 4 $inputstring=~s/%(..)/pack("C", hex())/ge; # After decoding %xy print "-" x 80, "<BR>"; print "<B>After decoding <I>%xy</I>:</B>"; 5 print "<H3> $inputstring </H3>"; # Extracting & and creating key/value pairs 6 @key_value=split(/&/, $inputstring); 7 foreach $pair ( @key_value){ ($key, $value) = split(/=/, $pair); 8 %input{$key} = $value; # Creating a hash } # After decoding print "-" x 80, "<BR>"; print "<B>After decoding + and &:</B>"; 9 while(($key, $value)=each(%input)){ 10 print "<H3> $key: <I> $value </I></H3>"; } print "<B>Now what do we want to do with this information?"

EXPLANATION

  1. This MIME header line describes the format of the data returned from this program to be HTML text. The two newlines (required!) end the header information.

  2. The %ENV hash contains the key/value pairs sent to this Perl program by the Web server. The value of the QUERY_STRING environment variable is assigned to a scalar, $inputstring.

  3. The tr function translates all + signs to spaces.

  4. The pack function converts any hexadecimal numbers to their corresponding ASCII characters.

  5. The value of the scalar $ inputstring is sent from the Perl script to the server and then on to the browser.

  6. The scalar $inputstring is now split by ampersands. The output returned is stored in the three-element array, @key_value , as:

    Name=Louise Cederstrom&Salary=$200,000&Birthdate=7/16/51

  7. The foreach loop is used to iterate through the @key_value array. The resulting key/value pairs are created by splitting each array element by the = sign.

  8. A new hash called %input is created with corresponding key/value pairs.

  9. The while loop is used to iterate through the hash.

  10. The new key/value pair is printed and sent back to the Web server. The browser displays the output. Now that the Perl script has parsed and stored the input that came from the form, it is up to the programmer to decide what to do with this data. He may send back an e-mail to the user, store the information in a database, create an address book, etc. The real work is done!

Figure C.13. Output after CGI/Perl processing, Example C.18.

The POST Method

The only real difference between the GET and POST methods is the way that input is passed from the server to the CGI program. When the GET method is used, the server sends input to the CGI program in the QUERY_STRING environment variable.

When the POST method is used, the CGI program gets input from standard input, STDIN . Either way, the input is encoded in exactly the same way. One reason for using the POST method is that some browsers restrict the amount of data that can be stored in the QUERY_STRING environment variable. The POST method doesn't store its data in the query string. Also, the GET method displays the input data in the URL line in the Location box of the browser, whereas the POST method hides the data. Since the POST method does not append input to the URL, it is often used in processing forms where there is a lot of data being filled into forms.

In an HTML document, the <FORM> tag starts the form. The ACTION attribute tells the browser where to send the data that is collected from the user, and the METHOD attribute tells the browser how to send it. If the POST is method used, the output from the browser is sent to the server and then to the CGI program's standard input, STDIN . The amount of data, that is, the number of bytes taken as input from the user, is stored in the CONTENT_LENGTH environment variable.

Rather than assigning the input to the QUERY_STRING environment variable, the browser sends the input to the server in a message body, similar to the way e-mail messages are sent. The server then encapsulates all the data and sends it on to the CGI program.

The CGI program reads input data from the STDIN stream via a pipe.

The Perl read function reads the CONTENT_LENGTH amount of bytes, saves the input data in a scalar, and then processes it the same way it processes input coming from the query string. It's not that the format for the input has changed; it's just how it got into the program. Note that after the POST method has been used, the browser's Location box does not contain the input in the URL as it did with the GET method.

Example C.19

(The HTML source file) <HTML> <HEAD> <TITLE>CGI Form</TITLE> <HR> 1 <FORM ACTION="http://127.0.0.1/cgi-bin/postmethod.cgi" METHOD=POST> <!When user presses "submit", cgi script is called to process input > 2 Please enter your name: <BR> 3 <INPUT TYPE="text" SIZE=50 NAME=Name> <P> Please enter your salary ($####.##): <BR> <INPUT TYPE="text" SIZE=30 NAME=Salary> <P> Please enter your birth date (mm/dd/yy): <BR> <INPUT TYPE="text" SIZE=30 NAME=Birthdate> <P> 4 <INPUT TYPE=SUBMIT VALUE="Submit Query"> <INPUT TYPE=RESET VALUE="Reset"> 5 </FORM> </HTML>

EXPLANATION

  1. The <FORM> tag starts the form. The ACTION attribute is assigned the URL of the CGI script, postmethod.cgi , that will be executed whent the Submit button is pressed by the user, and the METHOD attribute is assigned POST to indicate how the data coming from the form will be handled.

  2. The user is asked for input.

  3. Text Fields are created to hold the user's name, salary, and birth date.

  4. The Submit button is created.

  5. The form is ended.

Example C.20

(The CGI Script) #!/bin/perl # Scriptname: postmethod.cgi 1 print "Content-type: text/html\n\n"; print "<H2><U>Decoding the query string</U></H2>"; # Getting the input 2 if ( $ENV{REQUEST_METHOD} eq 'GET' ){ 3 $inputstring=$ENV{QUERY_STRING}; } else{ 4 read(STDIN, $inputstring, $ENV{'CONTENT_LENGTH'}); } 5 print "<B>Before decoding:</B><BR>"; print "<H3> $inputstring </H3>"; # Replace + signs with spaces 6 $inputstring =~ tr/+/ /; # Decoding the hexadecimal characters 7 $inputstring=~s/%(..)/pack("C", hex())/ge ; # After decoding %xy print "-" x 80, "<BR>"; 8 print "<B>After decoding <I>%xy</I>:</B>"; print "<H3> $inputstring </H3>"; # Extracting the & and = to create key/value pairs 9 @key_value=split(/&/, $inputstring); 10 foreach $pair ( @key_value){ 11 ($key, $value) = split(/=/, $pair); 12 %input{$key} = $value; # Creating a hash to save the data } # After decoding print "-" x 80, "<BR>"; print "<B>After decoding + and &:</B>"; 13 while(($key, $value)= each(%input)) { # Printing the contents of the hash print "<H3> $key : <I> $value </I></H3>"; } print "<B>Now what do we want to do with this information?";

EXPLANATION

  1. The content being sent to the browser is text interspersed with HTML tags.

  2. One of the environment variables sent by the server to the script is $ENV{REQUEST_METHOD} , which will have a value of either GET or POST .

  3. If the value of the $ENV{REQUEST_METHOD} variable is GET , the scalar, $inputstring will be assigned the value of the query string, $ENV{QUERY_STRING} .

  4. If the value of the $ENV{REQUEST_METHOD} variable is POST, the scalar, $inputstring will be assigned the input coming from the standard input stream via the read function. The amount of data read is found in the environment variable, $ENV{CONTENT-LENGTH} .

  5. The value of $inputstring is printed with the URL encoding still in place; for example, a space is represented by a + sign, the key/value pairs are separated with an & , and the % sign is followed by the hexadecimal value of the character it represents.

  6. All + signs are translated to single spaces.

  7. This line replaces the hexadecimal characters with their corresponding ASCII values.

  8. After decoding the % hex values, the value of $inputstring is printed.

  9. The split function uses the & as a field separator.

  10. The foreach loop iterates through array, assigning each element, in turn , to $pair .

  11. Key/value pairs are created by splitting the string at = signs.

  12. A hash, %input , is being created on the fly. It will consist of key/value pairs created by splitting up the input string.

  13. The each function extracts the key/value pairs from the %input hash. Each time through the loop the next key/value pair is extracted and displayed in the browser.

Figure C.14. The HTML input form from Example C.19.

Figure C.15. The output from the CGI script in Example C.20.

C.8.6 Handling E-Mail

The SMTP Server

When processing a form, it is often necessary to send e-mail before exiting. You may be sending e-mail to the user and/or to yourself with the submitted form data. E-mail cannot be sent over the Internet without a valid SMTP (Simple Mail Transfer Protocol) server. [5]

[5] The format for Internet mail messages is defined by RFC822.

The SMTP server is an instance of a mail daemon program that listens for incoming mail on Port 25. SMTP is a TCP-based client/server protocol where the client sends messages to the server. UNIX systems commonly use a mail program called sendmail to act as the SMTP server listening for incoming mail. Normally you would run sendmail at the command line with the recipient's name as an argument. To end the e-mail message, a period is placed on a line by itself. In a CGI script, the mail will not be sent interactively, so you will probably want to use the sendmail options to control these features. See Table C.12.

Table C.12. sendmail options.

Option

What It Does

-o

A sendmail option follows

-t

Reads headers To, From, Cc , and Bcc information from message body

-f "email address"

Message is from this e-mail address

-F "name"

Message is from name

-i

Periods will be ignored if on a line by themselves

-odq

Queues up multiple e-mail messages to be delivered asynchronously

For Windows, two programs similar to sendmail are Blat, a public domain Win32 console utility that sends e-mail using the SMTP protocol (see www.interlog.com/~tcharron/blat.html), and wSendmail, a small utility that can send e-mail from programs, the command line, or directly from an HTML form (see www.kode.net/wsendmail.html or www.softseek.com/Internet/E_Mail/E_Mail_Tools). Go to CPAN and find the MailFolder package, which contains modules such as Mail::Folder, Mail::Internet, and Net:: SMTP , to further simplify the sending and receiving e-mail. For a complete discussion on sendmail , see www.networkcomputing.com/unixworld/tutorial008.

Example C.21

(From the HTML form where the e-mail information is collected) <FORM METHOD="post" ACTION="http://127.0.0.1/cgi-bin/submit-form"> <INPUT TYPE="hidden" NAME="xemailx" VALUE="elizabeth@ellieq.com"> <INPUT TYPE="hidden" NAME="xsubjext" VALUE="Course Registration"> <INPUT TYPE="hidden" NAME="xgoodbyex" VALUE="Thank you for registering."> <P> <A NAME="REGISTRATION"> <TABLE CELLSPACING=0 CELLPADDING=0> <TR> <TD ALIGN=right><B>First Name:</B></TD> <TD ALIGN=left><INPUT TYPE=text NAME="first_name*" VALUE=""> </TD> </TR> <TR> <TD ALIGN=right><B>Last Name:</B></TD> <TD ALIGN=left><INPUT TYPE=text NAME="last_name*" VALUE=""></TD> </TR> <TR> <TD ALIGN=right><B>Company:</B></TD> <TD ALIGN=left><INPUT TYPE=text SIZE=30 NAME="company*" VALUE=""></TD> </TR> <TR> <TD ALIGN=right><B>Address1:</B></TD> <TD ALIGN=left><INPUT TYPE=text SIZE=30 NAME="address1*" VALUE=""></TD> </TR> <TR> <TD ALIGN=right><B>Address2:</B></TD> <TD ALIGN=left><INPUT TYPE=text SIZE=30 NAME="address2" VALUE=""></TD> </TR> <TR> <TD ALIGN=right><B>City/Town:</B></TD> <TD ALIGN=left><INPUT TYPE=text SIZE=30 NAME="city*" VALUE=""></TD> </TR> <TR> <TD ALIGN=right><B>State/Province:</B></TD> <TD ALIGN=left><INPUT TYPE=text SIZE=10 NAME="state" VALUE=""><FONT SIZE=-1> Abbreviation or code</TD></TR> <TR> <TD ALIGN=right><B>Postal/Zip Code:</B></TD> <TD ALIGN=left><INPUT TYPE=text SIZE=10 NAME="zip" VALUE=""></TD> </TR> ------------------------------------------------------------ <continues here>

Figure C.16. Portion of the HTML registration form from Example C.21.

Example C.22

(From a CGI script) # An HTML Form was first created and processed to get the name of the # user who will receive the e-mail, the person it's from, and the # subject line. 1 $mailprogram="/usr/lib/sendmail"; # Your mail program goes here 2 $sendto="$input{xemailx}"; # Mailing address goes here 3 $from="$input{xmailx}"; 4 $subject="$input{xsubjext}"; 5 open(MAIL, "$mailprogram -t -oi") die "Can't open mail program: $!\n"; # -t option takes the headers from the lines following the mail # command -oi options prevent a period at the beginning of a # line from meaning end of input 6 print MAIL "To: $sendto\n"; print MAIL "From: $from\n"; print MAIL "Subject: $subject\n\n"; 7 print MAIL <<EOF; # Start a "here document" Registration Information for $input{$first_name} $input{$last_name}: Date of Registration: $today ----------------------------------------------- First Name: $input{$first_name} Last Name: $input{$last_name} Street Address: $input{$address} City: $input{$city} State/Province: $input{$state} <Rest of message goes here> 8 EOF 9 close MAIL; # Close the filter

EXPLANATION

  1. The name of the mail program being used here is sendmail , located in the UNIX subdirectory, /usr/lib.

  2. This line will be assigned to the To: header in the e-mail document.

  3. This line will be assigned to the From: header in the e-mail document.

  4. And this line is the Subject: header in the e-mail document.

  5. Perl is going to open a filter called MAIL that will pipe the user's e-mail message to the sendmail program. The -t option tells sendmail to scan the e-mail document for the To:, From: , and Subject: lines (instead of from the command line) and the -i option tells the mail program to ignore any period that may be found on a line by itself.

  6. These are the header lines indicating to whom the mail is going, where it's going, and the subject of the mail. These values were pulled from the form.

  7. A here document is started. The text between EOF and EOF is sent to the sendmail program via the MAIL filter.

  8. EOF marks the end of the here document .

  9. The MAIL filter is closed.

The Mail::Mailer Perl Module

Mail::Mailer provides a simple interface for sending Internet mail with sendmail and mail or mailx .

Example C.23

[View full width]

(From a CGI script) 1 use Mail::Mailer; 2 my $mailobj = new Mail::Mailer("smtp", Server=>"www.ellieq.com"); 3 $mailer -> open( { To => $emailaddress, From => $sender, Subject => "Testing email..." } ); # The mail message is created in a here document 4 print $mailobj << EOF; This is a test to see if the Mail::Mailer module is working for us. Thankyou for participating in this little experiment! EOF 5 close $mailobj;

EXPLANATION

  1. After downloading Mail::Mailer from CPAN, it is to be used in the CGI script.

  2. The constructor new is called with the name of the SMTP server passed as the first argument. Mail will use the Net:: SMTP Perl module to send the mail. The server will relay the message on to the e-mail address listed in the To: header. A pointer to the mail object is returned.

  3. The Mail::Mailer 's open method is called with an anonymous hash as an argument, consisting of three attributes: the To: field with the recipent's address, the From: field with the sender's address, and the Subject: field. The open method creates a Perl output filter. Output from the script will go as input to mail program.

  4. A here document is created to send the e-mail message.

  5. The object is closed; that is, the mail filter is closed.

E-mail and the mailto: Protocol

HTML anchors can be used to create links to files and to e-mail adresses. When a user selects the e-mail hyperlink, their e-mail program starts an e-mail message to the address specified in the HREF attribute. The mailto: protocol is followed by the valid e-mail address.

Example C.24

[View full width]

(Portion of the HTML form showing the e-mail hyperlink) </MENU> <P> Students unable to send appropriate payment information will be dropped from the class unceremoniously. <P> <I> If you would like to speak to one of our staff, please dial +1(530)899-1824. <BR> If you have a question , <A HREF="mailto:elizabeth@ellieq.com">click here.</A> <BR> <I><FONT SIZE=2>Provide as much detail in your request as possible, so that we may reply quickly and as informative as possible.</I> </TD> </TR> <BR> <BR>If you would like to speak with someone, please dial +1(530) 899-1824 <HR> -----------------------------------

Figure C.17. The HTML form and hyperlink to an e-mail address, from Example C.24.

Figure C.18. E-mail window that appears after clicking on the hyperlink, from Example C.24.

C.8.7 Extra Path Information

Information can also be provided to the CGI script by appending some extra path information to the URL of the HTML document. The path information starts with a forward slash ( / ) so that the server can identify where the CGI script ends and the new information begins. The information can then be processed in the CGI script by parsing the value of the PATH_INFO environment variable where this extra information is stored.

If the information appended is a path to another file, the PATH_TRANSLATED environment variable is also set, mapping the PATH_INFO value to the document root directory. The document root directory is found in the DOCUMENT_ROOT environment variable. The pathname is treated as relative to the root directory of the server.

Example C.25

(The HTML Document) 1 <HTML> 2 <HEAD> <Title>Testing Env Variables</title> </HEAD> <BODY> <P> <H1> Major Test </h1> <P> If You Would Like To See The Environment Variables<Br> Being Passed On By The Server, Click . 3 <A Href="Http://susan/cgi-bin/pathinfo.cgi/color=red/ size=small">here</a> <P> Text Continues Here... </BODY> </HTML>

Example C.26

(The CGI Script) #!/bin/perl 1 print "Content type: text/html\n\n"; print "CGI/1.0 test script report:\n\n"; print "The argument count is ", $#ARGV + 1, ".\n"; print "The arguments are @ARGV.\n"; # Print out all the environment variables 2 while(($key, $value)=each(%ENV)){ 3 print "$key = $value\n"; } print "=" x 30, "\n"; 4 print "$ENV{PATH_INFO}\n"; 5 $line=$ENV{PATH_INFO}; 6 $line=~tr/\// /; 7 @info = split(" ", $line); 8 print "$info[0]\n"; 9 eval "$$info[0]\n"; 10 print $color;

EXPLANATION

  1. The content type is text/html .

  2. The loop iterates through each of the ENV variables, assigning the key to $key and the corresponding value to $value .

  3. Each key and value is printed.

  4. The value for the $ENV{PATH_INFO} environment variable is printed.

  5. The value of $ENV{PATH_INFO} variable is assigned to the scalar $line .

  6. All forward slashes are replaced with spaces. /color=red/size=small will become color=red size=small and assigned to $line .

  7. The split function splits the scalar $line into an array, using spaces as the separator.

  8. The first element of the array, color=red , is printed.

  9. The eval function evaluates the expression and assigns red to $color .

  10. When the scalar $color is printed, the value is red.

Figure C.19. CGI output with extra path information, from Example C.26.

C.8.8 Server Side Includes

It is not always necessary to produce a full-blown CGI script just to get a small amount of data on the fly from a static HTML document. If you just wanted to know the name of a remote server, the current file, or the date and time, etc., it would seem silly to have to write a CGI script. Now most servers support a shortcut feature that allows the HTML document to output these small amounts of information without requiring an HTTP header. The feature is called SSI , short for Server Side Includes, which are really just HTML directives that are inserted into the HTML document; this type of file normally ends with .shtml .

FORMAT

<!--command option=value -->

Example C.27

<!--#exec cgi="/cgi-bin/joker/motto"-->

EXPLANATION

Executes the CGI program enclosed in quotes as though it was called from an anchor link.

Table C.13. Some common SSI commands.

Command

Example

Meaning

config

<!-- #config sizefmt="bytes" -->

Sets the format for display size of the file in bytes

echo

<!-- #echo var="DATE_GMT" -->

Prints the date in Greenwich Mean Time (same as UTC); other values are shown in Example C.28

exec

<!-- #exec cmd="finger" -->

Executes shell command finger

flastmod

<!-- $flastmod file="test.html" -->

Inserts a file in the current directory or in a subdirectory

fsize

<!-- #fsize file="test.html" -->

Prints the size of the file

include

<!-- #include file="myfile.html" -->

Inserts a file in the current directory or in a subdirectory

The following example is the HTML source test file from an OmniHTTPd Web server.

Example C.28

<HTML> <HEAD> <Meta Http-equiv="Pragma" Content="No-cache"> <Title>CGI And SSI Test</title> </head> <Body Bgcolor="#ffffff"> <H1>CGI And SSI Test</h1> <Hr> <H2>standard CGI Test</h2> You Are Visitor # <Img Src="/cgi-bin/visitor.exe"><P> <Hr> 1 <H2> Server Side Includes </h2> If Server Side Includes Are Enabled, You Will See Data Values Below: <P> 2 The Date Is: <!--#echo Var="Date_local"--> <Br> 3 The Current Version Of The Server Is: <!--#echo Var="Server_software"--> <Br> 4 The CGI Gateway Version Is: <!--#echo Var="Gateway_interface"--> <Br> 5 The Server Name Is: <!--#echo Var="Server_name"--> <Br> 6 This File Is Called: <!--#echo Var="Document_name"--> <Br> 7 This File's Uri Is: <!--#echo Var= "Document_uri"--> <Br> 8 The Query String Is: <!--# Echo Var="Query_string_unescaped"--> <Br> 9 This File Was Last Modified: <!--#echo Var="Last_modified"--> <Br> 10 The Size Of The Unprocessed File Is !--#fsize Virtual="/test.shtml"--> <Br> 11 You Are Using <!--#echo Var="Http_user_agent"--> <Br> 12 You Came From <!--#echo Var="Http_referer"--> <P> <Br> <Input Type="Submit" Value="Go!"> </FORM> <HR> </BODY> </HTML>

EXPLANATION

  1. Server side includes is enclosed in heading tags to print. If server side includes are enabled, you will see data values below:

  2. The date is : Jul 22 1999

  3. The current version of the server is : OmniHTTPd/2.0a2(Win32;i386)

  4. The CGI gateway version is : CGI /1.1

  5. The server name is : ellie.Learn1.com

  6. This file is called : C:\HTTPD\HTDOCS\test.shtml

  7. This file's URI is : /test/shtml

  8. The query string is:

  9. This file was last modified : Jun24 1997

  10. The size of the unprocessed file is 1989

  11. You are using Mozilla/2.01KIT (Win95; U)

  12. You came from http://127.0.0.1/default.htm

An Object-Oriented Perl/CGI Program

If you would like to study a complete CGI program, written by a professional Web developer, go to Appendix B.

Категории