📄 ch33.htm
字号:
<HTML>
<HEAD>
<TITLE>Chapter 33 -- Debugging CGI Applications</TITLE>
<META NAME="GENERATOR" CONTENT="Mozilla/3.0b5aGold (WinNT; I) [Netscape]">
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000EE" VLINK="#551A8B" ALINK="#CE2910">
<H1><FONT COLOR=#FF0000>Chapter 33</FONT></H1>
<H1><B><FONT SIZE=5 COLOR=#FF0000>Dynamic Image Creation</FONT></B>
</H1>
<P>
<HR WIDTH="100%"></P>
<P>
<H3 ALIGN=CENTER><FONT COLOR="#000000"><FONT SIZE=+2>CONTENTS<A NAME="CONTENTS"></A>
</FONT></FONT></H3>
<UL>
<LI><A HREF="#WrongPermissionsonCGIScripts" >Wrong Permissions on CGI Scripts</A>
<UL>
<LI><A HREF="#CheckingReturnedValuesfromScripts" >Checking Returned Values from Scripts</A>
<LI><A HREF="#CheckingErrorsWhenOpeningFiles" >Checking Errors When Opening Files</A>
<LI><A HREF="#DebugYourCGIScript" >Debug Your CGI Script</A>
<LI><A HREF="#CheckingErrorsWhenOpeningPipes" >Checking Errors When Opening Pipes</A>
<li><a href="#SendMail">Send Mail to Valid Recipients</a></UL>
<LI><A HREF="#UsethePerlInterpreterLineonUNIXSy" >Use the Perl Interpreter Line on UNIX Systems</A>
<LI><A HREF="#LibrariesforDynamicallyLoadedModules" >Libraries for Dynamically Loaded Modules</A>
<LI><A HREF="#CheckforSupportforSystemCalls" >Check for Support for System Calls</A>
<LI><A HREF="#DontReturnMalformedHeaders" >Don't Return Malformed Headers</A>
<LI><A HREF="#FlushOutputBuffersImmediately" >Flush Output Buffers Immediately</A>
<LI><A HREF="#DontSetEnvironmentVariables" >Don't Set Environment Variables</A>
<LI><A HREF="#CleanUpAfterYourself" >Clean Up After Yourself</A>
<LI><A HREF="#ConfigureYourServerCorrectly" >Configure Your Server Correctly</A>
<LI><A HREF="#AlwaysCreateanindexhtmlFile" >Always Create an index.html File</A>
<LI><A HREF="#Summary" >Summary</A>
</UL>
<HR>
<P>
This chapter is devoted to providing solutions to some of the
most common bugs you'll run across when debugging CGI applications.
The information in this chapter is the result of many frustrating
hours spent figuring out why an obviously simple CGI script would
not work. Hopefully, the information in this chapter will solve
some of the problems you might face while debugging CGI scripts.
The information in this chapter is based on topics covered in
<A HREF="ch20.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch20.htm" >Chapter 20</A>, "Introduction to Web
Pages and CGI."
<P>
Basically, this chapter will cover the points to keep in mind
when you write CGI scripts that have to open files or pipes or
keep temporary information in files, as well issues about how
to respond to client-side requests. We will also cover some security
issues about writing and placing Perl scripts in directory trees.
The summary at the end of the chapter will serve as a good checklist
for you to use when evaluating potential problems with your Perl
CGI scripts.
<H2><A NAME="WrongPermissionsonCGIScripts"><B><FONT SIZE=5 COLOR=#FF0000>Wrong
Permissions on CGI Scripts</FONT></B></A></H2>
<P>
The CGI script on the server side must be an executable file and
have execute permissions set for the file. Not having the correct
permissions results in "file not found" errors sent
back to the client. Not having execute permissions results in
other error messages being sent back to the client.
<H3><A NAME="CheckingReturnedValuesfromScripts"><B>Checking Returned
Values from Scripts</B></A></H3>
<P>
All paths of execution in the CGI script must return a value that
can be interpreted by the client. Test your CGI to make sure that
the application does not exit with an unpredictable return code.
If the CGI script relies on files on the server side, are they
accessible? The CGI script will be running under the same permissions
as the Web server. The server runs as the user called "nobody."
Make sure that the data files being accessed by the CGI script
have the correct read/write permissions for being accessed by
"nobody."
<H3><A NAME="CheckingErrorsWhenOpeningFiles"><B>Checking Errors
When Opening Files</B></A></H3>
<P>
Opening the file usually entails checking for errors before proceeding.
Here's a usual call in a Perl script to open a file and read from
it:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">open(MFILE,"</tmp/bogus/data/file")
<BR>
|| die "$!: Cannot open it!";</FONT></TT>
</BLOCKQUOTE>
<P>
If the Perl script skips the error-checking portion and just goes
on attempting to read from the nonexistent file handle <TT><FONT FACE="Courier">MFILE</FONT></TT>,
it will read no data. (Perl does not crash in this instance.)
For example, the following lines are expected to return a GIF
image back to the client:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">print "Content-type:image/gif \n\n";
<BR>
open(MFILE,"</tmp/bogus/data/image.file");<BR>
while (<MFILE>) {<BR>
print $_;<BR>
}<BR>
close MFILE;</FONT></TT>
</BLOCKQUOTE>
<P>
This code would be called in a CGI script to return the contents
of an image back to the browser whose request caused the script
to be executed. If the GIF image being opened does not exist,
then no data is sent back to the browser. Here are the ways to
avoid such errors:
<UL>
<LI><FONT COLOR=#000000>Write some code to make sure that the
data file being read does exist and could be opened.</FONT>
<LI><FONT COLOR=#000000>Return an error message back to the client
if a file cannot be opened or some condition, such as an empty
file, prevents the file from being opened.</FONT>
</UL>
<H3><A NAME="DebugYourCGIScript"><B>Debug Your CGI Script</B></A>
</H3>
<P>
One important thing to look for are possible infinite loops. Make
sure your CGI script always returns. Remember that CGI scripts
are run as the result of a client request coming to your server.
It's quite possible to have several clients make the same request
to start off these infinitely looping CGI scripts on your server.
Too many of these scripts will cause the machine running the server
to lock up!
<H3><A NAME="CheckingErrorsWhenOpeningPipes"><B>Checking Errors
When Opening Pipes</B></A></H3>
<P>
Another common mistake when writing CGI scripts is to use the
error from a pipe command directly. The returned code from a pipe
command is based on whether or not the pipe was opened. The returned
code from the pipe command has nothing to do with the command
on either side of the pipe symbols (<TT><FONT FACE="Courier">|</FONT></TT>).
For example, the following code will almost never execute the
<TT><FONT FACE="Courier">die</FONT></TT> statement because a pipe
almost always can be opened on a given system:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">open(MYFILE,"myprogram |")
|| die "Cannot run myprogram";</FONT></TT>
</BLOCKQUOTE>
<P>
Instead, break this statement into two statements and then close
the file handle. The relevant error code will be in the variable
(<TT><FONT FACE="Courier">$?</FONT></TT>) in case of any errors.
Use the error code returned from the <TT><FONT FACE="Courier">close</FONT></TT>
call before proceeding with the second portion of the code. If
there are no errors, reopen the file and continue. This procedure
sounds really hokey, but it works as long as you keep two things
in mind: that starting up <TT><FONT FACE="Courier">myprogram</FONT></TT>
is not inefficient and that each invocation of <TT><FONT FACE="Courier">myprogram</FONT></TT>
is totally unrelated to any previous invocations of <TT><FONT FACE="Courier">myprogram</FONT></TT>.
If these conditions are met, then you can go ahead and simply
structure the code like this:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">open(MYFILE,"myprogram |");
<BR>
close(MYFILE);<BR>
if ($?)<BR>
{<BR>
die "\n Cannot run myprogram";<BR>
}<BR>
open(MYFILE,"myprogram |");</FONT></TT>
</BLOCKQUOTE>
<a name="SendMail"><H3><B>Sending Mail to Valid Recipients</B></H3>
<P>
One way to use CGI scripts is to send mail to a recipient as part
of a response to a <TT><FONT FACE="Courier">FORM</FONT></TT> handler.
For example, the following statements send a mail message using
<TT><FONT FACE="Courier">mailx</FONT></TT>:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$sendTo = "badguy@bad.code.edu";
<BR>
#### NO, NO, NO, NOT this way....<BR>
open (MAILME,"| mailx -s 'A report' $sendTo")<BR>
print MAILME, $mailMessage;<BR>
#<BR>
# some other code here.<BR>
#<BR>
close MAILME;</FONT></TT>
</BLOCKQUOTE>
<P>
When using lines to send mail, make sure you specify the absolute
pathname to the mailer program. Also, close the pipe to the mail
handler as soon as possible; otherwise you might forget to do
so later in the code. Therefore, it's generally better to structure
the previous lines as this:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$sendTo = "myname@ikra.com";
<BR>
open (MAILME,"| /usr/bin/mailx -s 'A report' $sendto")
<BR>
print MAILME, $mailMessage;<BR>
close MAILME;<BR>
#<BR>
# some other code here.<BR>
#</FONT></TT>
</BLOCKQUOTE>
<P>
Of course, you should use your system's mail carrier, such as
<TT><FONT FACE="Courier">mh</FONT></TT>, or<TT><FONT FACE="Courier">
elm</FONT></TT>, instead of <TT><FONT FACE="Courier">mailx</FONT></TT>
in the previous example. Obviously, the underlying mail system
has to be up and running for this to work.
<H2><A NAME="UsethePerlInterpreterLineonUNIXSy"><B><FONT SIZE=5 COLOR=#FF0000>Use
the Perl Interpreter Line on UNIX Systems</FONT></B></A></H2>
<P>
Most CGI applications run on UNIX systems that require the first
line of the CGI script to be a "bang" line. For example,
if your CGI script is a Perl script and your Perl interpreter
is in <TT><FONT FACE="Courier">/usr/local/bin</FONT></TT>, then
the first line of the file should be <TT><FONT FACE="Courier">#!/usr/local/bin/perl</FONT></TT>.
If you don't use this bang line, the default shell script is used
instead, and your CGI script is run by the default shell script.
<P>
On NT systems, the Perl CGI script should not have the bang line
as the first line in the script. The bang line is ignored on NT
systems. The CGI script should run on the NT machine without any
problems. However, when porting CGI scripts from an NT system
to a UNIX system, make sure you add the <TT><FONT FACE="Courier">#!</FONT></TT>
line to the first line of every Perl CGI script.
<H2><A NAME="LibrariesforDynamicallyLoadedModules"><B><FONT SIZE=5 COLOR=#FF0000>Libraries
for Dynamically Loaded Modules</FONT></B></A></H2>
<P>
Some Perl scripts use the <TT><FONT FACE="Courier">Autoload.pm</FONT></TT>
module to dynamically load in extensions at execution time. A
Perl script will not run if the module cannot dynamically load
the extensions. When porting such scripts to different systems,
ensure that the extensions you have to load are available on each
system you port your Perl script to. Some modules may not be available
on the base system you port your CGI script to.
<P>
To avoid such problems at load time, you can either port the modules
yourself, not use the module extensions, or statically link the
extensions in. For example, most modules are statically linked
into the NT version of Perl because the <TT><FONT FACE="Courier">autoload</FONT></TT>
module is not supported under NT. If you are certain that the
modules you are loading are not dynamically linked executables
and that all the functionality you need is in the <TT><FONT FACE="Courier">.pm
</FONT></TT>file, then you can simply use the <TT><FONT FACE="Courier">use</FONT></TT>
statement to load the <TT><FONT FACE="Courier">.pm</FONT></TT>
module file.
<H2><A NAME="CheckforSupportforSystemCalls"><B><FONT SIZE=5 COLOR=#FF0000>Check
for Support for System Calls</FONT></B></A></H2>
<P>
Avoid system calls as much as possible when writing CGI scripts
that have to run on different systems. As its name suggests, a
system call is very dependent on the type of system on which it's
being called. Most versions of UNIX support system calls uniformly
and do not cause any problems. Different operating systems support
different types of system calls. A system call that works on a
VMS system might not work on a UNIX system, and vice versa.
<H2><A NAME="DontReturnMalformedHeaders"><B><FONT SIZE=5 COLOR=#FF0000>Don't
Return Malformed Headers</FONT></B></A></H2>
<P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -