Debugging CGI scripts can be tiresome because until they are pretty well working, nothing happens on the browser screen. If possible, it is a good idea to test a script every time you change it by running it locally from the command line before you invoke it from the Web. Perl will scan it, looking for syntax errors before it tries to run it. These error reports, which you will find repeated in the error log when you run under Apache, will save you a lot of grief.
Similarly, try out your MySQL calls from the command line to make sure they work before you embed them in a script.
Keep an eye on the Apache error log: it will often give you a useful clue, though it can also be bafflingly silent even though things are clearly going wrong. A common cause of silent misbehavior is a bad call to MySQL. The DBI module never returns, so your script hangs without an explanation in the error log.
As long as you have printed an HTTP header, something (but not
necessarily what you want) will usually appear in the browser screen.
You can use this fact to debug your scripts, by printing variables or
by putting print markers — GOT TO 1<BR>
,
GOT TO 2<BR>
. . . through the code so that
you can find out where it goes wrong. (<BR>
is the HTML command for a newline). This doesn’t
always work because these debugging messages may appear in weird
places on the screen — or not at all — depending on how
thoroughly you have confused the browser. You can also print to
error_log from your script:
print STDERR "thing\n";
or to:
warn "thing\n";
If you have an HTML document that sets up frames and you print anything else on the same page, they will not appear. This can be really puzzling.
You can see the HTML that was actually sent to the browser by putting the cursor on the page, right-clicking the mouse, and selecting View Source (or similar, depending on your flavor of browser).
When working with a database, it is often useful to print out the
$query
variable before the database is accessed.
It is worth remembering that although scripts that invoke MySQL will
often run from the command line (with various convincing error
messages caused by variables not being properly set up), if queries
go wrong when the script is run by Apache, they tend to hang without
necessarily writing anything to error_log. Often
the problem is caused by getting the quote marks wrong or by invoking
incorrect field names in the query.
A common, but enigmatic, message in error_log is: Premature
end of script headers
. This signals that the HTTP header
went wrong and can be caused by several different mistakes:
Your script refused to run at all. Run it from the command line and
correct any Perl errors. Try making it executable with chmod
+x <scriptname>
.
Your script has the wrong permissions to run under Apache.
The HTTP headers weren’t printed, or the final
\n
was left off it.
It generated an error before printing headers — look above in the error log.
Occasionally, these simple tricks do not work, and you need to print variables to a file to follow what is going on. If you print your error messages to STDERR, they will appear in the error log. Alternatively, if you want errors printed to your own file, remember that any program executed by Apache belongs to the useless webuser, and it can only write files without permission problems in webuser’s home directory. You can often elicit useful error messages by using:
open B,">>/home/webserver/script_errors" or die "couldn't open: $!"; close B;
Sometimes you have to deal with a bit of script that prints no page. For instance, when WorldPay (described in Chapter 12) has finished with a credit card transaction, it can call a link to your web site again. You probably will want the script to write the details of the transaction to the database, but there is no browser to print debugging messages. The only way out is to print them to a file, as earlier.
If you are programming your script in Perl, the CGI::Carp module can be helpful. However, most other languages[4] that you might want to use for CGI do not have anything so useful.