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

📄 ch11_02.htm

📁 用perl编写CGI的好书。本书从解释CGI和底层HTTP协议如何工作开始
💻 HTM
📖 第 1 页 / 共 2 页
字号:
    unlink cart_filename( $id ) or die "Cannot remove user's cart file: $!";        print header( $q, "Thank You!" ),          $q-&gt;p( "Thanks for shopping with us, $customer{name}. ",                 "We will contactly you shortly!"          ),          $q-&gt;end_html;}</pre></blockquote><p>Again, nothing here should be unfamiliar. Within our tables we makeextensive use of the feature within CGI.pm that distributes tagsaround items if they are supplied as<a name="INDEX-2269" /><a name="INDEX-2270" />array references. We also includehidden fields in all of our forms for "id", whichcontains the <a name="INDEX-2271" /> <a name="INDEX-2,272" />session identifier.</p><p><a href="ch11_02.htm#ch11-12515">Figure 11-3</a> shows the shopping cart page.</p><a name="ch11-12515" /><div class="figure"><img width="481" src="figs/cgi2.1103.gif" height="211" alt="Figure 11-3" /></div><h4 class="objtitle">Figure 11-3. The shoppe.cgi shopping cart page</h4><p>Now let's look at the <a name="INDEX-2274" />functions that maintain theuser's state for us:</p><blockquote><pre class="code">#/--------------------------------------------------------------------# State subs# sub get_id {    my $q = shift;    my $id;        my $unsafe_id = $q-&gt;param( "id" ) || '';    $unsafe_id =~ s/[^\dA-Fa-f]//g;        if ( $unsafe_id =~ /^(.+)$/ ) {        $id = $1;        load_state( $q, $id );    }    else {        $id = unique_id(  );        $q-&gt;param( -name =&gt; "id", -value =&gt; $id );    }        return $id;}# Loads the current CGI object's default parameters from the saved statesub load_state {    my( $q, $id ) = @_;    my $saved = get_state( $id ) or return;        foreach ( $saved-&gt;param ) {        $q-&gt;param( $_ =&gt; $saved-&gt;param($_) ) unless defined $q-&gt;param($_);    }}# Reads a saved CGI object from disk and returns its params as a hash refsub get_state {    my $id = shift;    my $cart = cart_filename( $id );    local *FILE;        -e $cart or return;    open FILE, $cart or die "Cannot open $cart: $!";    my $q_saved = new CGI( \*FILE ) or        error( $q, "Unable to restore saved state." );    close FILE;        return $q_saved;}# Saves the current CGI object to disksub save_state {    my $q = shift;    my $cart = cart_filename( $id );    local( *FILE, *DIR );        # Avoid DoS attacks by limiting the number of data files    my $num_files = 0;    opendir DIR, $DATA_DIR;    $num_files++ while readdir DIR;    closedir DIR;        # Compare the file count against the max    if ( $num_files &gt; $MAX_FILES ) {        error( $q, "We cannot save your request because the directory " .                   "is full. Please try again later" );    }        # Save the current CGI object to disk    open FILE, "&gt; $cart" or return die "Cannot write to $cart: $!";    $q-&gt;save( \*FILE );    close FILE;}# Returns a list of item titles and quantitiessub get_items {    my $q = shift;    my @items;        # Build a sorted list of movie titles and quantities    foreach ( $q-&gt;param ) {        my( $title, $quantity ) = ( $_, $q-&gt;param( $_ ) );                # Skip "* " from beginning of movie titles; skip other keys        $title =~ s/^\*\s+// or next;        $quantity or next;                push @items, [ $title, $quantity ];    }    return @items;}# Separated from other code in case this changes in the futuresub cart_filename {    my $id = shift;    return "$DATA_DIR/$id";}sub unique_id {    # Use Apache's mod_unique_id if available    return $ENV{UNIQUE_ID} if exists $ENV{UNIQUE_ID};        require Digest::MD5;        my $md5 = new Digest::MD5;    my $remote = $ENV{REMOTE_ADDR} . $ENV{REMOTE_PORT};        # Note this is intended to be unique, and not unguessable    # It should not be used for generating keys to sensitive data    my $id = $md5-&gt;md5_base64( time, $$, $remote );    $id =~ tr|+/=|-_.|;  # Make non-word chars URL-friendly    return $id;}</pre></blockquote><p>The first function, <tt class="function">get_id</tt>, checks whether thescript received a parameter named "id"; this can besupplied in the query string or as a hidden field in a form submittedvia POST. Because we later use this as a filename, we perform acouple of checks to make sure that the identifier is safe. Then wecall <tt class="function">load_state</tt> to retrieve any previously savedinformation. If it did not receive an identifier, then it generates anew one.</p><p>The <tt class="function">load_state</tt> function calls<tt class="function">get_state</tt>, which checks whether there is a filematching the user's identifier and creates a CGI.pm object fromit if so. <tt class="function">load_state</tt> then loops through theparameters in the saved CGI.pm, adding them to the current CGI.pmobject. It skips any parameters that are already defined in thecurrent CGI.pm object. Remember this was triggered by a call to<tt class="function">get_id</tt> at the top of the script, so all of thisis happening before any form processing has been done; if weoverwrite any current parameters, we lose that information. Byloading saved parameters into the current CGI.pm object, it allowsCGI.pm to fill in these values as defaults in the forms. Thus, thecatalog and checkout pages remember the information you previouslyentered until the order is submitted and the cart is deleted.</p><p>The <tt class="function">save_state</tt> function is the complement of<tt class="function">get_state</tt>. It takes a CGI.pm object and saves itto disk. It also counts the number of carts that are already in thedata directory. One problem with this CGI script is that it allowssomeone to repeatedly visit the site with different identifiers andthus create multiple cart files. We do not want someone to fill upthe available disk space, so we limit the number of carts. We couldalso assign<tt class="literal">$CGI::POST_MAX</tt><a name="INDEX-2275" /> a low value at thestart of the script if we wanted to be extra careful (refer to <a href="ch05_01.htm#ch05-33739">Section 5.1.1, "Denial of Service Attacks"</a>).</p><p>The <tt class="function">get_items</tt> function is used by the<tt class="function">cart</tt> function, above, and the<tt class="function">send_email</tt> function, below. It loops over theparameters in a CGI.pm object, finds the ones beginning with anasterisk, and builds a list of these items along with theirquantities.</p><p>The <tt class="function">get_state</tt>, <tt class="function">save_state</tt>,and <tt class="function">thanks</tt> functions all interact with the cartfile. The <tt class="function">cart_filename</tt> function simplyencapsulates the logic used to generate a filename.</p><p>Finally, the <tt class="function">unique_id</tt> function is the same onewe saw <a name="INDEX-2276" />earlier in <a href="ch11_01.htm#ch11-50116">Example 11-1</a>.</p><p>Our CGI script also uses a number of additional <a name="INDEX-2277" /><a name="INDEX-2278" />utility functions.Let's take a look at them:</p><blockquote><pre class="code">#/--------------------------------------------------------------------# Other helper subs# sub header {    my( $q, $title ) = @_;        return $q-&gt;header( "text/html" ) .           $q-&gt;start_html(               -title    =&gt; "The Tennis Shoppe: $title",               -bgcolor  =&gt; "white"           ) .           $q-&gt;h2( $title ) .           $q-&gt;hr;}sub footer {    my( $q, $id ) = @_;    my $url = $q-&gt;script_name;        my $catalog_link =        $q-&gt;a( { -href =&gt; "$url?action=catalog&amp;id=$id" }, "View Catalog" );    my $cart_link =        $q-&gt;a( { -href =&gt; "$url?action=cart&amp;id=$id" }, "Show Current Cart" );    my $checkout_link =        $q-&gt;a( { -href =&gt; "$url?action=checkout&amp;id=$id" }, "Checkout" );        return $q-&gt;hr .           $q-&gt;p( "[ $catalog_link | $cart_link | $checkout_link ]" ) .           $q-&gt;end_html;}sub email_sales {    my( $customer, $items ) = @_;    my $remote = $ENV{REMOTE_HOST} || $ENV{REMOTE_ADDR};    local *MAIL;        my @item_rows  = map sprintf( "%-50s     %4d", @$_ ), @$items;    my $item_table = join "\n", @item_rows;        open MAIL, "| $SENDMAIL" or        die "Cannot create pipe to sendmail: $!";        print MAIL unindent &lt;&lt;"    END_OF_MESSAGE";        To: $SALES_EMAIL        Reply-to: $customer-&gt;{email}        Subject: New Order        Mime-Version: 1.0        Content-Type: text/plain; charset="us-ascii"        X-Mailer: WWW to Mail Gateway        X-Remote-Host: $remote                Here is a new order from the web site.                Name:       $customer-&gt;{name}        Email:      $customer-&gt;{email}        Address:    $customer-&gt;{address}        City:       $customer-&gt;{city}        State:      $customer-&gt;{state}        Zip:        $customer-&gt;{zip}                Title                                               Quantity        -----                                               --------    END_OF_MESSAGE        close MAIL or die "Could not send message via sendmail: $!";}sub unindent {    local $_ = shift;        my( $indent ) = sort                    map /^(\s*)\S/,                    split /\n/;    s/^$indent//gm;    return $_;}</pre></blockquote><p>The <tt class="function">header</tt><a name="INDEX-2279" /> and <tt class="function">footer</tt>functions simply return HTML, and help us maintain a consistentheader and footer across the pages. In this example<tt class="function">header</tt> and <tt class="function">footer</tt> arerather simple, but if we wanted to improve the look of our site, wecould do a lot simply by modifying these two functions.</p><p>The checkout page is shown in <a href="ch11_02.htm#ch11-69770">Figure 11-4</a>.</p><a name="ch11-69770" /><div class="figure"><img width="481" src="figs/cgi2.1104.gif" height="331" alt="Figure 11-4" /></div><h4 class="objtitle">Figure 11-4. The shoppe.cgi checkout page</h4><p>The <tt class="function">send_email</tt><a name="INDEX-2282" /><a name="INDEX-2283" /> function sends a the completedorder information to our sales folks. We use our<tt class="function">unindent</tt> function from <a href="ch05_01.htm">Chapter 5, "CGI.pm"</a> so we can indent our email message in the codeand still format it properly when we send it.</p><p>As we've seen in the last two sections, passing a sessionidentifier from document to document can get a bit tedious. We eitherhave to embed the information in an existing HTML file, or constructone containing the identifier entirely on the fly. In the nextsection, we'll look at client-side persistent cookies, wherethe browser allows us to store information on the client side. Thatway, we don't have to pass information from <a name="INDEX-2284" /> <a name="INDEX-2,285" />document to<a name="INDEX-2286" /><a name="INDEX-2287" /><a name="INDEX-2288" /><a name="INDEX-2289" />document.</p><hr align="left" width="515" /><div class="navbar"><table border="0" width="515"><tr><td width="172" valign="top" align="left"><a href="ch11_01.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0" /></a></td><td width="171" valign="top" align="center"><a href="index.htm"><img src="../gifs/txthome.gif" alt="Home" border="0" /></a></td><td width="172" valign="top" align="right"><a href="ch11_03.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0" /></a></td></tr><tr><td width="172" valign="top" align="left">11. Maintaining State</td><td width="171" valign="top" align="center"><a href="index/index.htm"><img src="../gifs/index.gif" alt="Book Index" border="0" /></a></td><td width="172" valign="top" align="right">11.3. Client-Side Cookies</td></tr></table></div><hr align="left" width="515" /><img src="../gifs/navbar.gif" alt="Library Navigation Links" usemap="#library-map" border="0" /><p><font size="-1"><a href="copyrght.htm">Copyright &copy; 2001</a> O'Reilly &amp; Associates. All rights reserved.</font></p><map name="library-map"><area href="../index.htm" coords="1,1,83,102" shape="rect" /><area href="../lnut/index.htm" coords="81,0,152,95" shape="rect" /><area href="../run/index.htm" coords="172,2,252,105" shape="rect" /><area href="../apache/index.htm" coords="238,2,334,95" shape="rect" /><area href="../sql/index.htm" coords="336,0,412,104" shape="rect" /><area href="../dbi/index.htm" coords="415,0,507,101" shape="rect" /><area href="../cgi/index.htm" coords="511,0,601,99" shape="rect" /></map></body></html>

⌨️ 快捷键说明

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