Follow the checklist given in the discussion.
This checklist is 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, or 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 (most FTP clients support changing protections on uploaded files if you don't have shell access to your server).
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, such as .cgi or .plx. Some servers have options to permit access via the GET method alone, 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? Or, if your server uses #! lines, have you given the correct path in the #! line?
Identify the user the script runs as 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 files, network connections, system calls, and so on, that 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 protections on the file allow access? Are you trying to get 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 by 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 the 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) name=joe number=10 ^D % 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 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' 2.49
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 or use warnings? 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 or Chapter 23 of Programming Perl 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 use 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 return values from every system call? Many people blindly believe that every open or system or rename or 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 permissions on the libraries (they must be readable by the user the script runs as). Don't copy modules from one machine to another—a lot of them have compiled and autoloaded components hidden 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 slashdot 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.
Post to comp.infosystems.www.authoring.misc if your question is about a CGI script (the CGI module, decoding cookies, finding out where the user is coming from, etc.).
Recipe 19.2; the discussion on buffering in the Introduction of Chapter 8; the CGI FAQ at http://www.webthing.com/tutorials/cgifaq.html
Copyright © 2003 O'Reilly & Associates. All rights reserved.