Syntax of the Set-Cookie HTTP Response Header:
Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME;
secure
In addition to the required name=value pair, each cookie has several optional attributes:
an expiration time
This is a time/date string (in a special GMT format)
that indicates when a cookie expires. The
cookie will be saved and returned to your script
until this expiration date is reached if the user
exits Netscape and restarts it. If an expiration
date isn't specified, the cookie will remain active
until the user quits Netscape.
Negative expiration times (e.g. "-1d") cause some
browsers to delete the cookie from its persistent
store. This is a poorly documented feature.
a domain
This is a partial or complete domain name for which
the cookie is valid. The browser will return
the cookie to any host that matches the partial
domain name. For example, if you specify a domain
name of ".capricorn.com", then Netscape will return
the cookie to Web servers running on any of
the machines "www.capricorn.com", "www2.capricorn.com",
"feckless.capricorn.com", etc.
Domain names must contain at least two periods to
prevent attempts to match on top level domains
like ".edu". If no domain is specified, then the
browser will only return the cookie to servers on the
host the cookie originated from.
a path
If you provide a cookie path attribute, the browser
will check it against your script's URL before
returning the cookie. For example, if you specify
the path "/cgi-bin", then the cookie will be
returned to each of the scripts "/cgi-bin/tally.pl",
"/cgi-bin/order.pl", and
"/cgi-bin/customer_service/complain.pl", but not
to the script "/cgi-private/site_admin.pl". By
default, path is set to "/", which causes the cookie
to be sent to any CGI script on your site.
a "secure" flag
If the "secure" attribute is set, the cookie will
only be sent to your script if the CGI request is
occurring on a secure channel, such as SSL.
Syntax of the Cookie HTTP Request Header:
Cookie: NAME1=OPAQUE_STRING1; NAME2=OPAQUE_STRING2 ...
Here is an example of cookie file:
# Netscape HTTP Cookie File # http://www.netscape.com/newsref/std/cookie_spec.html # This is a generated file! Do not edit. .imgis.com TRUE / FALSE 1043584626 JEB2 -1029749540| .excite.com TRUE / FALSE 946642835 registered no .excite.com TRUE / FALSE 946642835 UID F994E3D134CDD638 www.bcc.com.tw FALSE / FALSE 1293754727 EGSOFT_ID 128.198.11.144-1825492944.29174561 .looksmart.com TRUE / FALSE 1202199509 LookSmartPIN 149a086373a987245f1 .doubleclick.net TRUE / FALSE 1920499140 id 18d6785c .yahoo.com TRUE / FALSE 915146472 Y v=1&n=dn9gkdn14uiki .netscape.com TRUE / FALSE 946686067 NETSCAPE_ID 10010408,11a1a3e7 home.netscape.com FALSE / FALSE 942190438 NGUserID cfc84d28-8663-886990942-3 cgi2.fxweb.com FALSE FALSE 915155700 H87664-00VISIT 2
.altavista.com TRUE / FALSE 1260362602 AV_PARM aves=1&poa=netspp .engage.com TRUE / FALSE 1283963823 CyberGlobalAnonymous CTG00068F1615AF09B91FCA0721CD8B1DB4 .netscape.com TRUE / FALSE 1293839340 HITO_VISITS AEE147D53+1755E3*E6E49*2 .linkexchange.com TRUE / FALSE 1126668201 LE_COOKIE 1.2a.433dc7a7997675a7c371509a73295d537d9a71f5508760e2afce6abc19219a8b729616127a7097fddc4452ce6496d647adaafa86ef4bfe07 .industry.net TRUE / FALSE 2051222400 SITESERVER ID=020217fda9c04b85e8c8e455b18a85ef .techsavvy.com TRUE / FALSE 2051222535 SITESERVER ID=c17788c508268c97433912293ab0d26c www.techsavvy.com FALSE / FALSE 2137622535 CFID 151106 www.techsavvy.com FALSE / FALSE 2137622535 CFTOKEN 42825407 .sun.com TRUE / FALSE 973103239 sun_visitor_uid 3336353737383032385e30 .looksmart.com TRUE / FALSE 1284576790 LookSmartPIN 000917x29c005742b8243a77d1,isp=US,Ped .earthlink.net TRUE / FALSE 1056321312 Am_UserId 39cfd2332c9043ec2 .ads.link4ads.com TRUE / FALSE 1032993148 247CID sid-a8c00e0b-969921148x1f47e.2830 sales-bilbo.uccs.edu:8088 FALSE / FALSE 971373223 Apache 128.198.166.1.19790970163831468
Trying 128.198.8.231... Connected to vinci.uccs.edu. Escape character is '^]'. GET / HTTP/1.0 HTTP/1.1 200 OK Date: Sat, 14 Feb 1998 07:23:13 GMT Server: Apache/1.2.5 Set-Cookie: Apache=viva1801887440994503; path=/ Last-Modified: Fri, 13 Feb 1998 22:20:03 GMT ETag: "2caf-c9-34e4c713" Content-Length: 201 Accept-Ranges: bytes Connection: close Content-Type: text/html...
What is your reply ("$" to break connection)?
bash$ /mpc/home/chow/src/auth
Z3Vlc3Q6Z2FuZDAwYWxm
decoded=guest:gand00alf
- "GET / HTTP/1.0" [13/Feb/1998:23:06:44 -0700] - "GET /form_summer.html HTTP/1.0" [13/Feb/1998:23:06:50 -0700] - "POST /cgi-bin/mycgi HTTP/1.0" [13/Feb/1998:23:07:22 -0700] - "GET / HTTP/1.0" [13/Feb/1998:23:08:06 -0700] - "GET / HTTP/1.0" [13/Feb/1998:23:08:40 -0700] - "GET / HTTP/1.0" [13/Feb/1998:23:09:17 -0700] - "GET /info HTTP/1.0" [13/Feb/1998:23:30:57 -0700] annexp71796887440130910 "GET /info HTTP/1.0" [14/Feb/1998:00:08:50 -0700] annexp71796887440130910 "GET / HTTP/1.0" [14/Feb/1998:00:10:23 -0700] annexp71796887440130910 "GET /form_summer.html HTTP/1.0" [14/Feb/1998:00:10:27 -0700] annexp71796887440130910 "GET /bath.jpg HTTP/1.0" [14/Feb/1998:00:10:28 -0700] annexp71796887440130910 "GET /bench.jpg HTTP/1.0" [14/Feb/1998:00:10:28 -0700] annexp71796887440130910 "GET /hen.jpg HTTP/1.0" [14/Feb/1998:00:10:28 -0700] annexp71796887440130910 "GET /tree.jpg HTTP/1.0" [14/Feb/1998:00:10:28 -0700] - "GET / HTTP/1.0" [14/Feb/1998:00:10:52 -0700] - "GET / HTTP/1.0" [14/Feb/1998:00:11:06 -0700] viva1796887440480793 "GET / HTTP/1.0" [14/Feb/1998:00:14:40 -0700] viva1799887440487890 "GET /form_summer.html HTTP/1.0" [14/Feb/1998:00:14:47 -0700] viva1797887440563871 "GET / HTTP/1.0" [14/Feb/1998:00:16:03 -0700] viva1800887440569772 "GET /form_summer.html HTTP/1.0" [14/Feb/1998:00:16:09 -0700] annexp71796887440130910 "GET /bench.jpg HTTP/1.0" [14/Feb/1998:00:16:39 -0700] annexp71796887440130910 "GET /hen.jpg HTTP/1.0" [14/Feb/1998:00:16:40 -0700] annexp71796887440130910 "GET /tree.jpg HTTP/1.0" [14/Feb/1998:00:16:40 -0700] annexp71796887440130910 "GET /bath.jpg HTTP/1.0" [14/Feb/1998:00:16:40 -0700]
- "GET / HTTP/1.0" [26/Sep/2000:16:43:37 -0600] - "GET / HTTP/1.0" [26/Sep/2000:16:43:43 -0600] - "GET / HTTP/1.0" [28/Sep/2000:11:57:05 -0600] 128.198.166.1.19790970163831468 "GET / HTTP/1.0" [28/Sep/2000:11:57:11 -0600] 128.198.166.1.19790970163831468 "GET /form_summer_sales.html HTTP/1.0" [28/Sep/2 000:11:57:13 -0600] 128.198.166.1.19790970163831468 "GET /bath.jpg HTTP/1.0" [28/Sep/2000:11:57:13 - 0600] 128.198.166.1.19790970163831468 "GET /bench.jpg HTTP/1.0" [28/Sep/2000:11:57:14 -0600] 128.198.166.1.19790970163831468 "GET /hen.jpg HTTP/1.0" [28/Sep/2000:11:57:14 -0
A cookie is a name=value pair much like the named parameters in a CGI
query string. CGI scripts create
one or more cookies and send them to the browser in the HTTP header.
The browser maintains a list of
cookies that belong to a particular Web server, and returns them to
the CGI script during subsequent
interactions.
The interface to Netscape cookies is the cookie() method:
$cookie = $query->cookie(-name=>'sessionID',
-value=>'xyzzy',
-expires=>'+1h',
-path=>'/cgi-bin/database',
-domain=>'.capricorn.org',
-secure=>1);
print $query->header(-cookie=>$cookie);
cookie() creates a new cookie. Its parameters include:
-name
The name of the cookie (required). This can be any
string at all. Although Netscape limits its
cookie names to non-whitespace alphanumeric characters,
CGI.pm removes this restriction by
escaping and unescaping cookies behind the scenes.
-value
The value of the cookie. This can be any scalar
value, array reference, or even associative array
reference. For example, you can store an entire
associative array into a cookie this way:
$cookie=$query->cookie(-name=>'family
information',
-value=>\%childrens_ages);
-path
The optional partial path for which this cookie
will be valid, as described above.
-domain
The optional partial domain for which this cookie
will be valid, as described above.
-expires
The optional expiration date for this cookie. The
format is as described in the section on the
header() method:
"+1h" one hour from now
-secure
If set to true, this cookie will only be used within
a secure SSL session.
The cookie created by cookie() must be incorporated into the HTTP header
within the string returned by
the header() method:
print $query->header(-cookie=>$my_cookie);
To create multiple cookies, give header() an array reference:
$cookie1 = $query->cookie(-name=>'riddle_name',
-value=>"The Sphynx's Question");
$cookie2 = $query->cookie(-name=>'answers',
-value=>\%answers);
print $query->header(-cookie=>[$cookie1,$cookie2]);
To retrieve a cookie, request it by name by calling cookie() method without the -value parameter:
use CGI;
$query = new CGI;
%answers = $query->cookie('answers');
# $query->cookie(-name=>'answers')
works too!
To retrieve the names of all cookies passed to your script, call cookie()
without any parameters. This
allows you to iterate through all cookies:
foreach $name ($query->cookie())
{
print $query->cookie($name);
}
The cookie and CGI namespaces are separate. If you have a parameter
named 'answers' and a cookie
named 'answers', the values retrieved by param() and cookie() are independent
of each other. However,
it's simple to turn a CGI parameter into a cookie, and vice-versa:
# turn a CGI parameter into a cookie
$c=$q->cookie(-name=>'answers',-value=>[$q->param('answers')]);
# vice-versa
$q->param(-name=>'answers',-value=>[$q->cookie('answers')]);
See the cookie.cgi example script for some ideas on how to use cookies effectively.
NOTE: There appear to be some (undocumented) restrictions on Netscape
cookies. In Netscape 2.01, at
least, I haven't been able to set more than three cookies at a time.
There may also be limits on the length
of cookies. If you need to store a lot of information, it's probably
better to create a unique session ID,
store it in a cookie, and use the session ID to locate an external
file/database saved on the server's side
of the connection.
use CGI qw(:standard);
@cookies=sort qw/peanut mint chocolate butter mm/;
# Recover the previous cookie order from the magic cookie.
# The cookie has been formatted as an associative array
# mapping cookie name to the number of cookies package ordered.
%orders = cookie('cookie_order');
$ID = cookie('ID');
#if there is no unique ID create one
if (length($ID) eq 0) {
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)
= localtime(time);
$ID = "CS401_$year\_$mon\_$mday:$hour:$min:$sec";
}
# Recover the new order(s) from the parameter 'new_animal'
@neworder = param;
foreach $na (@neworder) {
$val = param($na);
$orders{$na} = $val;
}
# Put them in a cookie
$the_cookie = cookie(-name=>'cookie_order',
-value=>\%orders,
-expires=>'+1h');
$cookie2 = cookie(-name=>'ID',
-value=>$ID,
-expires=>'+3333h');
# Print the header, incorporating the cookie and the expiration date...
print header(-cookie=>[$the_cookie,$cookie2]);
# Now we're ready to create our HTML page.
print start_html('cookie order'),
h1('Cookie Order'),
"Your ID = $ID<BR>",
"Enter the number of boxs for each cookie
you like to order",
hr,
start_form("POST", "/cgi-bin/op.pl");
print "previous order<br>";
foreach $key (keys %orders) {
print "$key=$orders{$key}<br>";
}
print "<table BORDER=2>";
print "<tr><td><b>Cookie</b></td><td><b># of Boxes</b></td></tr>";
foreach $cookie (@cookies) {
print "<tr><td>$cookie</td><td
align=right>",
textfield(-name=>"$cookie",
-default=>"$orders{$cookie}",
-size=>10),
"</td></tr>";
}
print "</table>";
print submit(-name=>"action", -value=>"Order");
print reset;
end_form;
print end_html;
use CGI qw(:standard);
@cookies=sort qw/peanut mint chocolate butter mm/;
# Recover the previous cookie order from the magic cookie.
# The cookie has been formatted as an associative array
# mapping cookie name to the number of cookies package ordered.
%orders = cookie('cookie_order');
$ID = cookie('ID');
#if there is no unique ID create one
if (length($ID) eq 0) {
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)
= localtime(time);
$ID = "CS401_$year\_$mon\_$mday:$hour:$min:$sec";
}
# Recover the new order(s) from the parameter
@neworder = param;
foreach $na (@neworder) {
$val = param($na);
$orders{$na} = $val;
}
# Put them in a cookie
# Print the header, incorporating the cookie and the expiration date...
$the_cookie = cookie(-name=>'cookie_order',
-value=>\%orders,
-expires=>'+1h');
$cookie2 = cookie(-name=>'ID',
-value=>$ID,
-expires=>'+3333h');
# Print the header, incorporating the cookie and the expiration date...
print header(-cookie=>[$the_cookie,$cookie2]);
# Now we're ready to create our HTML page.
print header('text/html');
print start_html('cookie order'),
h1('Cookie Order'),
"Order# = $ID<BR>",
"Please confirm the order",
hr;
print "previous order<br>";
foreach $key (keys %orders) {
print "$key=$orders{$key}<br>";
}
print start_form("POST", "/cgi-bin/cp.pl");
print "Order#=$ID<br>";
print "<table BORDER=2>";
print "<tr><td><b>Cookie</b></td><td><b># of boxes</b></td></tr>";
foreach $cookie (@cookies) {
print "<tr><td>$cookie</td><td
align=right>$orders{$cookie}</td></tr>";
}
print "</table>";
print submit(-name=>"action", -value=>"confirm");
print submit(-name=>"action", -value=>"cancel");
end_form;
print end_html;
use CGI qw(:standard);
@cookies=sort qw/peanut mint chocolate butter mm/;
# Recover the previous cookie order from the magic cookie.
# The cookie has been formatted as an associative array
# mapping cookie name to the number of cookies package ordered.
%orders = cookie('cookie_order');
$ID = cookie('ID');
#if there is no unique ID create one
if (length($ID) eq 0) {
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)
= localtime(time);
$ID = "CS401_$year\_$mon\_$mday:$hour:$min:$sec";
}
print header('text/html');
print start_html('cookie order');
print "The following order has been ";
if (param('action') eq 'cancel') {
print "canceled. Please
press the button for start another order.<BR>";
} else {
print "confirmed and processed.
You should receive the cookie at the end
of March. Thanks.<BR>";
}
print hr,
start_form("POST", "oc.pl");
print "Order#=$ID<br>";
print "<table BORDER=2>";
print "<tr><td><b>Cookie</b></td><td><b># of boxes</b></td></tr>";
foreach $cookie (@cookies) {
print "<tr><td>$cookie</td><td
align=right>$orders{$cookie}</td></tr>";
}
print "</table>", hr;
print submit(-name=>"action", -value=>"Start Another
Order");
end_form;
print end_html;