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.