separator

Take a quiz or make one of your own
Article 5 - CGI Form Handling with Perl
Setting up a test environment on your website
If we jump right into this we can do things to make our website look worse rather than better. Because ultimately the goal here is to create our own customized error messages. But until that's all been setup and properly working we can really foul up a site by setting this up improperly. If the program isn't working right and we override the standard server response then someone mistyping a URL on your site might just see something like THIS, which likely won't impress them much. Those last two lines wouldn't normally happen, they're caused by having a bad install. Here's what you'd normally get without even trying to install this. See the difference?
For this application then we should definitely create a testing environment first, get everything looking nice and neat and tested out on that isolated environment. And then install the real deal on the whole site.

Follow these steps:
  1. point your ftp client to your website
  2. create a new directory under /cgi-bin/thecgibin/ called /testart05/
  3. on your text editor create a file called my.htaccess which we'll later rename on the server to .htaccess
  4. copy and paste the following text into my.htaccess

    # Interrupt Handler Specification for Test Environment

    ErrorDocument 302 /cgi-bin/thecgibin/testart05/handler.cgi
    ErrorDocument 400 /cgi-bin/thecgibin/testart05/handler.cgi
    ErrorDocument 401 /cgi-bin/thecgibin/testart05/handler.cgi
    ErrorDocument 403 /cgi-bin/thecgibin/testart05/handler.cgi
    ErrorDocument 404 /cgi-bin/thecgibin/testart05/handler.cgi
    ErrorDocument 500 /cgi-bin/thecgibin/testart05/handler.cgi
    ErrorDocument 501 /cgi-bin/thecgibin/testart05/handler.cgi
  5. save my.htaccess, upload to your server and rename it to .htaccess.
  6. Important -- verify that this new file on your server is /cgi-bin/thecgibin/testart05/.htaccess
Now we have a testing environment set up, but it's quite isolated so it shouldn't interfere with the workings of your visitors. To test this out you should enter the following two url's on your favorite browser:
  • http://www.mydomain.com/this-page-not-found/
  • http://www.mydomain.com/cgi-bin/thecgibin/testart05/this-page-not-found/
In the first case we're going after an address that doesn't exist on the main site. The server response should be the standard '404 Error - File not found' message that your server gives.

In the second case we're going against the test environment and the .htaccess file is telling the server to handle this 404 error by running handler.cgi on this path. And since that program doesn't exist yet, you should see something like this:

File Not Found

The requested URL /cgi-bin/thecgibin/testart05/this-page-not-found/ was not found on this server.

Additionally, a 404 File Not Found error was encountered while trying to use an ErrorDocument to handle the request.

If this worked as described and it all looks familiar and makes sense to you, it's time to proceed to the hander program.

If not, it'd be a great time to review what we've done up to this point.

The Handler Program

#!/usr/local/bin/perl
#
# Server Error Handler
#
# Program05(a) in a series of CGI/Perl Tutorials on
# http://www.thecgibin.com/
# Author : Marty Landman Email : cgiperl@thecgibin.com
#
# You may use and distribute this freely as long as you agree
#
# 1) not to hold Face 2 Interface Inc or Marty Landman
# responsible for the results of using this software
# 2) to keep these comments intact
#

use strict;
use vars qw (%Error %Fldlen);

&init;
&process;
&finis;

sub init {
print "Content-type: text/html\n\n
<html><head><title>Error Handler</title></head>\n";
require 'err_fld.pl' or die "Error_Field file not executed - $|\n";
}

sub process {
my ($name,$value,@env);
my @specs = &Rd_File($ENV{'REDIRECT_STATUS'});
for (keys %Fldlen) {$Fldlen{$_} = '';}
for (@specs) {
if ($_ =~ /^([\w|_]*)=(.*)\n$/) {
($name,$value) = ($1,$2);
if ($name =~ /^Env([\w|_]*)/) {push @env,$1;}
else {$Fldlen{$name} = $value;}
}
}
my $fld = 1;
print qq|<hr><h$fld align="center">
Server Error $ENV{'REDIRECT_STATUS'}</h$fld><hr>\n|;
for (sort keys %Fldlen) {
++$fld;
print qq|<br><h$fld align="center">$Fldlen{$_}</h$fld><br>\n|
if ($Fldlen{$_} ne '') and ($_ ne 'Entrance_URL');
print qq|<center><table bgcolor="#99CCCC" cellpadding="25">
<tr><td><a href="$Fldlen{$_}">Go to our homepage</a>
</td></tr></table></center><br><br>\n|
if $_ eq 'Entrance_URL';
}
print '<center><table border="1"><tr><th>Environment Field</th>
<th>Environment Value</th></tr>';
for (sort @env) {print "<tr><td>$_</td><td>$ENV{$_}</td></tr>\n";}
print '</table></center>',"\n";
}

sub Rd_File {
my @buffer;
my $file = "HTdata/Err$_[0].dat";
if (open(SPEC,$file)) {
push @buffer,$_ while ();
close(SPEC) or print "<br>Close Spec File $file failed - $!\n";
return (@buffer);
}
}

sub finis {
print "</body></html>\n";
}

__END__
How the Handler Works
The Error Handler program, handler.cgi will get invoked whenever one of the server error conditions occur under the directory where the .htaccess file was placed. The program will print out a standard type of formatted message, with text supplied by the site's webmaster. That means you will have to specify what that text is.
The Handler will pick up the data to be displayed from a file which has been precreated. There will be one file per error condition, and since the error conditions are each assigned 3 digit codes by the NCSA documentation, we'll use those to create the files. Look at 'sub Rd_File' in the program, it's towards the bottom. The second line of code says 'my $file = "HTdata/Err$_[0].dat";', and when the routine is called, it's passed as a parameter the error code. Therefore, when you point your browser at /cgi-bin/thecgibin/testart05/this-page-not-found/ the server will see that you have an .htaccess file installed on the directory, with a line that says

ErrorDocument 404 /cgi-bin/thecgibin/testart05/handler.cgi

on it. Since the error raised is a 404, the server will now invoke the handler program, and the handler program will in turn call the Rd_File subroutine with '404' as the parameter.
All of which means that the scalar $file will take on the value 'HTdata/Err404.dat'.
So, how do we go about creating seven error code specification files? That's where HTML forms and our other program come in. We'll install another program called msg_mgr.cgi which will be a web transaction for the webmaster to run. The program will present a form which gets filled in, and then process the info from that form.
The data collected by the Message Manager transaction will in turn be written out to flat files of the form 'HTdata/Errnnn.dat' where 'nnn' is the error number for the particular condition being trapped. Not coincidentally, these are the names of the data files being read by the Handler program.
The Message Manager Program

#!/usr/local/bin/perl
#
# Server Error Message Manager
#
# Program05(b) in a series of CGI/Perl Tutorials on
# http://www.thecgibin.com/
# Author : Marty Landman Email : cgiperl@thecgibin.com
#
# You may use and distribute this freely as long as you agree
#
# 1) not to hold Face 2 Interface Inc or Marty Landman
# responsible for the results of using this software
# 2) to keep these comments intact
#


use strict;
use CGI;
use vars qw($CGI %Error %Fldlen %Input);

&Init();
&Process();
&Finis();

sub Init {
$CGI = new CGI;
print $CGI->header;
require 'err_fld.pl' or die "Error_Field file not executed - $|\n";
print qq|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd"><html><head>
<title>Bug-Away : Message Manager Transaction</title></head>
<body bgcolor="#FFFFFF" link="#663333" vlink="#996666"
alink="#FF0000"><h2 align="center">Message Manager
Transaction</h2>
|;
}

sub Process {
!($ENV{'REQUEST_METHOD'} eq 'POST') ? &Prt_Form : &Prt_Msgs;
}

sub Prt_Form {
my $out;
print q|<form action="msg_mgr.cgi" method=post>|;
&prt_select('Err','Error Document Types this will apply to',\%Error);
for (sort keys %Fldlen) {
$out = &prep($_);
print "<br>$out<br>\n";
}
&prt_select('Env','Environment Variables to display to users',\%ENV);
print qq|<br><input type="submit" value="Submit"></form>\n|;
}

sub prep {
(my $desc = $_[0]) =~ s/_/ /g;
my $wi = 50;
my ($out,$ln,$val);
print qq|<br>$desc\n|;
if ($Fldlen{$_} < 100) {
$val = ($_ eq 'Entrance_URL') ? 'http://www.' : '';
$out = qq|<input type="text" name="$_" size="$wi" value="$val"
maxlength="$Fldlen{$_}">|;
}
else {
$ln = int($Fldlen{$_}/$wi);
$out = qq|<textarea name="$_" rows="$ln" cols="$wi"
wrap="virtual"></textarea>|;
}
return $out;
}

sub prt_select {

# print out checkboxes

my ($typ,$title,$href) = @_;
my ($name,@data,$txt);
while (($name) = each %$href) {push @data,$name;}

print "<br><br>Select one or more $title :<br>";
for (sort @data) {
($txt = $_) =~ s/_/ /g;
print qq|<br><input type="checkbox" name="$typ$_">$txt\n|;
}
}

sub Prt_Msgs {
&Get_Input;
my (@Files,%Outpt);
chop(my $shortdate = `date +"%D %T %Z"`);
for (keys %Input) {
print "<br>key = $_\n";
if ($_ =~ /^Err(\w+)/)
{push @Files,$1;}
else {$Outpt{$_} = $Input{$_};}
}
for (sort @Files) {
open (MSG,">HTdata/Err$Error{$_}.dat") or die "Open MSG failed:$!";
print MSG "***** $shortdate\n";
for (sort keys %Outpt) {print MSG "$_=$Outpt{$_}\n";}
close MSG or die "close MSG failed:$!";
}
my ($tag,$num,$mon_msg) = ('<h1 align="center">',++$#Files);
$mon_msg = "No messages have been specified" if $num == 0;
$mon_msg = "Your message has been edited" if $num == 1;
$mon_msg = "Your $num messages have been edited" if $num > 1;
print "$tag$mon_msg</h1>\n";
}

sub Get_Input {
my @Names = $CGI->param;
for (@Names) {$Input{$_} = $CGI->param("$_");}
}

sub Finis {
print qq|<br><br><h6 align="center">© 1999 Face 2 Interface Inc
</h6></body></html>\n\n|;
}

__END__
There's more to be said, and a missing part to the code too. Let's get into that stuff when we do the install.

separator

© thecgibin.com