Previous Page TOC Index Next Page See File


6

How To Use Environment Variables in Your Programs

It seems like every time you turn around, you run into some code that uses environment variables. Environment variables are certainly integral to making your CGI programwork. In this chapter, you will learn all about CGI environment variables and get exposed to the different types of environment variables on your server. In addition, you will learn about two programs that let you see the environment variables with which your CGI programis working.

In particular, you will learn:

Understanding Environment Variables

How does my program figure out how much data to read? Can I tell what type of browser is calling my CGI program? How can I get the name of the person that called my Web page? What do all these environment variables mean? What are environment variables? STOP!

That one is a good place to start.

You're familiar with variables by now; they are the placeholders for data that can change and data that you want to reference again elsewhere in your program. Well, that's what environment variables are, with one extra feature. That extra feature has to do with a term called scope.

Program Scope

When you set a variable in your CGI program, only your CGI program knows about that variable. In fact, by using the local command in Perl, you can limit the "knowledge" of a variable to the block of code in which you are executing. Just add the local(variable list); command between any enclosing curly braces ({}) and you get variables that only the code in those enclosing braces knows about. Any code outside the block of code or curly braces will not have any knowledge of the variables inside the block of code.

If you take the program fragment in Listing 6.1 as an example, the print statement in line 3 prints

Mozilla/1.1N (Windows; I; 16bit)

and the print statement on line 5 prints testing scope. The rules of block scope can be summed up as follows: Whatever is defined with the local command is limited in scope to the enclosing code block.

$browser = "testing scope";
{
   local($browser) = $ENV{'HTTP_USER_AGENT'};
   print "The local browser is $browser \n" ;
}
print "The original browser is $browser \n" ;

Why would you want to do this? Well, the most common application is for subroutine parameter passing. By assigning the incoming parameter list to a local variable list, you have changed from a call by reference to a call by value paradigm. This means that your CGI code can modify the input parameters and not affect the code that called your subroutine. The best advice I can give you is to use local variables, especially in subroutines. You'll find that you save lots of debugging time as you develop your CGI programs.

Let's get back to environment variables. Remember the difference we're talking about is File variables versus environment variables and the scope of those environment variables. The scope of environment variables is the process in which they are executing.

This means that environment variables are the same for every process started within the same executing shell. Did I lose you with that sentence? I'll try to restate it—I'm trying to avoid the use of the word environment to describe environment variables. Every process or program you start has an environment of data with which it begins. Part of the data that the program starts with is the environment variable data. Every process or program you start will have the same environment variables available to them.

So enough with explanations. Let's talk some details. If I type env at the Unix command line, what do I get? The simple answer is that I get the environment variables that are available to my program when executing from the command line. But first, maybe you're asking, "Why do I care about what type of environment variables are available from the command line?" You care because you should be testing your CGI programs by first executing them at the command line. This at least gets rid of all the syntax errors.

When you run your CGI program from the command line, however, not all the environment variables your program may need are available. So this is only the beginning of testing your program. In addition to being aware of what is available to your program at the command line, you also need to understand what the differences are between command line environment variables and when someone calls your CGI program from a Web page.

The environment variables available to my CGI programs from the command line are shown in Listing 6.2. Probably the most important variable that is different is the Path variable.

TERM=vt102
HOME=/usr/u/y/yawp
PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11/bin:/usr/andrew/bin:/usr/openwin/bin:/usr/games:.
SHELL=/bin/tcsh
MAIL=/var/spool/mail/yawp
LOGNAME=yawp
SHLVL=1
PWD=/usr/u/y/yawp
USER=yawp
HOST=langley
HOSTTYPE=i386-linux
OPENWINHOME=/usr/openwin
MANPATH=/usr/local/man:/usr/man/preformat:/usr/man:/usr/X11/man:/usr/openwin/man
MINICOM=-c on
HOSTNAME=langley.io.com
LESSOPEN=|lesspipe.sh %s
LS_COLORS=:
LS_OPTIONS=--8bit --color=tty -F -T 0
WWW_HOME=lynx_bookmarks.html

The Path Environment Variable

The Path environment variable can be found in Figures 6.1 through 6.5, and it's different for each figure. This is very important to you! The Path environment variable defines how your CGI program will find any other data or programs within your server. If your CGI program includes another file, when the Perl interpreter goes to search for that file, it uses the Path environment variable to define the areas where it will search. The same is true for system commands or other executable programs you run from within your CGI programs. The Path environment variable tells the system how and where to look for programs and files outside your CGI program.

Let's use the Path environment variable in Listing 6.2 as an example. When you execute a program from the command line, Unix looks at the Path environment variable. The Path environment variable tells Unix in which directories to look for executable programs and data. Unix reads the Path environment variable from left to right, so it starts looking in the first directory in the Path defined in Listing 6.2. The first directory is /usr/local/bin. If your program can't find what it is looking for there, it looks in the next directory, /usr/local. Each new directory is separated by the colon (:) symbol. Let's skip everything in the middle and move to the last directory. You might have missed this one, and it's one of the most important. The period (.) at the end of the Path environment variable line is not a grammatical end of sentence; it is a command to the Unix system. The period (.), in this context, tell Unix to look in the current directory. The current directory will be the directory in which your CGI program resides.

It's not always desirable to look in the current directory last. If the server begins its search elsewhere first, it might find a program that has the same name as yours and run it instead of your CGI program. Also, it's slower. If the program you want to run is in the current directory and the server has to search through every directory in the Path environment variable before it finds it in the current directory, that's time wasted! Take a look at the Server Side Include Path environment variable in Listing 6.3. Suppose that you're executing a CGI program that uses another CGI program that's in the same directory. The server has to search through every directory until it finds the "." directory (the current directory). That's 33 searches before it finds the correct path. Remember that the Path environment variable is used by your operating system to find the programs and data your CGI programs need to execute.

Getting the environment variables on your server is not very difficult. The Server Side Include environment variables in Listing 6.3 are from a single SSI command: <!--# exec cmd="env" -->. You would think that running an SSI would be the same as running a command from the command line. Obviously, it's Not! This is a clear example in which you can see the difference between running your command from the command line and running it from within your CGI program.

DOCUMENT_NAME=env.shtml
SCRIPT_FILENAME=/usr/local/business/http/accn.com/cgibook/chap6/env.shtml
SERVER_NAME=www.accn.com
DOCUMENT_URI=/cgibook/chap6/env.shtml
REMOTE_ADDR=199.170.89.42
TERM=dumb
HTTP_COOKIE=s=dialup-3240811768697386
HOSTTYPE=i386
PATH=/home/c/cloos/bin:/usr/local/gnu/bin:/usr/local/staff/bin:/usr/local/X11R5/bin:/usr/X11/bin:
/etc:/sbin:/usr/sbin:/usr/local/bin:/usr/contrib/bin:/usr/games:/usr/ingres/bin:/usr/ucb:/home/c/cloos/bin:
/usr/local/gnu/bin:/usr/local/staff/bin:/usr/local/X11R5/bin:/usr/X11/bin:/etc:/sbin:/usr/sbin:/usr/local/bin:
/usr/contrib/bin:/usr/games:/usr/ingres/bin:/usr/ucb:/usr/local/bin:/bin:/usr/bin:/usr/X11/bin:/usr/andrew/bin:
/usr/openwin/bin:/usr/games:.:/sbin:/usr/sbin:/usr/local/sbin:/usr/X11/bin:/usr/andrew/bin:/usr/openwin/bin:
/usr/games:.
SHELL=/bin/tcsh
SERVER_SOFTWARE=Apache/0.8.13
DATE_GMT=Friday, 22-Sep-95 13:56:58 CST
REMOTE_HOST=dialup-4.austin.io.com
LAST_MODIFIED=Friday, 22-Sep-95 08:55:11 CDT
SERVER_PORT=80
DATE_LOCAL=Friday, 22-Sep-95 08:56:58 CDT
DOCUMENT_ROOT=/usr/local/business/http/accn.com
OSTYPE=Linux
HTTP_USER_AGENT=Mozilla/1.1N (Windows; I; 16bit)
HTTP_ACCEPT=*/*, image/gif, image/x-xbitmap, image/jpeg
DOCUMENT_PATH_INFO=
SHLVL=1
SERVER_ADMIN=webmaster@accn.com
_=/usr/bin/env

Printing Your Environment Variables

The next question you should be asking is, "Are the Server Side Include environment variables different from the environment variables available to my CGI program?" Figures 6.1 through 6.3 are listings of the environment variables available when I run a CGI program on my server. The CGI program for printing these environment variables is in Listing 6.4.

Figure 6.1.

Figure 6.2.

Figure 6.3.


Figures 6.1-6.3. The CGI environment variables as printed by the Print Environment Variables function.

The CGI program in Listing 6.4 is a simple little script that you now should be comfortable reading and understanding. It has a few functions in it that I haven't talked about yet. Because both of these functions are useful for lots of other purposes, I'll use this program to introduce them to you. The Print Environment variable's CGI program uses the Perl sort function and the Perl keys function (I mentioned the keys function in previous chapters). Both of these functions are handy tools to have available in your programming toolbox. The keys function enables you to determine how your associative array is indexed, and the sort function puts the array of indexes returned from keys into alphabetical order.

As you can see, the environment variables available to your CGI program are even different from the environment variables available to your SSI programs.

Why is there such a difference? As I said earlier, environment variables are based on the process from which your program executes. The command line, SSI, and CGI program all have different process environments. The command-line environment is based on your initial login environment. From the command line, you get a custom environment that you can customize through startup scripts.

Because it is started by your Web server, the SSI environment starts with the environment available to a CGI program. However, when it executes a Unix command like "env", it also gets the environment available at the command line. This happens because the SSI command must open a command-line process in order to run. So it gets the existing CGI environment variables plus the new environment variables available when it opened the command-line process.

Your CGI program gets its environment from your Web server—in this case, the Apache/0.8.13.

01: #!/usr/local/bin/perl
02: push(@INC, "/cgi-bin");
03: require("cgi-lib.pl");
04: print &PrintHeader;
05: print "<html>\n";
06: print "<head> <title> Environment Variables </title> </head>\n";
07: print "<body>\n";
08: print <<"EOF";
09: <center>
10: <table border=2 cellpadding=10 cellspacing=10>
11: <th align=left><h3>Environment Variable</h3>
12: <th align=left> <h3>Contents </h3><tr>
13: EOF
14: foreach $var (sort keys(%ENV))
15: {
16:     print "<td> $var <td> $ENV{$var}<tr>";
17: }
18: print <<"EOF"
19: </table>
20: </body>
21: </html>
22: EOF

Because each method of printing these environment variables starts with a different executing environment, the environment variables available to each are different.

The keys function is solely for use with Perl's associative arrays. Remember that associative arrays are indexed by strings. This can make programming painful when you are trying to get data out and you are not sure what's in the array. This is clearly the case with the ENV array. You really don't know what's in it. For one thing, not always the same environment variables are available to your CGI program. We'll talk about that in more detail later in this chapter. Of course, Perl makes things easy rather than hard. So there must be a simple way to get the data out of an associative array, even if you don't know what the indexes are.

Anyway, the keys function returns an array or a list (arrays and lists are the same thing as far as Perl is concerned) of the indexes to an associative array. The order of the returned indexes is based on how the associative array first was constructed. You can control the order in which your program sees the returned values, however, by using the sort function.

The Perl sort function sorts on an input array. This means that the array input from keys is passed to sort. Sort modifies the array and returns an array alphabetically sorted, from a to z. You can invert the sort order, from z to a, by using the reverse command.

The Print Environment variables program uses the keys and sort function in line 14 of Listing 6.4. The keys function is passed the associative %ENV array. It returns a list of all the indexes or keys to the %ENV array. The sort function then sorts the list into alphabetical order.

Sending Environment Variables to Your E-Mail Address

So far, you've seen how to send the environment variable back to you through your Web browser, but what if you want to save those variables on you local computer? You could, of course, just use the File Save As function on your browser, but that doesn't format the data in a very usable manner. The other option is to save the data to a local file on your server. That may present a couple of problems for you, however. First, you might not have the privileges you need to write a file to your server. I hope this isn't the case, and I suggest changing servers when you can if you encounter this situation. Not all servers' Administrators are as helpful as mine, though.

Second, and more likely, you don't want to have to deal with reading the file on a Unix system. Heck—you probably would have to telnet in and then use some arcane editor like emacs or vi.

Instead of this headache, you can use the program in Listing 6.5 to mail your environment variable back to your user account. This example has lots of useful potential for you. First, it shows you how to use the mail program. I go into detail on mailers in Chapter 11, "Getting Feedback and Sending Information," but this is a nice introduction. Second, this program shows you your environment variables URI encoded and decoded. This makes a great reference for the future. Third, you obviously can adapt this program to other purposes.

As you go though this program, you will learn about Perl subroutines and how they receive and return variables, about call by reference and call by value parameter passing, and the Perl special variables $_, @_ and |.

#!/usr/local/bin/perl
#perltest.p
#for testing cgi-bin interface
# Put this in your cgi-bin directory, changing the e-mail address below...
#sub to remove cgi-encoding
sub unescape {
    local ($_)=@_;
    tr/+/ /;
    s/%(..)/pack("c",hex($1))/ge;
    $_;
}
# ---------------------------------------------------------------------------
# The escape and unescape functions are taken from the wwwurl.pl package
# developed by Roy Fielding <fielding@ics.uci.edu> as part of the Arcadia
# project at the University of California, Irvine. It is distributed
# under the Artistic License (included with your Perl distribution
# files).
# ---------------------------------------------------------------------------
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#.PURPOSE       Encodes a string so it doesn't cause problems in URL.
#
#.REMARKS
#
#.RETURNS       The encoded string
#------------------------------------------------------------------------------
sub cgi_encode
{
    local ($str) = @_;
    $str = &escape($str,'[\x00-\x20"#%/+;<>?\x7F-\xFF]');
    $str =~ s/ /+/g;
    return( $str );
}
# ===========================================================================
# escape(): Return the passed string after replacing all characters matching
#           the passed pattern with their %XX hex escape chars.  Note that
#           the caller must be sure not to escape reserved URL characters
#           (e.g. / in path names, ':' between address and port, etc.) and thus
#           this routine can only be applied to each URL part separately. E.g.
#
#           $escname = &escape($name,'[\x00-\x20"#%/;<>?\x7F-\xFF]');
#
sub escape
{
    local($str, $pat) = @_;
    $str =~ s/($pat)/sprintf("%%%02lx",unpack('C',$1))/ge;
    return($str);
}
#now the main program begins
#testing environment variables passed via URL...
print "Content-type: text/plain","\n";
print "\n";
open (MAIL,"| mail name@foo.edu") ||
  die "Error: Can't start mail program - Please report this error to name@foo.edu";
print MAIL "Matt's New cgi-test script report","\n";
print MAIL "\n";
print MAIL "\n";
print MAIL "Environment variables" ,"\n";
print MAIL "\n";
        foreach(sort keys %ENV)  #list all environment variables
           {
              $MyEnvName=$_;
              $MyEnvValue=$ENV{$MyEnvName};
              $URLed = &cgi_encode($MyEnvValue);
              $UnURLed = &unescape($MyEnvValue);
              print MAIL $MyEnvName,"\n";
              print MAIL "Value: ",$MyEnvValue,"\n";
              print MAIL "URLed: ",$URLed,"\n";
              print MAIL "UnURLed: ",$UnURLed,"\n";
              print MAIL "\n";
           }
 if ($ENV{'REQUEST_METHOD'} eq "POST")
   {#POST data
      print MAIL "POST data \n";
    for ($i = 0; $i < $ENV{'CONTENT_LENGTH'}; $i++)
        {
          $MyBuffer .= getc;
        }
print MAIL "Original data: \n";
print MAIL $MyBuffer,"\n";
print MAIL "unURLed: \n";
print MAIL &unescape($MyBuffer), "\n\n";
      @MyBuffer = split(/&/,$MyBuffer);
      foreach $i (0 .. $#MyBuffer)
        {
           print MAIL $MyBuffer[$i],"\n";
           print MAIL "FName:",&unescape($MyBuffer[$i]),"\n";
        }
   }
close ( MAIL );
print "\n";
print "Thanks for filling out this form !\n";
print "It has been sent to name@foo.edu\n<p>\n";

Perl Subroutines

This program is nicely segmented into several smaller subroutines. Subroutines break your logic up into smaller reusable pieces. You've seen this with the ReadParse function. It is a good habit to get into, and I highly recommend it.

This program has all its subroutines defined first, followed by the main program statements. The convention of declaring subroutines first comes from using compilers that require you to declare and/or define subroutines before you use them. You do not have to do this in Perl.

I prefer to define all my subroutines last. That way, the main program logic is always at the top of the file and easy to find. Anyway, if you use Perl, a subroutine can be defined anywhere in your CGI program. Perl treats the subroutine definition as a non-executable statement and just doesn't care where it finds it in your program.

When your program is compiled into memory, Perl builds a cross-reference table so it can find all the subroutines you have defined. You therefore can call your subroutines regardless of where you define them.

All the parameters passed to your subroutine are in the special Perl variable @_. This array actually references the locations of the passed-in variables. So, if you change something in the @_ array, you will be changing the contents of the passed-in parameters. This type of parameter passing is termed calling by reference because any use of the variables in your subroutine actually reference and modify the passed parameters.

Usually, it is considered a smart idea to use a form of parameter passing: calling by value.

With this form of parameter passing, all the modifications to your subroutine's parameters are local to the subroutine. This means that the parameters have a scope local to the subroutine.

A convention has developed with Perl that simulates pass by value. If you use the local function, you create variables whose scope is local to the subroutine. You often will see the first line of a subroutine as the local call. Then the subroutine operates on the variables defined in the local command. Each of the subroutines in this mail program contains a local command.

Finally, Perl subroutines act differently than most other languages in one important way. The result of the last line evaluated in the subroutine is returned automatically to the calling routine.

The unescape Subroutine

As you can see, the last line of subroutine unescape, repeated in Listing 6.6, takes advantage of this by having Perl evaluate the $_ variable. The side effect of this is that the local copy of $_ is returned to the calling subroutine. If you want to explicitly state the return value, you can do so by using a return statement.

01: #sub to remove cgi-encoding
02: sub unescape {
03:     local ($_)=@_;
04:     tr/+/ /;
05:     s/%(..)/pack("c",hex($1))/ge;
06:     $_;
07: }

Okay, let's take a closer look at the subroutines in this program. The subroutine unescape converts the URL-encoding input parameter much like ReadParse. The tr function is a built-in function and works much like the built-in s function. The tr stands for translate and s stands for substitute.

The tr function translates all occurrences of the characters found in the search pattern to those found in the replacement list. So, in this case, it replaces every plus sign (+) with a space.

Substitute performs exactly the same function but in its own way. I've been over substitute, and I don't think it deserves a rehash here.

Perl has lots of different functions in it. Some of your choices are based on familiarity. In this case, using tr in unescape or s in ReadParse has no significant difference.

In line 5, of Listing 6.6,

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

is the same as ReadParse. The difference you might notice about this function is the use of the $_ character. A lot of people find using the $_ variable confusing, at least initially. In case you were confused about what these functions are modifying, it is the $_ variable. This variable is the underlying variable or default for lots of Perl functions.

This code makes its own local copy from the input array @_ in line 3 of the globally scoped $_ variable and then returns the local copy on the last line.

One final note about subroutines. If there are not any parameters passed to the subroutine, the @_ array takes on the last value of the $_ variable.

The cgi_encode Subroutine

Now let's take a brief look at the cgi_encode subroutine, repeated here for convenience in Listing 6.7. It passes that strange-looking parameter with all the Xs and pound signs (#) in it. What is it doing? Well, it's telling the escape routine to look for all the HEX numbers between 00 and 20 and 7F and FF. These numbers are outside the boundaries of normal printable ASCII characters. It also says look for special characters like percent signs (%), single quotation marks ('), question marks (?), and so on.

sub cgi_encode
{
    local ($str) = @_;
    $str = &escape($str,'[\x00-\x20"#%/+;<>?\x7F-\xFF]');
    $str =~ s/ /+/g;
    return( $str );
}

The escape routine does the opposite of the decode routine. It just converts all these special characters to their HEX equivalent numbers. It does this using the substitute command and the unpack function. Unpack just works like a reverse pack function. (The pack function was covered in Chapter 5, "Decoding the Data Sent to Your CGI Program.")

The main mail Program

Now that you understand all the subroutines, the main program is a snap. I have repeated the main program in Listing 6.8 so that you don't have to switch back and forth between pages. This means that most of the program was duplicated, but I personally like seeing the entire program in a book. That way, when I look at the program I can see how everything fits together.

01: #now the main program begins
02: #testing environment variables passed via URL...
03: print "Content-type: text/plain","\n";
04: print "\n";
05: open (MAIL,"| mail name@foo.edu") ||
06:   die "Error: Can't start mail program - Please report this error to name@foo.edu";
07: print MAIL "Matt's New cgi-test script report","\n";
08: print MAIL "\n";
09: print MAIL "\n";
10: print MAIL "Environment variables" ,"\n";
11: print MAIL "\n";
12:         foreach(sort keys %ENV)  #list all environment variables
13:            {
14:               $MyEnvName=$_;
15:               $MyEnvValue=$ENV{$MyEnvName};
16:               $URLed = &cgi_encode($MyEnvValue);
17:               $UnURLed = &unescape($MyEnvValue);
18:               print MAIL $MyEnvName,"\n";
19:               print MAIL "Value: ",$MyEnvValue,"\n";
20:               print MAIL "URLed: ",$URLed,"\n";
21:               print MAIL "UnURLed: ",$UnURLed,"\n";
22:               print MAIL "\n";
23:            }
24:  if ($ENV{'REQUEST_METHOD'} eq "POST")
25:    {#POST data
26:       print MAIL "POST data \n";
27:     for ($i = 0; $i < $ENV{'CONTENT_LENGTH'}; $i++)
28:         {
29:           $MyBuffer .= getc;
30:         }
31: print MAIL "Original data: \n";
32: print MAIL $MyBuffer,"\n";
33: print MAIL "unURLed: \n";
34: print MAIL &unescape($MyBuffer), "\n\n";
35:       @MyBuffer = split(/&/,$MyBuffer);
36:       foreach $i (0 .. $#MyBuffer)
37:         {
38:            print MAIL $MyBuffer[$i],"\n";
39:            print MAIL "FName:",&unescape($MyBuffer[$i]),"\n";
40:         }
41:    }
42: close ( MAIL );
43: print "\n";
44: print "Thanks for filling out this form !\n";
45: print "It has been sent to name@foo.edu\n<p>\n";

Don't forget that the first line of code executed by Perl for the entire program begins after the comment about testing environment variables. Printing of the content type with two new lines is the first code output by the program.

The rest seems kind of anti-climatic. A file handle is opened. The file handle is named Mail. From this point, every print command sends data to the Unix Mail program.

Each of the environment variables is encoded and decoded and then mailed to your user name. You get to see the environment variable in each of its three formats:

Next, from lines 24 through 30 of Listing 6.8, you can see how to check for and how to read Post data.

This is a simple for loop. It reads one character at a time using the getc function reading from the STDIN file handle. Remember that Post data always is available at STDIN. You saw this handled differently in the ReadParse function. ReadParse read the entire input sting in one gulp in line 10:

read(STDIN,$in,$ENV{'CONTENT_LENGTH'});

But using a for loop and reading a character at a time works also, and looks a lot more like traditional coding languages. The Post data then is encoded and decoded just like the environment data.

This stuff actually becomes pretty easy to understand if you just step through it one line at a time.

There is one bit of Perl magic here that I want to bring out. It's the vertical bar (|) used in the open statement. The vertical bar (|) used in an open command before the file name tells Perl that you want to send all your output data to a system command and not a file.

This makes your job of sending mail messages easy and very safe. By opening the mail program with the parameter name@foo, you told the mail program where you wanted to send the data. Anything that is sent to the mail program after the initial open statement is sent in the body of the mail message. Because everything is sent in the body of the mail message, any offensive hacker commands can never reach the command line. There is no concern about hacker commands getting to the Unix shell and reeking havoc.

Don't forget to close your file handle Mail. This will flush the output buffer and initiate the sending of the mail.

Remember to change the line that opens up the mail account to point to your mailbox name; @ foo.edu should be replaced with your e-mail address.

When I used this program, accessing it through a registration form, it returned the data shown in Listing 6.9.


Listing 6.9. CGI environment variables returned by the Mail Environment variables program.

Matt's New cgi-test script report
Environment variables
DOCUMENT_ROOT
Value: /usr/local/business/http/accn.com
URLed: %2fusr%2flocal%2fbusiness%2fhttp%2faccn.com
UnURLed: /usr/local/business/http/accn.com
GATEWAY_INTERFACE
Value: CGI/1.1
URLed: CGI%2f1.1
UnURLed: CGI/1.1
HTTP_ACCEPT
Value: */*, image/gif, image/x-xbitmap, image/jpeg
URLed: *%2f*,%20image%2fgif,%20image%2fx-xbitmap,%20image%2fjpeg
UnURLed: */*, image/gif, image/x-xbitmap, image/jpeg
HTTP_COOKIE
Value: s=dialup-7207812894493652
URLed: s=dialup-7207812894493652
UnURLed: s=dialup-7207812894493652
HTTP_REFERER
Value: http://www.accn.com/cgibook/chap6/call-mail.html
URLed: http:%2f%2fwww.accn.com%2fcgibook%2fchap6%2fcall-mail.html
UnURLed: http://www.accn.com/cgibook/chap6/call-mail.html
HTTP_USER_AGENT
Value: Mozilla/1.1N (Windows; I; 16bit)
URLed: Mozilla%2f1.1N%20(Windows%3b%20I%3b%2016bit)
UnURLed: Mozilla/1.1N (Windows; I; 16bit)
PATH
Value: /usr/local/bin:/usr/bin/:/bin:/usr/local/sbin:/usr/sbin:/sbin
URLed: %2fusr%2flocal%2fbin:%2fusr%2fbin%2f:%2fbin:%2fusr%2flocal%2fsbin:%2fusr%2fsbin:%2fsbin
UnURLed: /usr/local/bin:/usr/bin/:/bin:/usr/local/sbin:/usr/sbin:/sbin
QUERY_STRING
Value: first=Eric+&last=Herrmann&street=255+S.+Canyonwood+Dr.&city=Dripping+Springs&state=Texas
&zip=78620&phone=%28999%29+999-9999&simple=+Submit+Registration+
URLed: first=Eric%2b&last=Herrmann&street=255%2bS.%2bCanyonwood%2bDr.&city=Dripping%2bSprings
&state=Texas&zip=78620&phone=%2528999%2529%2b999-9999&simple=%2bSubmit%2bRegistration%2b
UnURLed: first=Eric &last=Herrmann&street=255 S. Canyonwood Dr.&city=Dripping Springs&state=Texas&
zip=78620&phone=(999) 999-9999&simple= Submit Registration
REMOTE_ADDR
Value: 199.170.89.45
URLed: 199.170.89.45
UnURLed: 199.170.89.45
REMOTE_HOST
Value: dialup-7.austin.io.com
URLed: dialup-7.austin.io.com
UnURLed: dialup-7.austin.io.com
REQUEST_METHOD
Value: GET
URLed: GET
UnURLed: GET
SCRIPT_FILENAME
Value: /usr/local/business/http/accn.com/cgibook/chap6/perltest.cgi
URLed: %2fusr%2flocal%2fbusiness%2fhttp%2faccn.com%2fcgibook%2fchap6%2fperltest.cgi
UnURLed: /usr/local/business/http/accn.com/cgibook/chap6/perltest.cgi
SCRIPT_NAME
Value: /cgibook/chap6/perltest.cgi
URLed: %2fcgibook%2fchap6%2fperltest.cgi
UnURLed: /cgibook/chap6/perltest.cgi
SERVER_ADMIN
Value: webmaster@accn.com
URLed: webmaster@accn.com
UnURLed: webmaster@accn.com
SERVER_NAME
Value: www.accn.com
URLed: www.accn.com
UnURLed: www.accn.com
SERVER_PORT
Value: 80
URLed: 80
UnURLed: 80
SERVER_PROTOCOL
Value: HTTP/1.0
URLed: HTTP%2f1.0
UnURLed: HTTP/1.0
SERVER_SOFTWARE
Value: Apache/0.8.13
URLed: Apache%2f0.8.13
UnURLed: Apache/0.8.13

Using the Two Types of Environment Variables

Not all environment variables are created equal. How come you don't always know what's in the environment variables associative array? The environment variable is the server's way of communicating with you CGI program, and each communication is unique.

The uniqueness of each communication with your CGI program is based on the request headers that are sent by the Web page client when it calls your CGI program. If your Web page client is responding to an Authorization response header from the server, it will send authorization request headers. Because the request headers define a number of your environment variables, you can never be sure what environment variables are available

Environment Variables Based on the Server

Some of the environment variables always are set for you and are not dependent on the CGI request. These environment variables typically define the server on which your CGI program runs. The environment variables discussed in the following subsections are based on your server type and always should be available to your CGI program.

GATEWAY_INTERFACE

The environment variable GATEWAY_INTERFACE is the version of the CGI specification that your server is using. The CGI specification is defined at

http://hoohoo.ncsa.uiuc.edu/cgi/

This is an excellent site for further information about CGI. At the time of this writing, CGI is at revision 1.1. You can see this in Figure 6.3. The format of the variable is CGI/revision number.

SERVER_ADMIN

The environment variable SERVER_ADMIN should be the e-mail address of the Web guru on your server. When you can't figure out the answer yourself, this is the person to e-mail. Be careful, though. These people usually are very busy. You want to establish a good relationship early so that your Web guru will respond to your requests in the future. Make sure that you have tried all the simple things—everything you know first—before you ask this person questions. This is definitely an area in which "crying wolf" can have a negative effect on your ability to get your CGI programs working. When you have a real tough problem that no one seems able to figure out, you want your Server Administrator to respond to your questions. So don't overload her with simple problems that you should be able to figure out on your own.

SERVER_NAME

The environment variable SERVER_NAME contains the domain name of your server. If a domain name is not available, it will be the IP number of your server. This should be in the same URL format as that in which your CGI program was called.

SERVER_SOFTWARE

The environment variable SERVER_SOFTWARE contains the type of server under which your CGI program is running. You can use this variable to figure out what type of security methods are available to you and whether server side includes are even possible. This way, you don't have to ask your Web Master these simple questions.

Environment Variables Based on the Request Headers

This next set of environment variables give your CGI program information about what is happening during this call to your program. These environment variables are defined when the server receives the request headers from a Web page. Some of these variables should look very familiar because they are directly related to the HTTP headers discussed in Chapter 2, "Understanding How the Server Communicates with the Browser."

AUTH_TYPE

The AUTH_TYPE environment variable defines the authentication method used to access your CGI program. The AUTH_TYPE usually is Basic, because this is the primary method for authentication of the Net right now. AUTH_TYPE defines the protocol-specific authentication method used to validate the user. I discuss how to set up a user-password authentication scheme in Chapter, "Implementing Security." In the next chapter, you will use request headers and environment variables to perform user authentication.

Content-Length

The Content-Length environment variable specifies the amount of data attached after the end of the request headers. This data is available at STDIN and is identified with the Post or Put method.

Content-Type

The Content-Type environment variable defines the type of data attached with the request method. If no data is sent, this field is left blank. The content type will be

application/x-www-form-urlencoded

when posting data from a form.

HTTP_REQUEST_METHOD

The HTTP REQUEST_METHOD environment variable is the HTTP method request header converted to an environment variable. If you'll remember, the following request methods are possible: Get, Post, Head, Put, Delete, Link, and Unlink. Get and Post certainly are the most common for your CGI program and define where incoming data is available to your CGI program. If the method is Get, the data is available at the query string. If it is Post, the data is available at STDIN, and the length of the data is defined by the environment variable CONTENT_LENGTH. The Head request method normally is used by robots searching the Web for page links. The other methods are not quite as common and tell the server to modify a URL/file on the server.

PATH

The PATH environment variable is not strictly considered a CGI environment variable. This is because it actually includes information about your Unix system path. We discussed this in detail earlier, so I refer you to out previous discussion.

PATH_INFO

The PATH_INFO environment variable is set only when there is data after the CGI program (URI) and before the beginning of the QUERY_STRING variable. Remember that the query string begins after the question mark (?) on the link URI or Action field URI. PATH_INFO can be used to pass any type of data to your CGI program but it usually is used to send information about finding files or programs on the server. The server strips everything after it finds the target CGI program (URI) and before it finds the first question mark (?). This information is URI decoded and then placed in the PATH_INFO variable.

PATH_TRANSLATED

The PATH_TRANSLATED environment variable is a combination of the PATH_INFO variable and the DOCUMENT_ROOT variable. It is an absolute path from the root directory of the server to the directory defined by the extra path information added from PATH_INFO. This is called an absolute path. This type of path often is used when your CGI program moves in and out of different directories or different shell environments. As long as your server doesn't change, you can use the absolute path regardless of where you put or move your CGI program. Sometimes absolute paths are considered bad because you cannot move your CGI program to another server. You have to decide which is more likely: 1) Your CGI program will change directories, 2) You will change servers, or 3) The absolute path will change on your existing server. This can happen when your server adds or removes disks.

QUERY_STRING

The QUERY_STRING environment variable contains everything included on the URI after the question mark. The setup for a query string normally is performed by your browser when it builds the request headers. You can create the data for your own query string if you want to by including a question mark in your hypertext reference and then URI encoding any data that is included after the question mark. This is just one more way to send data to your program. Two big drawbacks to using QUERY_STRING are the YUK! factor and the size of the input buffer. The YUK! factor means that your data will be displayed back to your client in the Location field. The size problem means that you have a limitation on how much data you can send to your program using this method. The amount of data you can send without exceeding the input buffer is server specific, so I can't give you any hard rules. But you should try to limit all data you send using this method to less than 1,024 bytes.

REMOTE_ADDR

The REMOTE_ADDR environment variable has the numeric Internet protocol (IP) address of the browser or remote computer calling your CGI program. Read the REMOTE_ADDR from right to left. The furthest right number defines today's connection to the remote server. Or, at least, this will be the case when your Web browser client connects from a modem to a commercial server.

REMOTE_HOST

The REMOTE_HOST environment variable contains the domain name of the client accessing your CGI program. You can use this information to help figure out how your script was called. If the domain name is unavailable to your server, this field is left empty. If this field is empty, the REMOTE_ADDR environment variable is filled in. Your program can read this environment variable from right to left. There can be more that one subhierarchy after the first period (.), so be sure to write your code to deal with more than one level of domain hierarchy to the left of the period.

REMOTE_IDENT

The REMOTE_IDENT environment variable is set only if the remote user name is retrieved from the server using the IDENTD method. This only occurs if your Web server is running the IDENTD identification daemon. This is a protocol to identify the user connecting to your CGI program. Just having your system running IDENTD is not sufficient, however; the remote server making the HTTP request also must be running IDENTD.

REMOTE_USER

The REMOTE_USER environment variable identifies the caller of your CGI program. This value is available only if server authentication is turned on. This is the user name authenticated by the username/password response to a response status of Unauthorized Access (401) or Authorization Refused (411).

SCRIPT_FILENAME

The SCRIPT_FILENAME environment variable gives the full path to the CGI program. You do not want to use this variable when building a self-referencing URI. Remember that the server is making some assumptions on how you will access your CGI program. The full path name would be appended to the server's full path name, thereby totally confusing your poor server. The server starts with the server name, and from there it determines the document root; then it adds the path to your CGI program.

SCRIPT_NAME

The SCRIPT_NAME environment variable gives you the path and name of the CGI program that was called. The path is a relative path starting at the document root path. You can use this variable to build self-referencing URLs. Suppose that you want to return a Web page and you want to generate an HTML that includes a link to the called CGI program. The print string would look like the following:

print "<a href=http://$SERVER_NAME$SCRIPT_NAME> This is a link to the CGI program you just called </a>";
SERVER_PORT

The SERVER_PORT environment variable defines the TCP port to which the request headers were sent. As discussed in Chapter 2, the port is like the telephone number used to call the server. The default port for server communications is 80. When you see a number appended after the domain name server, this is the port number to which the request was sent—for example, www.io.com:80. Because the default port is 80, it generally is not necessary to include the port number when making URI links.

SERVER_PROTOCOL

The SERVER_PROTOCOL environment variable defines the protocol and version number being used by this server. For the time being, this should be HTTP/1.0. The HTTP protocol is the only server protocol used for the WWW at the moment. But, like most good designs, this environment variable is designed to allow CGI programs to operate on servers that support other communications protocols.

Finding Out Who Is Calling at Your Web Page

"How can I tell who is using my Web site?" This question is asked over and over again. It gets asked by professionals and amateurs. It's natural to want to know who is using your Web site. In the next several pages, you will take a look at this question and see how close you can come to answering it. You'll start with the easier problems and work up to the harder problem of who is visiting your Web site.

Before you get started on this topic, let me give you the standard Net advice. The Internet is most loved for its anarchy and anonymity. People can cruise the Net and feel like they are doing it anonymously. Don't abuse the capability to get people's names or links, or you will find your Web site quickly black listed and abandoned. News travels quickly on the Net, and bad news about your Web site travels even faster.

Let's start with an easy one first. Suppose that your only goal is to figure out how your Web site is getting called. Where are all these hits coming from? Well, the environment variable with that answer is HTTP_REFERER.

Notice that this environment variable is prefixed with HTTP_. All the request headers sent by the browser are turned into environment variables by your server, and the request headers are prefixed with HTTP_ and the request header is capitalized. This is both good and bad. Because not all browsers are created equal, you cannot depend on getting the same request headers with every call. In other words, not all browsers will send the Referrer request header, so you might not have the HTTP_REFERER environment variable available. On the other hand, because all browsers tell the server what type of client they are, you can write your code to work with the browsers that send you the HTTP_REFERER environment variable. There are two ways to handle this, and I'll show you both methods.

First, you could check for the browser type. You did this back in Chapter 2. The browser type is in the environment variable HTTP_USER_AGENT. A code fragment for getting out Netscape's Mozilla and version number is shown in Listing 6.10. This actually is probably the harder method. But if you want to do specific things based on the HTTP_USER_AGENT type, this is the way to go. You might want to build a table with all the different HTTP_USER_AGENTs you're interested in, and then you could use loop through the table to look for valid HTTP_USER_AGENTs.

@user_agent = split(/\//,HTTP_USER_AGENT);
if ($user_agent[0] eq "Mozilla"){
   @version = split(/ /, $user_agent[1]);
    $version_number = substr($version_number, 0, 3)};

If you just want to make sure the HTTP_REFERER environment variable is defined, use the Perl defined function. Because all you are trying to do is determine whether the HTTP_Referer environment variable is set, this seems like a more straightforward approach.

Use the Perl fragment

if (defined ($ENV{'HTTP_REFER'}

to determine whether HTTP_REFERER is set and then perform some specific operation. From here, you could open a file or send yourself mail.

Back to HTTP_REFERER, this environment variable contains the full URI reference to the calling Web page. Just save the value to a file, and you've got the link back to the calling Web page.

That's the easy one. Now take a look at what is and isn't possible with some other environment variables that contain more specific information about your Web site visitor. First, the two that are the most likely to have information in them: the REMOTE_HOST and the REMOTE_ADDR variables.

The REMOTE_HOST environment variable usually is filled in. It contains the domain name of your Web site visitor's server as you would normally type it in the Location field of your Web browser. You can use this field to begin getting some ideas on how your Web site is linked around the Net. Or you might have a list of trusted sites that you compare the REMOTE_HOST environment variable with to determine who you want to allow access to your Web page.

If you want more specific information about where in the country the calling Web site is located, use the InterNIC whois command. Telnet into your server and type the name of the REMOTE_HOST environment variable. Figure 6.4 shows an example of the whois command. As you can see, there is quite a bit of information provided here about what type of server is calling you. You might find this handy to use if you are having problems with a robot from this site and the 'bot does not contain an HTTP_FROM environment variable. With this information, you can contact the registered administrative contact and resolve your problems with the errant robot.


Figure 6.4. Using the whois command to identify REMOTE_HOST.

Even if the REMOTE_HOST environment variable is not filled in, the REMOTE_ADDR always will be set. This variable contains the IP address of the calling Web page's server. You can use the whois command with this environment variable also. You are likely to get a different set of information back, however. The whois command used on the IP address returns the main server. You might find that your REMOTE_HOST name is only a subpart of an existing server. You normally will want to ignore the far right field in the IP address. InterNIC does not give registration information beyond the first three dotted decimal IP address numbers. You can see the results of the whois command in Figure 6.5. I have performed all these tasks manually but you easily could add to the script fragment in Listing 6.11 to handle this type of work for you.


Figure 6.5. Using the whois command to identify REMOTE_ADDR.

Before you save the HTTP_REMOTE_ADDR, you should clean up the IP address. The IP address should be limited to the first three IP numeric registration levels. So if the address in the HTTP_REMOTE_ADDR environment variable is 199.17.89.65.99, you only want 199.89.65. The Perl fragment in Listing 6.11 performs this work for you.

($part1, $part2, $part3, $the_rest) = split/\./$ENV{'HTTP_REMOTE_ADDR'}, 4);
$address = $part1 . '.' . $part2 . '.' . $part3;
print (output_file, "$address\n") ;

Getting the User Name of Your Web Site Visitor

So far, you have been able to tell where the links to your Web site are originating from, and to get information about the server where those links are connected.

Now let's look at the three environment variables that are supposed to contain the name of your Web site visitor: HTTP_IDENTD, HTTP_FROM, and REMOTE_USER.

First, let's deal with and ignore the environment variable HTTP_IDENTD. This is a lousy means of confirming who is visiting your Web site. It only works if both the client and the server are running the IDENTD process. Even if the server is doing everything correctly, HTTP_IDENTD still can fail when you try to use this method because you are dependent on the client's server also performing correctly. Even when everything works, the process requires extra communication between the server and the client, and that can really slow things down.

Finally, in the best of worlds, you are in charge of the server and you can turn on IDENT yourself. But more than likely, you are not the owner of the server and you would have to convince someone to turn on the IDENTD daemon. And still you must deal with the fact that your clients can come from any server in the world. There is no way you can force them to run IDENT.

This all just seems like way too much work to me. So I suggest that you avoid the HTTP_REMOTE_IDENT environment variable as a solution to validating users. In the next chapter, you will learn how to set up basic user authentication using a user name/password scheme. That methodology is much more reliable than the HTTP_REMOTE_IDENT environment variable.

So let's take a look at the last two environment variables: HTTP_FROM and REMOTE_USER.

HTTP_FROM is supposed to be set to the e-mail address of your Web site visitor. However, this has become an issue on the Net. People are afraid of unscrupulous Web sites getting their electronic name and address and selling it or using it for other commercial purposes. If junk e-mail isn't a problem for you yet, I'm betting it will be some time in the future.

So, to prevent themselves from getting a bad reputation, most browsers no longer support this feature. Or if they do, they allow users to turn off this identification method. So, unfortunately for us, this environment variable is best used only as a default value for a return e-mail address.

Well, we are down to the last environment variable that can help us. The REMOTE_USER environment variable. Will this one tell you who is accessing your Web site? Yes—BUT, you won't like the way it is set. This environment variable is set only if an authentication scheme is being used between the browser and the server.

This isn't quite as hard as you might expect it to be. In order to set up user authorization, you need to set protections on you files or directories and create a password file for validated users. In Chapter 7, you will build an entire application that includes registering users, building a password file, and validating a user. So don't despair; I will cover how to do this in detail in the next chapter.

Unfortunately, I haven't given you any easy answers for how to get the name of someone visiting your site. It certainly is possible, and you can gather some information with existing environment variables. But in the long run, unless you want to validate every user, you are going to have to make do with less than you probably wanted to. At least now you have the full picture.

Using the Cookie

I have saved the dessert for last. The cookie, as it is fondly called, is one of the most powerful environment variables of the HTTP environment variables. I have saved this variable for last for three reasons. First, it's only implemented for Netscape browsers. Second, it can really enhance your ability to treat a Web site visit as if a customer just entered your place of business. Third, it requires some detailed explanation.

One of the problems with building applications on the Internet is writing programs that remember what they were doing with customer X. When you cruise the Internet, each new link is a brand new connection to the server. It doesn't have any way of knowing what happened during the last connection. This means that each time your CGI program is invoked, you don't know what happened the last time.

Why do your care? Well, for example, I expect on-line catalogs to be a major new programming application on the Internet. But the first problem you run into is keeping track of what each customer is selecting for his purchases.

Imagine that you have three Web page customers at one time. Each of them is clicking on products, and your job is to keep track of who gets what. Just storing the data in a file isn't enough. If you have three customers, each making purchases, then you are going to need three separate files, one for each customer. How do you decide who is making the next purchase? Especially if they happen to be coming from the same server? Do you need to get the customer's name each time she makes a new selection? Yes!! In some way, you must be able to separate them. Well, the Netscape cookie was built to help you solve that problem.

The Netscape cookie shows up in your environment variables only if the browser accessing your Web page is a Netscape browser. The environment variable is HTTP-Cookie, and it is a marvelous tool for maintaining state.

Remember that your browser sends a request header to your server, and then the server turns that request header into an environment variable. This means that once your CGI program sends the cookie to the browser, the browser is responsible for keeping track of it and returning it as a request header. So, each time your client submits on one of your forms, you get a cookie that tells you which client it is.

Cookies are passed back and forth between the client and the sever to identify a particular Web client. How does this chain of cookies get started?

When your Web site client first visits your Web page, he connects to your sever and probably requests your home page. Unless your home page is a CGI program, no cookies are exchanged yet. When your Web client submits to your CGI program the first time, no cookie exists. Your CGI program responds to the submittal with some type of Set Cookie response header. You could generate a cookie based on the domain IP number and the current time. You then would send this cookie to the submitting browser as part of the normal response headers. This Set Cookie response header might look like the following:

Set Cookie: customer=$ENV{'HTTP_REMOTE_ADDR'} . $ENV{'DATE'};

This generates a unique cookie that the browser will send you the next time your Web client clicks on any Web page within your sever root. You now can identify this client every time he accesses any Web page on your sever root because the browser always will send this unique cookie, and your CGI program that previously saved the cookie can compare the cookie the browser sent with the saved cookie. The idea is that the requested URI will get only cookies that it knows how to interpret.

The Set Cookie response header is made up of several fields. The format of the Netscape cookie is not very complex. The server sends to the browser a Set Cookie response header. The only required field in the Set Cookie response header is the name of the cookie and the value to assign to that cookie. So a valid Set Cookie response header is

Set-Cookie: customer=Jessica-Herrmann;

The Set Cookie response header has several fields. Each filed can be used only once per Set Cookie response header. If you need to send more than one name=value pair back to the client browser, it is okay to send multiple Set Cookie response headers in a single response-header chain.

If all the fields of the Set Cookie response header were used, the cookie would look like this:

Set-Cookie: customer=Steve-Herrmann; expires=$ENV{'DATE'} + 2 HOURS ; domain=www.practical-inet.com; path=/cgibook ;

The semicolon (;) is used to separate the cookie fields.

The Name=Value Field

The Name=Value field is required and defines the uniqueness of a cookie to the browser. Don't be confused by this and the name/value pairs of forms. The name in this field should be set to a variable name that you will use in your CGI program—for example, customer or book. The value probably will be based on something your customer submits. You can send only one name=value pair per Set Cookie response header. You can send multiple Set Cookie response headers, however.

The Name field is the only required field of the Set Cookie request header.

The Expires=Date Field

The Expires=Date field is a command to the browser. It tells the browser to remember this cookie only until the expiration date given in the Expires field. When the expiration time is reached, the cookie is forgotten and is not sent to the server on any further connections.

This field is not required; if it is not set, the browser remembers the cookie throughout one Internet connect. So you can browse for hours, change Web pages, and return; as long as you don't close Netscape, it remembers your cookie.

The Domain=Domain_Name Field

The Domain=Domain_Name field should be set to the domain name of the server from where URI is fetched. So, if your form is submitted to

www.practical-inet.com/chap6/test-cookie.cgi

the Domain field should be

Domain=www.practical-inet.com

The Domain field is not required and defaults to the server that generated the Set Cookie response header.

The Path=Path Field

The Path=Path field is used to limit the URIs with which the cookie can be used. So, if I wanted a cookie to match only if you stayed in my chap6 directory, I would send a Set Cookie request header with a path of /cgibook/chap6.

The path is not required, and if it is not included, it is set to the path to the URI sending the Set Cookie request header.

Returning the Cookie

When the browser is deciding which cookies to send with the request headers, it looks at the domain name it is accessing and matches all those cookies. Then, it looks at the URI and the path and matches any cookies that have a path matching the path of the URI.

This works because the match is from most general to specific. If the path is / or the server root, everything from the server root and below matches. If the path is /cgibook/chap6/, everything in the Chapter 6 directory and below is a path and URI match and the browser is sent that cookie.

Think of a cookie as a ticket. A ticket is given each time your browser accesses a URI that sends a Set Cookie response header. The ticket has information on it about who should get a copy of the ticket. The browser's job is to look at each ticket it has in memory each time it accesses a URI. If the information on the ticket says this URI should get a copy of the ticket, the browser sends a copy along with its regular request headers.

Your code can look at the ticket and from the Name=Value field determine to which customer the ticket belongs. Then you can go to the files that contain customer session information. Compare the cookie with the cookies in each file until you find a match. Or use the cookie to create a unique file name and get the correct file without performing a search.

Summary

In this chapter, you learned that there are three types of environment variables; the ones you get at the command line, within your CGI program, and for SSI commands are each different. This happens because the scope of environment variables is at the process level, and the process environment is different for each.

You learned that scope defines the area within which a variable can be used and that you can limit the scope of a variable to the enclosing code block (curly braces) by using the Perl local function.

You learned that there are two types of CGI environment variables: the server environment variables and the environment variables based on HTTP request headers. The server environment variables always are available for your CGI program but the set of HTTP request header environment variables differs with every client connection.

You learned that you can use the HTTP request header environment variables to get a lot of information about each visitor to your Web site, but getting the name of that visitor often is difficult. Finally, you learned that the Netscape cookie is an excellent means of maintaining information about each client that connects to your Web site.

Q&A

Q: In this chapter, you told us the Path environment variable issued for searching for programs. In the last chapter, you said this was done with the @INC array. What gives?

A: Would you believe me if I told you that I told you the truth both times? Well, I did. The difference is who or what is doing the looking. The @INC array is another of Perl's special variables, so it must be used by Perl. And, of course, it is. It is used only when you use the require function. The require function tells Perl to add whatever Perl code is in the require parameter list to the list of code it will execute. The require command only uses the list of directories in the @INC array as a search path. But when you try to execute a system or another CGI program from within your CGI program, the Path variable is used by the Unix operating system to search for the system command you requested.

Q: If I modified my environment variables, would they be there when I tried to use them the next time?

A: No. Environment variables have process scope. This means that they are available to every executing program within that process. As soon as your CGI program stops executing, however, the process that enclosed it ends. So any environment variables that you set end with that process. When your CGI program is started again, even if from exactly the same connection, an entire new process is started with an entire new set of environment variables.

Previous Page TOC Index Next Page See File