⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch17.htm

📁 CGI programming is the hottest stuff to look out for in this book
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<BR>
From Host:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$ENV{REMOTE_HOST}
<BR>
<BR>
END<BR>
if ( $tokens{'disposition'} eq 'like' ) {<BR>
&nbsp;&nbsp;&nbsp;print EM &quot;The respondant likes green eggs
and ham and would be willing &quot;;<BR>
&nbsp;&nbsp;&nbsp;print EM &quot;to pay $tokens{'pay'} for a green
eggs and ham main course.\n&quot;;<BR>
} else {<BR>
&nbsp;&nbsp;&nbsp;print EM &quot;The respondant doesn't like likes
green eggs and ham...&quot;,<BR>
&nbsp;&nbsp;&nbsp;&quot; yet.\n&quot;;<BR>
}<BR>
<BR>
print EM &quot;\nHistorical Responses\n&quot;;<BR>
print EM &quot;--------------------\n\n&quot;;<BR>
foreach ( @dataline ) {<BR>
&nbsp;&nbsp;&nbsp;print EM &quot;$_\n&quot;;<BR>
}<BR>
<BR>
close(EM);<BR>
<BR>
#<BR>
# Jump to a subroutine which will send formatted HTML to the HTTPd.&nbsp;&nbsp;The
<BR>
# message thanks the user for the form submission, including a
report<BR>
# on their submission information and also historical information.
<BR>
#<BR>
&amp;thank_user;<BR>
<BR>
exit 0;<BR>
<BR>
sub refpage_error {<BR>
&nbsp;&nbsp;&nbsp;print &quot;Content-type: text/html\n\n&quot;;
<BR>
&nbsp;&nbsp;&nbsp;print &lt;&lt;END;<BR>
&lt;HTML&gt;<BR>
&lt;HEAD&gt;&lt;TITLE&gt;Improper refering page!&lt;/TITLE&gt;&lt;/HEAD&gt;
<BR>
&lt;BODY&gt;<BR>
&lt;P&gt;<BR>
The page which invoked this CGI program was not<BR>
&lt;A HREF=$refpage&gt;&lt;B&gt;$refpage&lt;/B&gt;&lt;/A&gt;.&nbsp;&nbsp;Please
re-submit this form using<BR>
that page.<BR>
&lt;/BODY&gt;&lt;/HTML&gt;<BR>
END<BR>
&nbsp;&nbsp;&nbsp;exit 1;<BR>
}<BR>
<BR>
sub dislike_error {<BR>
&nbsp;&nbsp;&nbsp;print &quot;Content-type: text/html\n\n&quot;;
<BR>
&nbsp;&nbsp;&nbsp;print &lt;&lt;END;<BR>
&lt;HTML&gt;<BR>
&lt;HEAD&gt;&lt;TITLE&gt;Improper Input!&lt;/TITLE&gt;&lt;/HEAD&gt;
<BR>
&lt;BODY&gt;<BR>
&lt;P&gt;<BR>
If you don't like green eggs and ham then it doesn't make sense
to say <BR>
you'd buy them for ANY price.&nbsp;&nbsp;Please press the BACK
button on your browser and re-enter your reply.<BR>
&lt;/BODY&gt;&lt;/HTML&gt;<BR>
END<BR>
&nbsp;&nbsp;&nbsp;exit 1;<BR>
}<BR>
<BR>
sub like_error{<BR>
&nbsp;&nbsp;&nbsp;print &quot;Content-type: text/html\n\n&quot;;
<BR>
&nbsp;&nbsp;&nbsp;print &lt;&lt;END;<BR>
&lt;HTML&gt;<BR>
&lt;HEAD&gt;&lt;TITLE&gt;Improper Input!&lt;/TITLE&gt;&lt;/HEAD&gt;
<BR>
&lt;BODY&gt;<BR>
&lt;P&gt;<BR>
Since you said you like green eggs and ham it is required that
you provide<BR>
a price you'd buy them at.&nbsp;&nbsp;Please press the BACK button
on your browser <BR>
and re-enter your reply.<BR>
&lt;/BODY&gt;&lt;/HTML&gt;<BR>
END<BR>
&nbsp;&nbsp;&nbsp;exit 1;<BR>
}<BR>
<BR>
sub thank_user {<BR>
&nbsp;&nbsp;&nbsp;print &quot;Content-type: text/html\n\n&quot;;
<BR>
&nbsp;&nbsp;&nbsp;print &lt;&lt;END;<BR>
&lt;HTML&gt;<BR>
&lt;HEAD&gt;&lt;TITLE&gt;Thank you!&lt;/TITLE&gt;&lt;/HEAD&gt;
<BR>
&lt;BODY&gt;<BR>
&lt;P&gt;<BR>
Thank you for taking the time to fill out Funny Food's questionnaire.&nbsp;&nbsp;Your
<BR>
input has been added to the database.&nbsp;&nbsp;Now, you can
see how your replies <BR>
stack up against what other people have submitted:<BR>
END<BR>
&nbsp;&nbsp;&nbsp;print &quot;&lt;P&gt;You said that you &lt;B&gt;$tokens{'disposition'}&lt;/B&gt;
green eggs&quot;,<BR>
&nbsp;&nbsp;&nbsp;&quot; and ham.\n&quot;;<BR>
&nbsp;&nbsp;&nbsp;if ( $tokens{'disposition'} eq 'like' ) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &quot;&lt;P&gt;You would
pay as much as &lt;B&gt;$tokens{'pay'}&lt;/B&gt; for a &quot;
,<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;green eggs and ham main
course.\n&quot;;<BR>
&nbsp;&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;&nbsp;print &quot;&lt;H3&gt;Historical Information&lt;/H3&gt;&lt;HR&gt;&lt;PRE&gt;\n&quot;;
<BR>
<BR>
&nbsp;&nbsp;&nbsp;foreach ( @dataline ) { print &quot;$_\n&quot;;
}<BR>
&nbsp;&nbsp;&nbsp;print &quot;&lt;/PRE&gt;\n&quot;;<BR>
&nbsp;&nbsp;&nbsp;print &quot;&lt;/BODY&gt;&lt;/HTML&gt;\n&quot;;
<BR>
}</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
This code handles the fairly simple form data generated by greenegg.html.
The specific actions of this voting booth program are as follows:
<OL>
<LI>Get and decode the form data.
<LI>Check for errors. If any are found, display an error message
to the Web and abort the voting process.
<LI>Update the database file with the newly submitted information.
<LI>Compose an e-mail containing information on the current submission
and send it to both the voter and the CGI system maintainer.
<LI>Output a message thanking the user for voting to the Web.
This message contains a report on both the current vote submission
and votes in the past. (as shown in Figure 17.2).
</OL>
<P>
<A HREF="f17-2.gif" ><B>Figure 17.2:</B> <I>The message a user receives after voting. The historical information is output without parsing at the bottom of the page.</I></A>
<P>
This example has managed to capture the essentials of a voting
booth. The process asks your voting/polling-style questions, and
it generates a report that contains historical information regarding
all votes submitted to date. Still, I find that the &quot;feel&quot;
produced by this voting booth to be lacking. Yes, the questions
are phrased in a vote-like way, but really there isn't much difference
between this voting booth and a page that asks you whether or
not you'd like to purchase a charity gift-basket and how much
you'd like to pay for it-yet this example would be considered
an on-line ordering form.
<P>
Usually, there would be no utility in providing users with a report
of how many other people had bought charity baskets and a payment
breakdown. So in this sense, Funny Foods has managed to create
a bona fide voting booth. The display of the voting booth is fairly
primitive, though, and it's questionable as to how much useful
information can be gleaned from this report.
<H2><A NAME="BadVotingBoothGoodCodeTechnicalMe"><FONT SIZE=5 COLOR=#FF0000>Bad
Voting Booth, Good Code-Technical Merits of greenegg.cgi</FONT></A>
</H2>
<P>
I've already talked about how I feel that greenegg.cgi falls short
as a voting booth. Of course, I did this on purpose; my hope is
that you'll learn how to build a better voting booth from my (intentional)
mistakes. However, one aspect of greenegg.cgi I will <I>not</I>
compromise is its coding. Bad philosophy can be examined, but
bad code should never be duplicated.
<P>
Having said that, I will state that there is one aspect of this
code that could be improved upon in theory: modularity. What I
refer to as my standard <TT><FONT FACE="Courier">GET</FONT></TT>/<TT><FONT FACE="Courier">POST</FONT></TT>
method handler could be put in a subroutine, called as <TT><FONT FACE="Courier">&amp;subroutine_name</FONT></TT>
and defined by sub <TT><FONT FACE="Courier">subroutine_name {
... }</FONT></TT>. Even better, it could be encapsulated as a
subroutine in an external file. Within the Perl program, the subroutine
would still be called as <TT><FONT FACE="Courier">&amp;subroutine_name</FONT></TT>,
but its definition would be within another file. The Perl interpreter/compiler
would be instructed to find this file by placing the following
line at the top of your Perl program, immediately following <TT><FONT FACE="Courier">#!/usr/bin/perl</FONT></TT>:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">require &quot;external_file_name.pl&quot;;</FONT></TT>
</BLOCKQUOTE>
<P>
In other words, I could have re-created cgi-lib.pl. This is a
very popular package that does essentially the same job as my
standard <TT><FONT FACE="Courier">GET</FONT></TT>/<TT><FONT FACE="Courier">POST</FONT></TT>
handler, but it also has a lot of other useful CGI-handling features.
This Perl library file can be found at
<BLOCKQUOTE>
<TT><FONT FACE="Courier"><A HREF="http://www.bio.cam.ac.uk/cgi-lib/">http://www.bio.cam.ac.uk/cgi-lib/</A><BR>
</FONT></TT>
</BLOCKQUOTE>
<P>
<CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Caution</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
Please don't take this observation as an unmitigated endorsement! Though cgi-lib.pl is very popular, it does have its detractors. For a critical analysis of cgi-lib.pl, you can go to</BLOCKQUOTE>

</TD></TR>
</TABLE></CENTER>
<P>
<P>
<TT><FONT FACE="Courier"><A HREF="http://www.perl.com/perl/info/www/!cgi-lib.html">http://www.perl.com/perl/info/www/!cgi-lib.html</A></FONT></TT>
<P>
For more modularity, the section within the main portion of the
program that handles the creation of the e-mail could also be
brought within a subroutine.
<P>
Now, let's look at the positive points of greenegg.cgi:
<H3><A NAME="UseofAssociativeArraysfortheHandli">Use of Associative
Arrays for the Handling of <TT><FONT SIZE=4 FACE="Courier">GET</FONT></TT><FONT SIZE=4>/</FONT><TT><FONT SIZE=4 FACE="Courier">POST</FONT></TT><FONT SIZE=4>
Method Data</FONT></A></H3>
<P>
Perl's associative array feature allows data to be arranged in
an array that is indexed by character strings rather than integers.
This lets the programmer easily preserve the name-value pair structure
that forms pass to CGI programs through <TT><FONT FACE="Courier">GET</FONT></TT>
and <TT><FONT FACE="Courier">POST</FONT></TT>. If you wanted to
keep this structure without associative arrays, as you might if
you programmed in C, you could build parallel arrays and supply
a backwards-indexing scheme. Me, I'll stick to Perl.
<P>
<CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Caution</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
Associative arrays have a slight amount of difficulty when presented with name/value pairs generated by <TT><FONT FACE="Courier">&lt;INPUT TYPE=chECKBOX&gt;</FONT></TT> or <TT><FONT FACE="Courier">&lt;SELECT MULTIPLE&gt;</FONT></TT>. These sorts of form 
elements can create several name-value pairs that share the same name. Using the standard handler I provided, those memory locations in the array that would all be indexed by the same name will be overwritten with the newest value. Schemes to avoid this 
problem can be built as best suits the situation at hand.
</BLOCKQUOTE>

</TD></TR>
</TABLE></CENTER>
<P>
<H3><A NAME="ImmediateErrorTrappingUsingtheState">Immediate Error
Trapping Using the Statement Modifier Form of <TT><FONT SIZE=4 FACE="Courier">if</FONT></TT></A>
</H3>
<P>
Programmers who are familiar with C will easily recognize the
meaning of the following code:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">if (comparison) {<BR>
&nbsp;&nbsp;&nbsp;statement 1;<BR>
&nbsp;&nbsp;&nbsp;...<BR>
&nbsp;&nbsp;&nbsp;statement n;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
This structure is also perfectly valid in Perl, too. However,
a simple C <TT><FONT FACE="Courier">if</FONT></TT> structure could
be written as follows:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">if (comparison) statement;</FONT></TT>
</BLOCKQUOTE>
<P>
This is not the case in Perl; Perl doesn't allow dangling conditionals.
The Perl equivalent of this code would be
<BLOCKQUOTE>
<TT><FONT FACE="Courier">if (comparison) { statement; }</FONT></TT>
</BLOCKQUOTE>
<P>
To &quot;make up&quot; for this (non) deficiency, Perl has a statement-modifier
<TT><FONT FACE="Courier">if</FONT></TT> structure:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">statement if comparison;<BR>
(statement) if comparison;</FONT></TT>
</BLOCKQUOTE>
<P>
Many people who migrate to Perl from C find this style of <TT><FONT FACE="Courier">if</FONT></TT>
structure somewhat disconcerting the first time they see it. Many
of those people eventually learn to love it, though. I am a member
of both these sets. It's a clear, concise, and intuitive way of
writing an <TT><FONT FACE="Courier">if</FONT></TT> statement.
<H3><A NAME="SlurpingDatawitharrayFILEHANDLE">Slurping Data with
<TT><FONT SIZE=4 FACE="Courier">@array = &lt;FILEHANDLE&gt;;</FONT></TT></A>
</H3>
<P>
In more traditional languages, one would write a loop that would
read a file line by line until <TT><FONT FACE="Courier">EOF</FONT></TT>
was encountered. This can certainly be done in Perl, as well:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">while ( $line = &lt;FILEHANDLE&gt; )
{<BR>
&nbsp;&nbsp;&nbsp;@array[$i++] = $line;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
This sort of loop is essential in Perl if you wanted to do more
than just read lines into an array; for example, if you wanted
some sort of <TT><FONT FACE="Courier">if (condition)</FONT></TT>
to decide whether or not to include <TT><FONT FACE="Courier">$line</FONT></TT>
in the array or not. But if not, you can accomplish the same in
less code <I>and</I> less run-time with
<BLOCKQUOTE>
<TT><FONT FACE="Courier">@array = &lt;FILEHANDLE&gt;;<BR>
</FONT></TT>
</BLOCKQUOTE>
<P>
<CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Note</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
In the case of a file attached to a filehandle, it's easy to see where the <TT><FONT FACE="Courier">&lt;FILEHANDLE&gt;</FONT></TT> will stop being read into the array-at the end-of-file. However, you can also use the default standard input filehandle, 
<TT><FONT FACE="Courier">STDIN</FONT></TT>, in this context. I'm not sure you'd want to, though. How does <TT><FONT FACE="Courier">@array</FONT></TT> know when <TT><FONT FACE="Courier">EOF</FONT></TT> has been reached? When standard input encounters a 
<BR>
<TT><FONT FACE="Courier">CTRL-d EOF</FONT></TT> character. Intuitive, no?
</BLOCKQUOTE>

</TD></TR>
</TABLE></CENTER>
<P>
<H3><A NAME="UseofOutputFiltertoProvidestdinto">Use of Output
Filter to Provide <TT><FONT SIZE=4 FACE="Courier">stdin</FONT></TT><FONT SIZE=4>
to </FONT><TT><FONT SIZE=4 FACE="Courier">/usr/sbin/sendmail</FONT></TT><FONT SIZE=4>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -