Your CGI script gives you a
Follow the checklist given in the discussion. It's aimed at a Unix audience, but the general principles embodied in the questions apply to all systems.
Check ownership and permissions with ls -l. The appropriate read and execute bits must be set on the script before the web server can run it. The script should be readable and executable by everyone (or at least by whomever the server runs scripts as). Use chmod 0755 scriptname if it's owned by you, otherwise chmod 0555 scriptname if owned by the designated anonymous web user, assuming you are running as that user or the superuser. All directories in the path must also have their execute bit set.
Make sure the script can be identified as a script by the web server. Most web servers have a system-wide cgi-bin, and all files in that directory will be run as scripts. Some servers identify a CGI script as any file whose name ends in a particular extension, like .cgi or .plx. Some servers have options to permit access via the GET method alone, and not through the POST method that your form likely uses. Consult your web server documentation, configuration files, webmaster, and (if all else fails) technical support.
If you're running on Unix, do you have the right path to the Perl executable on the
#! line? The
#! line must be the first line in the script; you can't even have blank lines before the
#! line. Some operating systems have ridiculously short limits on the number of characters that can be in this line, so you may need to make a link (e.g., from /home/richh/perl to /opt/installed/third-party/software/perl-5.004/bin/perl, to pick a hypothetical pathological example).
If you're running on Win32, have you associated your Perl scripts with the correct Perl executable?
Identify the user the script runs as by replacing with the simple code shown in Example 19.2.
#!/usr/bin/perl # webwhoami - show web users id print "Content-Type: text/plain\n\n"; print "Running as ", scalar getpwuid($>), "\n";
This prints the username the script is running as.
Identify the resources the script is trying to access. List the files, network connections, system calls, and so on, which require special privilege. Then make sure they can be accessed by the user the script is running as. Are there disk or network quotas? Do the protections on the file allow access? Are you trying to get to the encrypted password field using
getpwent on a shadow password system (since usually only the superuser can get shadow passwords)?
Set permissions on any files the script needs to write to at
0666, or better yet to
0644 if they're owned up the effective user ID the script is running under. If new files are to be created or old ones moved or removed, write and execute permission on enclosing directory of those files is also needed.
Try to run it from a shell prompt. CGI.pm lets you run and debug your scripts from the command line or from standard input. Here,
^D represents whatever you type to get an End of File.
% perl -wc cgi-script # just compilation % perl -w cgi-script # parms from stdin
(offline mode: enter name=value pairs on standard input)
% perl -w cgi-script name=joe number=10 # run with mock form input % perl -d cgi-script name=joe number=10 # ditto, under the debugger # POST method script in csh % (setenv HTTP_METHOD POST; perl -w cgi-script name=joe number=10) # POST method script in sh % HTTP_METHOD=POST perl -w cgi-script name=joe number=10
Check the server's error log. Most web servers redirect CGI process's STDERR into a file. Find that file (try /usr/local/etc/httpd/logs/error_log, /usr/local/www/logs/error_log, or just ask your administrator) and see whether any warnings or error messages are showing up there.
Are you using an old version of Perl? Type perl -v to find out. If you're not using 5.004 or better, you or your admins should upgrade, because 5.003 and earlier releases were not protected against buffer overruns. This is a grave security matter.
Are you using an old version of the libraries? You can either grep -i version in the library file (probably in /usr/lib/perl5/, /usr/local/lib/perl5, /usr/lib/perl5/site_perl, or some such). For CGI.pm, and in fact, with any module, you can do this to figure out which version you're using:
% perl -MCGI -le 'print CGI->VERSION'
Are you running the latest version of your web server? It's not often that it happens, but sometimes a web server has bugs that can interfere with your scripts.
Are you running with the -w switch? This makes Perl gripe about things like using uninitialized variables, reading from a write-only filehandle, and so on.
Are you running with the -T flag? If Perl complains about insecure actions, you might be assuming things about your script's input and environment that aren't true. Make it taint-clean (read Recipe 19.4, see the perlsec manpage to find out about tainting and its consequences for your program, and check the CGI Security FAQ for particular web traps to avoid) and you may sleep easier at night as well as have a working script.
Are you running with
strict? It makes you declare variables before you use them and quote your strings to avoid any confusion with subroutines, and in doing so finds a lot of errors.
Are you checking the return values of each and every one of your system calls? Many people blindly believe that every
unlink in their programs will work all the time. These functions return a value so you can find out whether they worked or not - check them!
Can Perl find the libraries you're using? Write a small script that just prints
@INC (Perl's array of directories it looks for modules and libraries in). Check the permissions on the libraries (they must be readable by the user the script runs as). Don't try to copy modules from one machine to another - a lot of them have compiled and autoloaded components hidden away in the Perl library directory. Install them yourself from scratch.
Is Perl giving you warnings or errors? Try using CGI::Carp (see Recipe 19.2) to send Perl's error messages and warnings to the browser or a file you have access to.
The HTTP header must come before the text or image you return. Don't forget the blank line between the header and body. Also, because STDOUT is not automatically autoflushed but STDERR is, if your script generates warnings or errors to STDERR the web server might see them before it sees your HTTP header and can generate an error on some servers. Add this at the top of your script (after the
#! line) to also flush STDOUT:
$| = 1;
Don't ever try to decode the incoming form data by parsing the environment and standard input yourself. There are just too many places where it can go wrong. Use the CGI module and spend your time writing cool programs or reading Usenet instead of tracking down bugs in your implementation of an arcane protocol.
Check the FAQs and other documents mentioned at the end of the Introduction to this chapter. There is still a chance that you have made a common mistake on whatever system you're using - read the relevant FAQs to make sure you don't embarrass yourself by asking the CGI equivalent of "why doesn't my car run when it's out of gas and oil?"
Ask a friend. Almost everyone knows somebody they can ask for help. You'll probably get a reply much sooner than if you asked the Net.