📄 ch11_03.htm
字号:
<p>If the <em class="emphasis">domain</em> parameter is not explicitly set,it defaults to the full, current domain, such as <em class="emphasis">www.oreilly.com</em>.</p></li><li><p><em class="emphasis">Expires</em> contains a timestamp in the followingformat:</p><blockquote><pre class="code">Wdy, DD-Mon-YY HH:MM:SS GMT</pre></blockquote><p>Fortunately, you don't have to worry about rememberingthis because CGI.pm allows you to specify the expiration date usingrelative values:</p><blockquote><pre class="code">-expires => "+1y" # 1 year from now-expires => "+6M" # 6 months from now-expires => "-1d" # yesterday (i.e., delete it)-expires => "+12h" # 12 hours from now-expires => "+30m" # 30 minutes from now-expires => "+15s" # 15 seconds from now-expires => "now" # now</pre></blockquote><p>Note that <tt class="literal">M</tt> is used for months and<tt class="literal">m</tt> is used for minutes. If a time is specifiedthat's in the past, the browser does not save the cookie anddeletes any previous cookies with the same name for the same domainand path.</p><p>If an expiration date is not specified, thenthe browser saves the cookie in memory until it exits.</p></li><li><p><em class="emphasis">Path</em>, like<em class="emphasis">domain</em>, controls when the browser should sendthe cookie to the server. It must be an absolute path, and it mustmatch the path of the request that sets the cookie. Paths are matchedfrom left to right, and any trailing / is removed from the<em class="emphasis">path</em> parameter, so <em class="emphasis">/cgi/</em> matches <em class="emphasis">/cgi/check_cart.cgi</em> as well as <em class="emphasis">/cgi-bin/calendar.cgi</em>.</p><p>If<em class="emphasis">path</em> is not specified, it defaults to the fullpath of the request that sets the cookie.</p></li><li><p><em class="emphasis">Secure</em> tells thebrowser that it should only return the cookies for future requests ifthey are via <em class="emphasis">https</em>.</p></li></ul> <p>Browsers distinguish between<a name="INDEX-2315" />cookies with the same name butdifferent domains and/or paths. Thus, it is possible for a browser tosend you multiple cookies with the same name. However, the browsershould send the most specific cookie first in its response. Forexample, if you set the following two cookies:</p><blockquote><pre class="code">my $c1 = $q->cookie( -name => "user", -value => "site_value", -path => "/" );my $c2 = $q->cookie( -name => "user", -value => "store_value", -path => "/cgi" );print $q->header( -type => "text/html", -cookie => [ $c1, $c2 ] );..</pre></blockquote><p>then on future requests, the browser should send you the following:</p><blockquote><pre class="code">Cookie: user=store_value; user=site_value</pre></blockquote><p>Unlike form parameters, CGI.pm will not return multiple values forcookies with the same name; instead, it will always return the firstvalue. The following:</p><blockquote><pre class="code">my $user = $q->cookie( "user" );</pre></blockquote><p>sets <tt class="literal">$user</tt> to "store_value". If youneed to get the second value, you will have to inspect the value ofthe HTTP_COOKIE environment variable (or CGI.pm's<tt class="function">raw_cookie</tt> method) yourself.</p><p>Of course, you would probably never set two cookies with the samename in the same script. However, it is quite possible for largesites that you end up with different applications each setting acookie that share the same name. Therefore, especially if your siteis on a domain that is shared with others, it is a good idea withcookies to choose a unique name for your cookies and to restrict thedomain and path as much as possible.</p><p>Browsers do not consider cookies with different values for<em class="emphasis">secure</em> distinct the way that cookies withdifferent domains and paths are distinct. Thus, you cannot set onevalue for <em class="emphasis">https</em> connections and another valuefor <em class="emphasis">http</em> connections to the same domain andpath; the second cookie will simply overwrite the first <a name="INDEX-2316" />cookie.</p></div><a name="ch11-2-fm2xml" /><div class="sect2"><h3 class="sect2">11.3.2. Testing for Cookies</h3><p>If a <a name="INDEX-2317" /><a name="INDEX-2318" />client does not accept cookies, it willnot tell you this; instead it just quietly discards them. Thus, aclient who does not accept cookies looks to your CGI scripts justlike a new client who has not received any cookies yet. It can be achallenge to tell them apart. Some sites do not put much effort intodistinguishing the two and simply add a notice that their siterequires cookies and may not work correctly without them. However, abetter solution is to test for cookie support via redirection.</p><p>Let's say you have an application at <em class="emphasis">http://www.oreilly.com/cgi/store/store.cgi</em>that requires cookies in order to track users' shopping carts.The first thing that this CGI script can do is check to see whetherthe client sent a cookie. If so, then the user is ready to shop.Otherwise, the CGI script needs to set a cookie first. If the CGIscript sets a cookie at the same time that it forwards the user toanother URL, such as <em class="emphasis">http://www.oreilly.com/cgi/store/check_cookies.cgi</em>,the second URL can test whether the cookie was in fact set properly.<a href="ch11_03.htm#ch11-33985">Example 11-4</a> provides the beginning of the main CGIscript.</p><a name="ch11-33985" /><div class="example"><h4 class="objtitle">Example 11-4. store.cgi </h4><a name="INDEX-2319" /><a name="INDEX-2,320" /><blockquote><pre class="code">#!/usr/bin/perl -wTuse strict;use CGI;my $q = new CGI;my $cart_id = $q->cookie( -name => "cart_id" ) || set_cookie( $q );# Script continues for users with cookies..sub set_cookie { my $q = shift; my $server = $q->server_name; my $cart_id = unique_id( ); my $cookie = $q->cookie( -name => "cart_id", -value => $cart_id, -path => "/cgi/store" ); print $q->redirect ( -url => "http://$server/cgi/store/cookie_test.cgi", -cookie => $cookie ); exit;}</pre></blockquote></div><p>If we cannot retrieve a cookie for <em class="emphasis">cart_id</em>, wecalculate a new unique id for the user and format it as a cookie forthe current session that is only visible within our store. The<tt class="function">unique_id</tt> subroutine is the same one used in<a href="ch11_01.htm#ch11-50116">Example 11-1</a> and <a href="ch11_02.htm#ch11-79018">Example 11-3</a>; weomit it here for brevity. We set the cookie and forward the user to asecond CGI script that will test the cookie for us.</p><p>There are a number of issues specifically related to<a name="INDEX-2321" /><a name="INDEX-2322" />setting cookies as part of a redirection:</p><ul><li><p>If the domain of the URL in your redirection is different than thedomain of your script, then you cannot set a cookie for the targetdomain. Browsers are expected to ignore cookies under thesecircumstances to ensure privacy.</p></li><li><p>The URL must use an absolute path; otherwise, the web server mayattempt to avoid another request and response cycle by simplyreturning the content for the new URL as the content of the initialresponse via an internal redirect.</p></li><li><p>The scope of the cookie must include both the CGI script setting thecookie as well as the CGI script testing whether the cookie is set.In our case, they are both below <em class="filename">/cgi/store,</em> sowe set our cookie's path to this.</p></li></ul><p><a href="ch11_03.htm#ch11-91838">Example 11-5</a> contains the source for<em class="filename">cookie_test.cgi</em><a name="INDEX-2323" /> <a name="INDEX-2,324" /> <a name="INDEX-2,325" />.</p><a name="ch11-91838" /><div class="example"><h4 class="objtitle">Example 11-5. cookie_test.cgi </h4><blockquote><pre class="code">#!/usr/bin/perl -wTuse strict;use CGI;use constant SOURCE_CGI => "/cgi/store/store.cgi";my $q = new CGI;my $cookie = $q->cookie( -name => "cart_id" );if ( defined $cookie ) { print $q->redirect( SOURCE_CGI );}else { print $q->header( -type => "text/html", -expires => "-1d" ), $q->start_html( "Cookies Disabled" ), $q->h1( "Cookies Disabled" ), $q->p( "Your browser is not accepting cookies. Please upgrade ", "to a newer browser or enable cookies in your preferences and", $q->a( { -href => SOURCE_CGI }, "return to the store" ), "." ), $q->end_html;}</pre></blockquote></div><p>This script is quite short. First we store the relative URL of thescript that we came from in a constant. We could pull this from<a name="INDEX-2326" />HTTP_REFERER, but not all browsers sendthe <em class="emphasis">Referer</em><a name="INDEX-2327" /> HTTP field; because of privacy concerns,some browsers allow the user to disable this field. The safealternative is to hardcode it into our script here.</p><p>We then create a new CGI.pm object and check for the cookie. If thecookie is set, we redirect the user back to the original CGI script,which will now see the new cookie and continue. If the cookie is notset, then we display a message telling the user the problem andproviding a link back to the original script to try again. Noticethat we disable caching for this page by passing an expired parameterto CGI.pm's<tt class="function">header</tt><a name="INDEX-2328" /><a name="INDEX-2329" /> method. This ensures that when theuser returns, the browser calls the script to test for cookies againinstead <a name="INDEX-2330" /><a name="INDEX-2331" />ofdisplaying <a name="INDEX-2332" /> <a name="INDEX-2,333" /> <a name="INDEX-2,334" />a cached copy of the error<a name="INDEX-2335" /> <a name="INDEX-2,336" /> <a name="INDEX-2,337" /> <a name="INDEX-2,338" />message.</p></div><hr align="left" width="515" /><div class="navbar"><table border="0" width="515"><tr><td width="172" valign="top" align="left"><a href="ch11_02.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="ch12_01.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0" /></a></td></tr><tr><td width="172" valign="top" align="left">11.2. Hidden Fields</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">12. Searching the Web Server</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 © 2001</a> O'Reilly & 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 + -