|
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:
- point your ftp client to your website
- create a new directory under /cgi-bin/thecgibin/
called /testart05/
- on your text editor create a file called my.htaccess
which we'll later rename on the server to .htaccess
- 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
- save my.htaccess, upload to your server and rename it to
.htaccess.
- 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.
|