EIW Fall 2000 Lecture Notes - eiwcgi.pl


eiw-cgi.pl CGI library

We already looked at the GetQuery subroutine - we now look at a few other subroutines that are useful for CGI programs.

http_header

Any CGI program that sends an HTML document back to the browser needs to include an HTTP header indicating that the document is HTML. The CGI should also send a blank line that marks the end of the HTTP header lines. The following subroutine takes care of this and makes sure that the header is sent only once.

# --------------------------------------------
# http header generation
# this subroutine should be called before the perl CGI program
# prints anything!
# The extra logic in this subroutine just makes sure that the 
# header is never sent twice.
#
# example usage:
#  http_header();

sub http_header {
    if (! $http_header ) {
	print "Content-type: text/html\n\n";
	$http_header=1;
    }
}

Handling Errors

CGI programs always need to make sure that the query includes all the expected name/value pairs! Remember that just because you expect that your CGI will only be accessed from forms (or links) you create, you can't assume anything! Anyone can build a query by hand (or create thier own form) and send all kinds of crazy stuff.

When an error occurs in a CGI program, the program will typically send back an error message (formatted as an HTML document) and quit. The following subroutine handles both tasks - first by sending back an HTML document containing an error message and then by calling the perl exit function. This subroutine also attempts to create a back button so the user can easily return to the previous web page. The back button depends on the server creating an environment variable named "HTTP_REFERER" that contains the URL of the refering page - this information is not always available so the back button is only created if the environment variable exists.


# --------------------------------------------
# fatal_error generates an HTML error message and quits.
# This subroutine should only be called when a fatal
# error condition occurs, something like the query didn't
# include expected fields. 
# Any parameters to this subroutine are treated as strings that
# should be sent back as part of the error message.
#
# a back button is created that the user can press to go back to
# the refering page (typically the form that was sent here) if the
# environment variable REFERER is found (otherwise no back button
# is created).
# 
# Example usage:
#   fatal_error("You must fill in all fields in the form!\n");

sub fatal_error {

    # send the HTTP header 
    http_header();

    # and make this a real HTML document
    print "<HEAD><TITLE>Error!</TITLE></HEAD>\n";
    print "<BODY><HTML>\n";

    # send a generic error message back to the browser
    print "<H2>ERROR - YOUR QUERY COULD NOT BE PROCESSED</H2>\n";

    local($line);

    # now send back any parameters passed to this subroutine
    print @_;

    # now create the back button
    local($referer) = $ENV{'HTTP_REFERER'};
    if ($referer) {
	print "<P>\n";
	print "Press <A HREF=$referrer>here</A> to return\n";
    }
    # and close out the HTML document
    print "</HTML></BODY>\n";

    # terminate this program
    exit;
}

It is important to check for all error conditions before sending any document content back! You typically don't want to send back half of an HTML document followed by an error document!

Sending a static file

Another common operation is to send back the contents of a file containing part of an HTML document. This saves the programmer from creating all parts of an HTML document using print statements. For example, you could create a file that contains HTML that is always sent at the top of every HTML document. The following subroutine reads the contents of a named file and sends the file to the browser using print commands:

# --------------------------------------------
#
# send_file will read in a file and send the contents of the
# file to the browser. This is useful when part of the HTML
# you want to generate is always the same - just put it in
# a file instead of coding it in print statements
#
# example usage:
#   send_file("header.html");


sub send_file {
    local($filename) = $_[0];

    # attempt to open the file
    if (! open(F,$filename) ) {
	# Can't open the file - this is a fatal error!
	fatal_error("Can't find the file $filename\n");
    }

    # the file is open - read everything and send to
    # the browser
    local(@lines) = <F>;    # reads the whole file
    print @lines;           # sends all the lines to the browser
    close(F);               # close the file
}

Since it is possible that this subroutine can generate an error (if called with a parameter that names a file that does not exist) it is possible that the subroutine fatal_error can be called from within send_file.

send_file looks for files in the "current directory", which means the directory that holds the CGI program itself (assuming you use the default configuration for the Xitami server).

Using eiw-cgi.pl

In perl you can store a collection of subroutines in a file and include all the subroutines in your program using the require function. For example, your CGI program might have the following in it:


#!/perl/bin/perl
#
# the following line is needed if we want to use any of the
# subroutines defined in the file "eiw-cgi.pl" which is a 
# CGI library.

require "eiw-cgi.pl";


# This CGI program creates a table from the name/value pairs found in 
# the query.

# get the name/value pairs in the assoc. array named %fields

%fields = GetQuery();

# Here is how to get the value of a field named "age":

$age = $fields{"age"};


The require statement looks for files in the current directory (as well as some other places), so you probably need to put a copy of eiw-cgi.pl in your CGI directory. The require command evaluates each line of the named file (typically a sequence of subroutine definitions - but it could be anything) and looks for a value of TRUE after evaluating the last line in the file. If the last line of the file does not have the perl value TRUE the require command reports a fatal error and perl will quit! The simplest way to handle this is to always include the following line as the last line in a file holding a bunch of perl subroutines:

# this last line is needed ! (the return value of this file is used
# by the "require" statement, and the return value is the last 
# statement in the file).
1;