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

📄 ch06_04.htm

📁 用perl编写CGI的好书。本书从解释CGI和底层HTTP协议如何工作开始
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<a name="INDEX-1459" />text area tags with Embperl is similar tooutputting these tags with CGI.pm: if you create an element with aname matching an existing parameter, the value of the parameter isfilled in by default. When an element is created, Embperl checkswhether the name of that element exists within the<tt class="literal">%fdat</tt> hash (see below); if it does, then its valueis automatically filled in. Also, as HTML elements are generated,Embperl adds the name-value (if given) to <tt class="literal">%idat</tt>.</p></div></div><a name="ch06-15817" /><div class="sect2"><h3 class="sect2">6.4.4. Global Variables</h3><p><a name="INDEX-1460" /><a name="INDEX-1461" />Embperldefines a number of <a name="INDEX-1462" /> <a name="INDEX-1,463" /> <a name="INDEX-1,464" />global variables that you can usewithin your templates. Here is a list of the primary variables:</p><dl><dt><b><tt class="literal">%ENV</tt></b></dt><dd><p>This should look familiar. Embperl sets your environment variables tomatch standard CGI environment variables when running under<em class="emphasis">mod_perl</em>.</p></dd><dt><b><tt class="literal">%fdat</tt></b></dt><dd><p>This contains the name and value of all form fields that have beenpassed to your CGI script. Embperl, like CGI.pm, does not distinguishbetween GET and POST requests and loads parameters from either thequery string or the body of the request as appropriate. If an elementhas multiple values, these values are separated by tabs.</p></dd><dt><b><tt class="literal">%idat</tt></b></dt><dd><p>This contains the name and value of the form fields that have beencreated on the current page.</p></dd><dt><b><tt class="literal">%mdat</tt></b></dt><dd><p>This is only available when running under<em class="emphasis">mod_perl</em> with the Apache::Session module. Youcan use this hash to store anything and it will be available to everyfuture request for the same page, even if those requests are todifferent <tt class="command">httpd</tt> child processes.</p></dd><dt><b><tt class="literal">%udat</tt></b></dt><dd><p>This is only available when running under<em class="emphasis">mod_perl</em> with the Apache::Session module. Youcan use this hash to store anything and it will be available to anyfuture request made by the same user. This sends a HTTP cookie to theuser, but no cookies are sent if this hash is not used in your code.See <a href="ch11_03.htm#ch11-29714">Section 11.3, "Client-Side Cookies"</a>.</p></dd><dt><b><tt class="literal">@param</tt></b></dt><dd><p>If you use the <em class="emphasis">Execute</em> function to invokeEmbperl pages, the parameters you supply are available to your pagevia this variable.</p></dd></dl></div><a name="ch06-20-fm2xml" /><div class="sect2"><h3 class="sect2">6.4.5. Example</h3><p>Let's look at an example of using <a name="INDEX-1465" /> <a name="INDEX-1,466" />Embperl.For our example, we will create a basic "What'sNew" section that displays the headlines of recent stories. Ifusers click on a headline, they will be able to read the story. Thisin itself isn't that impressive, but we will createadministrative pages that make it very simple for someoneadministering the site to add, delete, and edit news stories.</p><p>There are a total of four pages to our application, the"What's New" page that displays current headlines;an article page where users can read a story; a main administrativepage that lists the current headlines and provides buttons foradding, deleting, and editing stories; and an administrative pagethat provides a form for entering a headline and article body, whichis used for both editing existing stories as well as creating newstories. These pages are shown later in <a href="ch06_04.htm#ch06-31772">Figure 6-3</a>through <a href="ch06_04.htm#ch06-86259">Figure 6-6</a>.</p><a name="ch06-21-fm2xml" /><div class="sect3"><h3 class="sect3">6.4.5.1. Embperl handler</h3><p>Traditional Embperl solutions use<em class="filename">.epl</em><a name="INDEX-1467" /><a name="INDEX-1468" /> files as the target of our requests.This example will work either via <em class="emphasis">mod_perl</em> or<em class="filename">embpcgi.pl</em>.</p><p>Let's look at the main "What's New" pagefirst. The code for <em class="filename">news.epl</em> is shown in <a href="ch06_04.htm#ch06-59372">Example 6-11</a>.</p><a name="ch06-59372" /><div class="example"><h4 class="objtitle">Example 6-11. news.epl </h4><blockquote><pre class="code">&lt;HTML&gt;[!  use lib "/usr/local/apache/lib-perl";  use News;!][- @stories = News::get_stories(  ) -]&lt;HEAD&gt;  &lt;TITLE&gt;What's New&lt;/TITLE&gt;&lt;/HEAD&gt;&lt;BODY BGCOLOR="white"&gt;&lt;H2&gt;What's New&lt;/H2&gt;&lt;P&gt;Here's the latest news of all that's happening around here.  Be sure to check back often to keep up with all the changes!&lt;/P&gt;&lt;HR&gt;&lt;UL&gt;  &lt;LI&gt;    [- ( $story, $headline, $date ) = @{ $stories[$row] } if $stories[$row] -]    &lt;A HREF="article.epl?story=[+ $story +]"&gt;[+ $headline +]&lt;/A&gt;    &lt;I&gt;[+ $date +]&lt;/I&gt;  &lt;/LI&gt;&lt;/UL&gt;  [$ if ( !@stories ) $]  &lt;P&gt;Sorry, there aren't any articles available now. Please check    back later!&lt;/P&gt;[$ endif $]&lt;/BODY&gt;&lt;/HTML&gt;</pre></blockquote></div><p>The result looks like <a href="ch06_04.htm#ch06-31772">Figure 6-3</a>.</p><a name="ch06-31772" /><div class="figure"><img width="473" src="figs/cgi2.0603.gif" height="199" alt="Figure 6-3" /></div><h4 class="objtitle">Figure 6-3. The main "What's New" page presented to users</h4><p>Embperl programs are much easier to read and maintain if you reducethe amount of Perl that is included in the HTML. We do this by movingmuch of our code into a common module, News.pm, which we place in<em class="filename">/usr/local/apache/perl-lib</em>.</p><p>We'll look at the News module in a moment, but let'sfinish looking at <em class="filename">news.epl</em> first. We call theNews module's <tt class="function">get_stories</tt> function. Thisreturns an array of stories with each element of the array containinga reference to an array of the story number, its headline, and thedate it was written.</p><p>Thus, within our unordered list later in the file, we loop over eachstory using Embperl's special <tt class="literal">$row</tt> variableand extract these elements of each story to the<tt class="literal">$story</tt>, <tt class="literal">$headline</tt>, and<tt class="literal">$date</tt> variables. Embperl will loop and create alist item until the expression containing <tt class="literal">$row</tt>evaluates to an undefined value. We then use these variables to builda link to a story as a list element.</p><p>If there are no stories, then we print a message telling the userthis. That's all there is to this file. <a href="ch06_04.htm#ch06-33311">Example 6-12</a> shows a relevant section of the<a name="INDEX-1469" />Newsmodule.</p><a name="ch06-33311" /><div class="example"><h4 class="objtitle">Example 6-12. News.pm (part 1 of 3) </h4><blockquote><pre class="code">#!/usr/bin/perl -wTpackage News;use strict;use Fcntl qw( :flock );my $NEWS_DIR = "/usr/local/apache/data/news";1;sub get_stories {    my @stories = (  );    local( *DIR, *STORY );        opendir DIR, $NEWS_DIR or die "Cannot open $NEWS_DIR: $!";    while ( defined( my $file = readdir DIR ) ) {        next if $file =~ /^\./;       # skip . and ..        open STORY, "$NEWS_DIR/$file" or next;        flock STORY, LOCK_SH;        my $headline = &lt;STORY&gt;;        close STORY;        chomp $headline;        push @stories, [ $file, $headline, get_date( $file ) ];    }    closedir DIR;    return sort { $b-&gt;[0] &lt;=&gt; $a-&gt;[0] } @stories;}# Returns standard Unix timestamp without the time, just the datesub get_date {    my $filename = shift;    ( my $date = localtime $filename ) =~ s/ +\d+:\d+:\d+/,/;    return $date;}</pre></blockquote></div><p>We store the path to the news directory in<tt class="literal">$NEWS_DIR</tt>. Note that we use a lexical variablehere instead of a constant because if this script is used with<em class="emphasis">mod_perl</em>, as is often the case with Embperl,using constants can generate extra messages in the log file.We'll discuss why this happens in <a href="ch17_03.htm#ch17-15286">Section 17.3, "mod_perl"</a>.</p><p>The format for our article files is rather basic. The first line isthe headline, and all following lines are the body of the article,which should contain HTML formatting. The files are named accordingto the time that they are saved, using the result of Perl's<tt class="function">time</tt> function -- the number of seconds afterthe epoch.</p><p>For the sake of this example we will assume that there is only oneadministrator who has access to create and edit files. If this werenot the case, we would need to create a more elaborate way to namethe files to prevent two people from creating stories at the samesecond. Plus, we would need to create a system to avoid having twoadministrators edit the same file at the same time; one way to dothis would be to have the edit page retrieve the current time into ahidden field when it loads a file for editing, which could then becompared against the last modification time of the file when the fileis saved. If the file has been modified since it was loaded, a newform would need to be presented to the administrator showing bothsets of changes so they can be reconciled.</p><p>The <tt class="function">get_stories</tt> function opens this newsdirectory and loops through each file. It skips any files startingwith a dot, including the current and parent directories. If weencounter any system errors reading directories we die; if we haveproblems reading a file, we skip it. Filesystem errors are notcommon, but they can happen; if you wish to generate a more friendlyresponse to the user than a cryptic <em class="emphasis">500 Internet ServiceError</em>, use <a name="INDEX-1470" /> <a name="INDEX-1,471" /> <a name="INDEX-1,472" /><a name="INDEX-1473" />CGI::Carp with<em class="emphasis">fatalsToBrowser</em> to catch any<tt class="function">die</tt> calls.</p><p>We get a shared <a name="INDEX-1474" /><a name="INDEX-1475" />lockon the file to make sure that we are not reading a file that is inthe process of being written by the administrator. Then we read thestory's headline and add the story's file number,headline, and date created to our list of stories. The<tt class="function">get_date</tt> function simply generates a Unixtimestamp from the file number via Perl's<em class="emphasis">localtime</em> function. That looks like this:</p><blockquote><pre class="code">Sun Feb 13 17:35:00 2000</pre></blockquote><p>It then replaces the time with a comma in order to get a basic datethat looks like this:</p><blockquote><pre class="code">Sun Feb 13, 2000</pre></blockquote><p>Finally, we sort the list of stories from largest to smallestaccording to the article number. Because this is the same as the datethe file was created, newest headlines will always appear at thebeginning of the list.</p><p>When the user selects a headline from the list, the applicationfetches the corresponding article. <a href="ch06_04.htm#ch06-87045">Example 6-13</a> showsthe page that displays the articles.</p><a name="ch06-87045" /><div class="example"><h4 class="objtitle">Example 6-13. article.epl </h4><blockquote><pre class="code">&lt;HTML&gt;[!  use lib "/usr/local/apache/lib-perl";  use News;!][- ( $headline, $article, $date ) = News::get_story( $fdat{story} ) -]&lt;HEAD&gt;  &lt;TITLE&gt;[+ $headline +]&lt;/TITLE&gt;&lt;/HEAD&gt;&lt;BODY BGCOLOR="white"&gt;  &lt;H2&gt;[+ $headline +]&lt;/H2&gt;  &lt;P&gt;&lt;I&gt;[+ $date +]&lt;/I&gt;&lt;/P&gt;  [+ local $escmode = 0; $article +]    &lt;HR&gt;  &lt;P&gt;Return to &lt;A HREF="news.epl"&gt;What's New&lt;/A&gt;.&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</pre></blockquote></div><p>The result looks like <a href="ch06_04.htm#ch06-97278">Figure 6-4</a>.</p><a name="ch06-97278" /><div class="figure"><img width="473" src="figs/cgi2.0604.gif" height="218" alt="Figure 6-4" /></div><h4 class="objtitle">Figure 6-4. A sample story</h4><p>Because most of the work is done by the News module, this file isalso quite simple. The links to this page from the main"What's New" page include a query string thatspecifies the number of the story to view. We use Embperl'sspecial <tt class="literal">%fdat</tt> hash to retrieve the number of thestory and pass it to the<em class="emphasis">News</em>::<tt class="function">get_story</tt> function,which gives us the headline, article contents, and date of thearticle.</p><p>Then we simply need to include tags for these variables in ourdocument where we want to display the data.<tt class="literal">$article</tt> requires some extra consideration. Thebody of the article contains HTML, but by default<a name="INDEX-1476" /><a name="INDEX-1477" />Embperl escapes any HTMLgenerated by your Perl blocks, so for example, &lt;P&gt; will beconverted to <tt class="literal">&amp;lt;P&amp;gt;</tt>. In order todisable this, we set Embperl's special<tt class="literal">$escmode</tt> variable to <tt class="literal">0</tt>, andbecause we provide a <tt class="function">local</tt> scope to thevariable, this change only lasts for the current block and the formervalue of <tt class="literal">$escmode</tt> is reset after the article isoutput.</p>

⌨️ 快捷键说明

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