Приглашаем посетить
Дружинин (druzhinin.lit-info.ru)

14.4 Passing data to CGI applications: name/value pairs

Table of Contents

Previous Next

14.4 Passing data to CGI applications: name/value pairs

Passing data to CGI applications is an important subject and is the first step for all kinds of server programming. Different server technologies such as Perl, PHP, and ASP may have different command names and data-passing procedures. Fortunately, they are all based on the same structure (CGI structure) and philosophy under the HTTP.

Basically, there are two data-passing methods used in CGI applications, namely, the get and post methods. You can specify them in the method attribute in a form. Basically, you pass information with a name and the value of that name, i.e., a name/value pair. Since data-passing methods and name/value pairs are the secret and success of all CGI applications, we will discuss them in detail via the browser/server interaction dialog.

14.4.1 Passing form contents with the get method

As soon as the Submit button of a form is pressed, every element with a name attribute between <form></form> will be passed to the CGI application specified by the form action. How these parameters are passed depends on the method attribute of the form. Consider the following form declaration:



<form action="my_perl.pl" method="get">
  Enter Your Name:
  <input type="text" name="usrName" id="usrName" value="">
  Telephone Number:
  <input type="text" name="tel" id="tel" value="">
  <input type="submit" value="Submit">
</form>

This is a form using the get method. When the method attribute is absent, the get method is the default. When the user enters "JohnSmith" and "01890-1234-5678" to the form and presses the Submit button, an HTTP request (canonical clientserver interaction) from the client would look something like



Listing: ex14-06.txt - An HTTP Message From The Client: get Method

 1: GET my_perl.pl?usrName=JohnSmith&tel=0189012345678
 2: Accept: www/source
 3: Accept: text/html
 4: Accept: image/gif
 5: Accept: image/jpg
 6: User Agent: xxxx
 7: From: xxxx
 8:   *** a blank line ***

As we can see from this message, the form contents are assembled into a query URL to the server as (see line 1)



GET my_perl.pl?usrName=JohnSmith&tel=0189012345678

The string after the first question mark "?" is called a query string. In this example, the query string passes two name/value pairs to the program my_perl.pl:



usrName=JohnSmith
tel=0189012345678

The left hand side is the name and the right hand side is the value. Name/value pairs are separated by an ampersand symbol "&." Some general rules for the query string are as follows:

  • Strange characters in any of the "name" or "value" string will be "escaped," i.e., encoded with the escape() function. This includes "=", "&," and punctuation. The space character is replaced by a "+" sign.

  • For text and password entry fields, the user input will be the value of the field. If the user didn't type anything, the value will be empty but the "name=" part of the query string will still be present.

  • For checkboxes and radio buttons, the value attribute specifies the value of a checkbox or radio button when it is checked.

  • Any unchecked checkbox is disregarded completely when assembling the query string. Multiple checkboxes can have the same name (and different values), if necessary.

  • Multiple radio buttons intended to have "one of many" behavior should have the same name and different values.

To see some of these rules in action, consider the example ex14-07.htm:



Example: ex14-07.htm - Using The get Method

 1: <?xml version="1.0" encoding="iso-88591"?>
 2: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 3: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 4: <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 5: <head><title> Using The get Method - ex1407.htm</title></head>
 6: <style>
 7:   .butSt{background:#aaffaa;width:200px;
 8:     font-family:arial;font-weight:bold;font-size:16pt;color:#880000}
 9: </style>
10: <body style="background:#000088;font-family:arial;font-size:18pt;
11:    color:#ffff00;font-weight:bold">
12: <form action="ex14-07.pl" method="get">
13:
14:  Enter Your Name:<input type="text" name="usrName"
15:    id="usrName" value="" class="butSt"><br /><br />
16:  Telephone Number:<input type="text" name="tel"
17:    id="tel" value="" class="butSt"><br /><br />
18:  <input type="submit" value="Submit" class="butSt">
19: </form>
20:
21: </body>
22: </html>

Figure 14.14. ex14-07.htm

graphics/14fig14.jpg


This is a simple form application and contains only two text fields. When the Submit button is clicked, the form contents are submitted to the Perl script ex14-07.pl (line 12). As a simple example, the script is constructed to output the query string and is listed below:



Example: ex14-07.pl - The Perl Script For ex14-07.htm

 1: #! /usr/bin/perl
 2:
 3: ## The magic string or CGI Application
 4: print ("Content-type/html\n\n");
 5:
 6: my $querySt = $ENV{ "QUERY_STRING" };
 7:
 8: print << "myDoc";
 9:  <?xml version="1.0" encoding="iso-88591"?>
10:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
11:  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
12:  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13:  <head><title>Perl Example: ex1407.pl</title></head>
14:  <body style="background:#000088;font-family:arial;font-size:18pt;
15:    color:#ffff00;font-weight:bold">
16: myDoc
17:
18: if ( $querySt eq "" )
19: {
20:   print 'We have received an empty input string';
21: } else {
22:   print 'The Query String For the get Method Is: <br /><br />',$querySt
23: }
24: print "</body></html>";

When this script is called, it returns a minimum CGI header "Content-type/html\n\n" to the browser (line 4) so that the server and the browser are linked together. Soon after that, a local variable $querySt is declared to store the environment QUERY_STRING which is the query string sent by the browser.

The rest of the program is to construct an XHTML document back to the browser. Since the query string is captured and stored in variable $querySt, a simple if statement in lines 1823 can be used to determine whether the string is empty. If the string is not empty, the print statement in line 22 will print it out.

Some screen shots of the example are shown in Figs 14.14 and 14.15. When the get method is used, the query string is appended in the URL at the address bar (see Fig. 14.15) and passed to the program.

Figure 14.15. Displaying the query string

graphics/14fig15.jpg


In order to have a more general and practical program, we need to get the name/value pairs from the query string one by one. Consider the following example:



Example: ex14-08.pl - The Perl Script For ex1408.htm

 1: #! /usr/bin/perl
 2:
 3: ## The magic string or CGI Application
 4: print ("Content-type:text/html\n\n");
 5:
 6: my $querySt = $ENV{ "QUERY_STRING" };
 7:
 8: print << "myDoc";
 9:  <?xml version="1.0" encoding="iso-88591"?>
10:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
11:  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
12:  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13:  <head><title>Perl Example: ex1408.pl</title></head>
14:  <body style="background:#000088;font-family:arial;font-size:18pt;
15:     color:#ffff00;font-weight:bold">
16: myDoc
17:
18: if ( $querySt eq "" )
19: {
20:   print 'We have received an empty input string';
21: } else {
22:   my @pairs = split ( "&", $querySt );
23:   printf "<br />The Input Form Contents are: <br />";
24:   foreach my $i (0 .. $#pairs)
25:   {
26:     my ( $name, $value ) = split ( "=", $pairs[$i] );
27:     print "'$name' = '$value'. <br />";
28:   }
29: }
30: print "</body></html>";

This Perl script is similar to ex14-07.pl in the sense that they both get the query string from the environment. Instead of displaying the query string entirely, this script splits the string into individual names and values.

The separation symbol for name/value pairs is "&." The statement in line 22 splits the string $querySt into a collection or array of "name=value" pairs. Now you apply the split function split() again to each element of the array @pairs using the for-loop as illustrated in lines 2428:



foreach my $i (0 .. $#pairs)
{
   my ( $name, $value ) = split ( "=", $pairs[$i] );
   print "'$name' = '$value'. <br />";
}

The first line declares a local variable $i and sets a loop from zero to the number of items or pairs. Then for each $i, the split function performs on $pairs[$i] at the symbol "=" and assigns the split result to $name and $value.

As an example of how to use this script, you may replace line 12 of ex14-07.htm as



12: <form action="ex1408.pl" method="get">

and call this new example ex14-08.htm. Now, this new example will display individual input fields as shown in Fig. 14.16.

Figure 14.16. ex14-08.htm

graphics/14fig16.jpg


For some short names and messages without strange characters, the Perl script ex14-08.pl is adequate to handle the input parameters. However, from the general rules of the query string we know that any special character in the name/value pairs is "escaped," i.e., encoded with the escape() function. In order to display these characters correctly, some modifications of ex14-08.pl and use of the unescape() function for decoding are necessary. The following Perl script, ex14-09.pl, is one of the modifications:



Example: ex14-09.pl - The Perl Script For ex14-09.htm

 1: #! /usr/bin/perl
 2:
 3: ## Minimum Requirement For CGI Application
 4: print ("Content-type:text/html\n\n");
 5: my $querySt = $ENV{ "QUERY_STRING" };
 6:
 7: print << "myDoc";
 8:  <?xml version="1.0" encoding="iso-88591"?>
 9:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
10:  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
11:  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
12:  <head><title>Perl Example: ex1409.pl</title></head>
13:  <body style="background:#000088;font-family:arial;font-size:18pt;
14:    color:#ffff00;font-weight:bold">
15: myDoc
16:
17: if ( $querySt eq "" )
18: {
19:   print 'We have received an empty input string';
20: } else {
21:   my @pairs = split ( "&", $querySt );
22:   print "Time : ",scalar(localtime());
23:   printf "<br />The Submitted Form Contents are: <br />";
24:   foreach my $i (0 .. $#pairs)
25:   {
26:     ## Convert plus's to spaces
27:     $pairs[$i] =~ s/\+/ /g;
28:     my ($name, $value) = split("=",$pairs[$i]);
29:
30:     # Convert %xx from hex numbers to alphanumeric
31:     $name =~ s/%(..)/pack("c",hex($1))/ge;
32:     $value =~ s/%(..)/pack("c",hex($1))/ge;
33:   print " '$name' = '$value' <br />";
34:   }
35:   print "====================================="
36: }
37: print "</body></html>";

To develop a script suitable for practical purposes, we have added a time feature in line 22 to display a string of date and time. From the general rules of the query string, the spaces of the name/value pairs are replaced by the "+" sign. A matching technique is employed in line 27 to convert the "+" signs back to spaces. In order to convert the ASCII value %nn back to alphanumeric, the following statement is used:



$name =~ s/%(..)/pack("c",hex($1))/ge;

This is a replacement statement from pattern matching to replace the hex value %xx with its corresponding character. We have covered pattern matching in some detail in Chapter 13. In fact, pattern matching is a feature that originated from Perl.

If you prefer, you can ask ECMAScript to convert the %xx for you by using its unescape() function. For example, you can use the statement



print "'$name' = '<script>document.write(unescape('$value'))</script>'";

to output a normal string to the browser. In this case, ECMAScript is doing the conversion for you. To see the difference, let's replace line 12 of ex14-08.htm by



12: <form action="ex1409.pl" method="get">

and call this new example ex14-09.htm. If you enter the following name and telephone number with some empty spaces and punctuation into the form



Name: Mr. John JohnSmith
Telephone Number: (01890) 1234 5678

you will see the difference. The results of ex14-08.htm and ex14-09.htm are shown in Figs 14.17 and 14.18.

To summarize the behavior of the get method, we have the following statement:

  • The get method of the form is the default method to pass form contents to CGI applications and causes parameters to be appended to the URL as if they were a normal query.

Figure 14.17. Escaped messages (ex14-08.htm)

graphics/14fig17.jpg


Figure 14.18. Unescaped messages (ex14-09.htm)

graphics/14fig18.jpg


14.4.2 Using the post method

Another data-passing method often used with form is the post method. The contents of the form are encoded exactly as with the get method mentioned above. Unlike the get method, the form contents of the post method are sent in a data block as part of the clientserver operation.

Consider the following "name and telephone" example fragment:



<form action="my_perl_2.pl" method="post">
  Enter Your Name:
  <input type="text" name="usrName" id="usrName" value="">
  Telephone Number:
  <input type="text" name="tel" id="tel" value="">
  <input type="submit" value="Submit">
</form>

This is a form application using the post method. When the form is filled out as



Enter Your Name: Mr. John JohnSmith
Telephone Number: (01890) 1234 5678

and submitted to the server, the following information (clientserver interaction) or something similar is sent to www.pwt-ex.com by the browser:



Listing: ex14-07.txt - An HTTP Message From The Client: the post Method

 1: POST /my_perl_2.pl HTTP/1.0
 2: Accept: www/source
 3: Accept: text/html
 4: Accept: image/gif
 5: Accept: image/jpg
 6: User Agent: xxxx
 7: From: xxxxxx
 8: Content-type: application/x-www-form-urlencoded
 9: Content-length: 52
10:   *** a blank line ***
11: usrName=Mr.+John+JohnSmith
12: &tel=%2801890%29+1234+5678

Sometimes, the post method is also called the post-query. This post-query requests the file my_perl_2.pl from the root directory of the server (line 1). In this case, the file is a Perl script and in fact can be any CGI applications acceptable by the CGI and server.

Unlike most clientserver interactions for which the content type (line 8) is usually text/html to indicate an XHTML document, the content type in this case is the MIME type specified as application/x-www-form-urlencoded. This means that the variable "name/value" pairs will be encoded in the same way as a URL encoding. The total length of data (lines 1112) is 52 and stored in the content length (line 9) environment.

Bearing the clientserver interaction in mind, you now have a basic picture of how CGI works and in particular how HTML/XHTML works as mentioned in Chapter 1. HTML/XHTML can be considered as a special case of CGI applications where the browser sends a simple HTTP message to get an HTML/XHTML document.

As a demonstration example, we change line 12 of ex14-09.htm to



12: <form action="ex1410.pl" method="post">

and call this new example ex14-10.htm. This example is a form application with the post method. When the form is submitted, the form contents are sent to the Perl script ex14-10.pl. The main function of this script is to output the content length and the entire post-query string as illustrated in lines 9, 11, and 12 of the listing ex14-07.txt. Some screen shots are shown in Figs 14.19 and 14.20.

Figure 14.19. ex14-10.htm

graphics/14fig19.jpg


Figure 14.20. The post-query string

graphics/14fig20.jpg


The listing of the Perl script ex14-10.pl is as follows:



Example: ex14-10.pl - The Perl Script For ex14-10.htm

 1: #! /usr/bin/perl
 2:
 3: ## Demonstration Script On The post Method
 4: ## The first thing after the Content-type is
 5: ## to read the data block with CONTENT_LENGTH
 6:
 7: print ("Content-type/html\n\n");
 8:
 9: my $postQuerySt;
10: read(STDIN, $postQuerySt, $ENV{'CONTENT_LENGTH'});
11:
12: print << "myDoc";
13:  <?xml version="1.0" encoding="iso-88591"?>
14:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
15:  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
16:  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
17:  <head><title>Perl Example: ex1410.pl</title></head>
18:  <body style="background:#000088;font-family:arial;font-size:18pt;
19:    color:#ffff00;font-weight:bold">
20: myDoc
21:
22: print "Content-length = $ENV{CONTENT_LENGTH} <br />";
23: print "Post-query String = $postQuerySt";
24: print "</body></html>";

After the CGI header in line 7, a local variable $postQuerySt is declared to store the post-query string. To get the post-query string from the clientserver interaction, you need to issue a read command to read from the standard input as illustrated in line 10. The third argument of the read command, $ENV{'CONTENT_LENGTH'}, represents the length of the string so that you have a proper reading. The content length and the post-query string are output to the screen by executing the print statements in lines 22 and 23.

To convert the encoded string back to a normal string and split the name/value pairs into individual items, let's modify the Perl script in ex14-10.pl to accept the post-query. This new Perl script is called ex14-11.pl and listed below:



Example: ex14-11.pl - The Perl Script For ex14-11.htm

 1: #! /usr/bin/perl
 2:
 3: ## Minimum Requirement For CGI Application
 4: print ("Content-type:text/html\n\n");
 5:
 6: my $postQuerySt;
 7: read(STDIN, $postQuerySt, $ENV{'CONTENT_LENGTH'});
 8:
 9: print << "myDoc";
10:  <?xml version="1.0" encoding="iso-88591"?>
11:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
12:  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
13:  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
14:  <head><title>Perl Example: ex1411.pl</title></head>
15:  <body style="background:#000088;font-family:arial;font-size:18pt;
16:    color:#ffff00;font-weight:bold">
17: myDoc
18:
19: if ( $postQuerySt eq "" )
20: {
21:   print 'We have received an empty input string';
22: } else {
23:   my @pairs = split ( "&", $postQuerySt );
24:   print "Time : ",scalar(localtime());
25:   printf "<br />The Submitted Form Contents are: <br />";
26:   foreach my $i (0 .. $#pairs)
27:   {
28:     ## Convert plus's to spaces
29:     $pairs[$i] =~ s/\+/ /g;
30:     my ($name, $value) = split("=",$pairs[$i]);
31:
32:     # Convert %XX from hex numbers to alphanumeric
33:     $name =~ s/%(..)/pack("c",hex($1))/ge;
34:     $value =~ s/%(..)/pack("c",hex($1))/ge;
35:   print " '$name' = '$value' <br />";
36:   }
37:   print "====================================="
38: }
39: print "</body></html>";

This script is similar to ex14-09.pl. The only modification is in lines 67 and changes the query string ($querySt) to a post-query string ($postQurySt). Line 7 is used to read the data string from the HTTP message. Once you have the data stored in the variable $postQuerySt, the process for splitting the name/value pairs is the same.

Let's consider another example based on ex14-06.htm. We replace the form definition (lines 1974) of ex14-06.htm by the form in ex14-08.txt and call this new example ex14-11.htm.



Listing: ex14-08.txt - Example Fragment Of ex14-11.htm

 1: <form action="ex1411.pl" style="text-align:center" method="post">
 2:
 3: <table class="txtSt" cellspacing="5"><tr><td>Name:</td>
 4:  <td><input type="text" name="usrN" id="usrN" class="butSt" /></td>
 5:  <td>Email Address:</td>
 6:  <td><input type="text" name="email" id="email" class="butSt" /></td>
 7: </table><br />
 8:
 9: Which Operating System Do You Like Best?<br /><br />
10: <table cellspacing="5" border="0">
11: <tr><td><input type="radio" name="os" id="os" class="butSt2"
12:    value="Windows 9x" checked /></td><td class="txtSt">Windows 9x</td>
13:  <td><input type="radio" name="os" id="os" class="butSt2"
14:    value="Windows NT" /></td><td class="txtSt">Windows NT</td></tr>
15: <tr><td><input type="radio" name="os" id="os" class="butSt2"
16:    value="Mac OS" /></td><td class="txtSt">Mac OS</td>
17:  <td><input type="radio" name="os" id="os" class="butSt2"
18:    value="LINUX" /></td><td class="txtSt">LINUX</td></tr>
19: </table><br />
20:
21: Which Browser Do You Like Best?<br /><br />
22: <table cellspacing="5" border="0">
23: <tr><td><input type="radio" name="br" id="br" class="butSt2"
24:    value="IE 6+" checked /></td><td class="txtSt">IE 6</td>
25:  <td><input type="radio" name="br" id="br" class="butSt2"
26:    value="IE 5.5" /></td><td class="txtSt">IE 5.5</td></tr>
27: <tr><td><input type="radio" name="br" id="br" class="butSt2"
28:    value="NS 6+" /></td><td class="txtSt">NS 6.1</td>
29:  <td><input type="radio" name="br" id="br" class="butSt2"
30:    value="NS 4.x" /></td><td class="txtSt">NS 4.x</td></tr>
31: <tr><td><input type="radio" name="br" id="br" class="butSt2"
32:    value="Opera" /></td><td class="txtSt">Opera</td>
33:  <td><input type="radio" name="br" id="br" class="butSt2"
34:    value="Mozilla" /></td><td class="txtSt">Mozilla</td></tr>
35: </table><br />
36:
37: <table class="txtSt" cellspacing="5"><tr>
38:  <td><input type="submit" value="Submit" class="butSt" /></td>
39:  <td><input type="reset" value="Reset" class="butSt" /></td></tr>
40: </table>
41:
42: </form>

Figure 14.12. ex14-06.htm

graphics/14fig12.jpg


Figure 14.21. ex14-11.htm

graphics/14fig21.jpg


This fill-out form is a questionnaire trying to collect information on favorite operating system and browser from users. The user name and email fields are defined in the first table. The favorite operating system and browser questions are defined in the second and third tables respectively. They are in the format of multiple choices with radio boxes. When the form is submitted, the Perl script ex14-11.pl is called and the results are displayed. Some screen shots are shown in Figs 14.21 and 14.22.

Figure 14.22. The collected results

graphics/14fig22.jpg


Naturally, the next question will be: "Can we have a script to collect form contents regardless of the get or post methods?"

14.4.3 A general script for the get and post methods

If you know the name attribute of an element, the param() function of the Perl script can be used to extract the value of that element. This function applies to most XHTML elements and contains no additional restrictions. For example, suppose you have a form fragment



<form action="my_perl.pl" method="post">
  Enter Your Name:
  <input type="text" name="usrName" id="usrName" value="">
  Telephone Number:
  <input type="text" name="tel" id="tel" value="">
  <input type="submit" value="Submit">
</form>

You can gain access to the value of usrName with the following Perl statement in my_perl.pl:



my $username = param('usrName');

The param() function is a useful and widely used function and, in many cases, elegant results can be achieved. However, to use param() function, you may need to have an additional CGI module installed. Also, to include a specific name in a script would mean that you may need to change the script at the same time when you want to change the name. For example, if you want to change the form above to get an email address instead of a telephone number, you need to change param(). How can we have a Perl script work on both get and post methods and independently of parameter name?

One solution is to use detection. In Perl script the request method is stored in the environment variable $ENV{'REQUEST_METHOD'}. This variable returns "GET," if the get method is used; if this variable returns "POST," you know that the post method is in action.

Consider the following Perl script:



Example: ex14-12.pl - Combining The get And post Methods

 1: #! /usr/bin/perl
 2:
 3: ## Minimum Requirement For CGI Application
 4: print ("Content-type:text/html\n\n");
 5:
 6: my $formSt="UNKNOWN";
 7: if ($ENV{'REQUEST_METHOD'} eq "GET")
 8: {
 9:     $formSt = $ENV{'QUERY_STRING'};
10: } elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
11:     read(STDIN,$formSt,$ENV{'CONTENT_LENGTH'});
12: }
13:
14: print << "myDoc";
15:  <?xml version="1.0" encoding="iso-88591"?>
16:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
17:  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
18:  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
19:  <head><title>Perl Example: ex1412.pl</title></head>
20:  <body style="background:#000088;font-family:arial;font-size:18pt;
21:    color:#ffff00;font-weight:bold">
22: myDoc
23:
24: if ( $formSt eq "" )
25: {
26:   print 'We have received an empty input string';
27: } else {
28:   my @pairs = split ( "&", $formSt );
29:   print "Time : ",scalar(localtime());
30:   printf "<br />The Submitted Form Contents are: <br />";
31:   foreach my $i (0 .. $#pairs)
32:   {
33:     ## Convert plus's to spaces
34:     $pairs[$i] =~ s/\+/ /g;
35:     my ($name, $value) = split("=",$pairs[$i]);
36:
37:     # Convert %XX from hex numbers to alphanumeric
38:     $name =~ s/%(..)/pack("c",hex($1))/ge;
39:     $value =~ s/%(..)/pack("c",hex($1))/ge;
40:   print " '$name' = '$value' <br />";
41:   }
42:   print "====================================="
43: }
44: print "</body></html>";

This script is a modification of ex14-10.pl, the only modification being the detection code in lines 612. If the request method equals "GET," the query string $ENV('REQUEST_STRING') is assigned to the variable $formSt (form string); if the request method is "POST," read the post-query string from the standard input and assign it to variable $formSt.

Now you have a general purpose Perl script to get form contents. This script will be used later in an e-commerce example. For further studies or if you want to program your own CGI applications with your favorite language, the following information and discussion may help.

For the get method, the string "GET" and the name/value pairs (query string) are stored in the environment variables "REQUEST_METHOD" and "QUERY_STRING" respectively. These settings are standard and independent of any programming language. If you are familiar with a programming language or script that can access the environment of your system, you can use it to gain access to the data passed by the XHTML form via the browser. The following listing is the pseudo code to read the query string associated with the get method:



form_method = read_env("REQUEST_METHOD");
if ( form_method eq "GET") then
 query_st = read_env("QUERY_STRING");
endif

The first line is to get the value of the environment variable "REQUEST_METHOD" and assign it to the variable form_method. If form_method equals "GET" then get the value of the "QUERY_STRING" and assign it to the variable query_st. If you are using C/C++, you can replace read_env("REQUEST_METHOD") by getenv("REQUEST_METHOD").

For the post method, the string "POST" and the length of the query string are stored in the environment variables "REQUEST_METHOD" and "CONTENT_LENGTH." The query string itself is passed as a data block via the standard input (similar to keyboard input). To get the query string from the post method, the following pseudo code may be used:



form_method = read_env("REQUEST_METHOD");
if ( form_method eq "POST") then
 noChar = read_env("CONTENT_LENGTH");
 query_st = read (STDIN,noChar);
endif

First you get the request method from the environment "REQUEST_METHOD." If it is a "POST" method, you get the number of characters (noChar) of the query string from the environment "CONTENT_LENGTH." The query string can be obtained by reading noChar, the number of characters, from the standard input (STDIN) or keyboard. Next, can we pass data to a CGI application without using forms?

14.4.4 Passing parameters without forms

In fact, any XHTML element with URL as attribute can call CGI applications and pass data. If you want to call and pass parameters to a CGI application with these elements, all you need is to append the parameters to the URL. Indeed, the ability to append data or parameters to an arbitrary URL makes it possible to construct elements such as <anchor> to send data to server scripts when they are activated. This allows XHTML programmers to set up so-called "canned queries" in the document and pass parameters to CGI programs easily when other passing techniques are difficult or impossible. Canned queries are used everywhere on the Web and some people consider the get method as a canned query too.

From a practical point of view, one characteristic of the canned query is that the name/value pairs will appear at the address bar of your browser since the name/value pairs are appended to the URL. Almost all major sites are using them in one way or another.

For example, the following page fragment could generate a list of conferences related to "Public Health," "Cancer Treatments," and "Healthy Diet":



Click the topic below for a list of conferences:

<a href="http://www.pwt-ex.com/search_engine?
   year=2003&conf_topic=public_health">Public Health</a>
<a href="http://www.pwt-ex.com/search_engine?
   year=2003&conf_topic=Cancer_Treatments">Cancer Treatments</a>
<a href="http://www.pwt-ex.com/search_engine?
   year=2003&conf_topic=Healthy_Diet">Healthy Diet</a>

Note that the attribute href="xx…xx" defined in each anchor element should be in one line since it represents a single string. When, for example, the "Public Health" topic is clicked, the anchor action will activate the CGI application search_engine with the name/value pair parameters, i.e.,

http://www.pwt-ex.com/search_engine?year=2002&conf_topic=public_health

The CGI application search_engine in this case can be designed to handle the parameters as input and generate the appropriate list. Since you should know the CGI application that you developed, parameters can be "canned" in as name/value pairs. This is just a virtual example fragment since we haven't yet considered databases. Another practical example is given in the next section.

14.4.5 A page to log on to multiple sites

Suppose you have three offices around the world in London, New York, and Tokyo. Each office has a Web server and is protected by a password login. The Internet addresses of the Web servers are

www.pwt-ex.com (London server)

www.pwt-ex.jp (Tokyo server)

www.pwt-ex.ne (New York server)

Suppose they are protected by the same password program ex14-13.pl. This program will ask for a user name (usern) and password (passw) before any server operation can be granted. Gaining access to these three computer servers is your daily business and your user name and password are

User name: johnsmith

Password: john199

Instead of typing your user name and password every time to log in to the server, you can actually develop a local Web page in your hard drive to log in to any of the servers at any time.

Consider the following page:



Example: ex14-13.htm - A Page To Log On To Multiple Sites

 1: <?xml version="1.0" encoding="iso-88591"?>
 2: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 3: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 4: <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 5: <head><title>Log On To Multiple Sites - ex1413.htm</title></head>
 6: <style>
 7:   .butSt{width:400px;font-family:arial;font-weight:bold;
 8:   font-size:18pt;color:#ffff00}
 9: </style>
10: <body style="background:#000088;font-family:arial;font-size:18pt;
11:    color:#ffff00;font-weight:bold">
12: Connect To Multiple Offices<br /><br />
13:
14: <a href="ex14-13.pl?usern=johnsmith&passw=john199"
15:     class="butSt">Connect local (London) office</a>
16: <a href="ex14-13.pl?usern=johnsmith&passw=john199"
17:     class="butSt">Connect To Tokyo office</a>
18: <a href="ex14-13.pl?usern=johnsmith&passw=john199"
19:     class="butSt">Connect To New York office</a>
20:
21: </body>
22: </html>

This page contains three texts, each defined by an anchor element. The first anchor element is



<a href="ex1413.pl?usern=johnsmith&passw=john199"
       class="butSt">Connect local (London) office</a>

This statement displays an underlined text "Connect local (London) office." When this text is clicked, the CGI application ex14-13.pl is activated with



usern=johnsmith&passw=john199

as the query string. The name/value pairs of the query string will be processed by the password program ex14-13.pl to perform the login operation. The listing of ex14-13.pl is given below:



Example: ex14-13.pl - The Perl Script For ex1413.htm

 1: #! /usr/bin/perl
 2: use warnings;
 3: use strict;
 4: use CGI qw( :standard );
 5: print ("Content-type/html\n\n");
 6:
 7: my $username = param("usern");
 8: my $password = param("passw");
 9: my $matchuser=0;
10: my $matchpass=0;
11:
12: my @name = ("johnsmith","Robinson","Brown");
13: my @pass = ("john199","Mike100","Tom111");
14:
15: foreach my $ii (0..2)
16: {
17:   if($name[$ii] eq $username)
18:   {
19:       $matchuser = 1;
20:     if ($pass[$ii] eq $password)
21:     {
22:       $matchpass = 1;
23:     }
24:   }
25: }
26:
27: print << "myDoc";
28:  <?xml version="1.0" encoding="iso-88591"?>
29:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
30:  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
31:  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
32:  <head><title>Perl Example: ex1413.pl</title></head>
33:  <body style="background:#000088;font-family:arial;font-size:18pt;
34:    color:#ffff00;font-weight:bold">
35: myDoc
36:
37: if ($matchuser && $matchpass)
38: {
39:     print "Thank you! $username.<br />";
40:     print "You have logged on successfully.";
41: }
42: elsif ($matchuser && !$matchpass)
43: {
44:     print "Sorry! $username.<br />";
45:     print "Wrong password.";
46: }
47: else
48: {
49:     print "Sorry! Access Denied.";
50: }
51:
52: print "</body></html>"

After the CGI header in line 5, we use two param() functions to get the user name (usern) and password (passw) data from the query string of the Web page. Two local variables, $matchuser and $matchpass, are also declared. They are used to indicate whether the user name and/or password are matched. Soon after the variables, two arrays are declared which store the list of user names and their corresponding passwords. As a simple demonstration example, only three names and passwords are included. A proper password program should read the data from a file or storage media and is the subject of the next chapter. Before that, we just want to hard-code the user names and passwords as arrays.

The main operation of this password program is the for-loop in lines 1624. The loop variable $ii runs from 0 through 2. That is, for each name in the array $name[], a comparison test takes place against the user name variable $username. If they match, we set the $matchuser as true. The comparison test is carried on to test the password. If a match is found, the variable $matchpass is also set to be true. The conditions of $matchuser and $matchpass are used to determine whether you are allowed to gain access to the system. If both $matchuser and $matchpass are true, you are allowed to use the system and a welcome message is displayed. If $matchuser is true but not in $matchpass, then we have a wrong password case as illustrated in lines 4246. If the user name is wrong, the login is denied and a message is displayed as in line 49. This script will be revisited in the next chapter to build a proper password program.

Some screen shots are shown in Figs 14.23 and 14.24.

Figure 14.23. ex14-13.htm

graphics/14fig23.jpg


Figure 14.24. Successful logon

graphics/14fig24.jpg


    Table of Contents

    Previous Next