Now
that we have looked at some of the common errors in CGI application
design, let's focus on programming errors that can cause unexpected
results. There is one extremely important point that you should
be aware of:
Always check the return value of all the system
commands, including eval, open, and system.
What does this mean? The next few sections will describe some
of the programming errors that occur frequently if you are not careful.
Since the server is running as a user that
has minimal privileges (usually "nobody"), you must be careful when
reading from or writing to files. Here is an example:
open (FILE, "<" . "/usr/local/httpd_1.4.2/data");
while (<FILE>) {
print;
}
close (FILE);
Now, what if the file that you are trying to read is not accessible?
The file handle FILE will not be created, but
the while loop tries to iterate through that file handle. Fortunately,
Perl does not get upset, but you will not have any data. So, it
is always better to check the status of the open
command, like this:
open (FILE, "<" . "/usr/local/httpd_1.4.2/data") ||
&call_some_subroutine ("Oops! The read failed. We need to do something.");
This will ensure that the subroutine call_some_subroutine
gets called if the script cannot open the file. Now, say you want
to write to an output file:
open (FILE, ">" . "/usr/local/httpd_1.4.2/data");
print FILE "Line 1", "\n;
print FILE "Line 2", "\n";
close (FILE);
Again, you should check for the status of the open
command:
open (FILE, ">" . "/usr/local/httpd_1.4.2/data") ||
&call_some_subroutine ("Oops! The write failed.
We need to do something".);
This is true when doing such tasks as updating a database
or creating a counter data file. In order for the server to write
to a file, it has to have write privileges on the file as well as
the directories in which the file is located.
We used pipes to
perform data redirection in numerous examples in this book. Unlike
files, there is no easy way to check to see if the contents of the
pipe have been successfully executed. Let's take a look at a simple
example:
open (FILE, "/usr/bin/cat /home/shishir/.login |")
|| &call_some_subroutine ("Error opening pipe!");
while (<FILE>) {
print;
}
close (FILE);
If the cat
command cannot be found by the shell, you might expect that an error
status will be returned by the open command,
and thus the call_some_subroutine function
will be called. However, this is not the case. An error status will
be returned only if a pipe cannot be created (which is almost never
the case). Due to the way the shell operates, the status of the
command is available only after the file handle is closed. Here
is an example:
open (FILE, "/usr/bin/cat /home/shishir/.login |")
|| &call_some_subroutine ("Error opening pipe!");
while (<FILE>) {
print;
}
close (FILE);
if ($?) {
&call_some_subroutine ("Error in executing command!");
}
Once the file handle is closed, Perl saves the return status
in the variable $?. This is the method that
you should use for all system commands.
There is another method for determining the status of the
pipe before the file handle is closed, though it is not always 100%
reliable. It involves checking the process ID (PID) of the process
that is spawned by the open command:
$pid = open (FILE, "/usr/bin/cat /home/shishir/.login |");
sleep (2);
$status = kill 0, $pid;
if ($status) {
while (<FILE>) {
print;
}
close (FILE);
} else {
&call_some_subroutine ("Error opening pipe!");
}
This is a neat trick! The kill statement with an argument of
0 checks the status of the process. If the process is alive, a value
of 1 is returned. Otherwise, a 0 is returned, which indicates that
the process is no longer alive. The sleep command
ensures a delay so that the value returned by kill
reflects the status of the process.