Phoenix.pm: Damn Cookies

Shay Harding mekla at geocities.com
Mon Aug 9 11:26:33 CDT 1999


I would definitely use CGI.pm not because anything it does is hard to
do otherwise, but because I'm lazy :)

I work with cookies almost on a daily basis and the header format is
the following:

print "Set-Cookie: _COOKIE_NAME_=_COOKIE_VALUE_; domain=_DOMAIN_;
path=/; expires=Thu, 12-Aug-1999 16:35:47 GMT\n";

Make sure when you end your headers you specify '\n\n' on the last
header. Also MSIE seems to need the 'Content-type' header sent
regardless of if you are going to output anything. An example would be:

print "Set-Cookie: _COOKIE_NAME_=_COOKIE_VALUE_; domain=_DOMAIN_;
path=/; expires=Thu, 12-Aug-1999 16:35:47 GMT\n";

print "Location:  http://www.server.com\n\n";

For some reason the above will not always work with MSIE. The cookie is
never set, but the redirect works fine? You have to specify:


print "Set-Cookie: _COOKIE_NAME_=_COOKIE_VALUE_; domain=_DOMAIN_;
path=/; expires=Thu, 12-Aug-1999 16:35:47 GMT\n";

print "Location:  http://www.server.com\n";
print "Content-type: text/html\n\n";


Good thing is this second method works with Netscape.

Anyway, it's just so much easier for us lazy people to use CGI.pm.
Thing I don't like about CGI.pm is it is very large and I only use the
header and param methods. So if this is all you use it for just do

use CGI qw(:cgi);

Also a good couple lines of code I always use to get at the form field
values is:

use CGI qw(:cgi);
$cgi = new CGI;

for ($cgi->param){
    ${$_} = $cgi->param($_);
}


or in keeping with your code below:

for ($cgi->param){
    $FORM{$_} = $cgi->param($_);
}

Basically when you loop through $cgi->param you are getting the field
names from the submitted form shoved into $_. The first method takes
these field names and creates variables out of them (${$_}) then
assigns the field value to the new variable. The second method does the
same but creates the hash %FORM to store the values. The second method
is safer and if you use strict will give you less errors as long as you
specify 'my %FORM = ()' at the beginning of your script somewhere.

OK, back to the cookies (sorry for the tangent)...

To get at the cookies use the method 'cookie':

if (!$cgi->cookie(COOKIE_NAME)){
    SET_COOKIE
}else{
    my $cookie_val = $cgi->cookie(COOKIE_NAME);

    do something with the cookie
}


A simple set_cookie sub would be:

sub set_cookie(){
    my $cookie = $cgi->cookie(-name=>COOKIE_NAME, -value=>VALUE,
-domain=>.domain.com, -expires=>'+3d');
    return $cookie;
}

For the 'expires' portion '+3d' means to expire 3 days from the date it
was set. I don't remember if there are codes for minutes, seconds,
hours, etc but I'm sure there are if you look in the man pages.

Looking at your code below, some of the above code will help you avoid
redundancy like shoving all the form values into %FORM only to set them
to the form field names anyway. I would use the CGI.pm module and be
lazy about it :)

Here's my version of your code with modifications:

#!/usr/bin/perl

use CGI qw(:cgi);
$cgi = new CGI;

for ($cgi->param){
    ${$_} = $cgi->param($_);
}

$phase = new unless $phase;
chomp($date = `date +"%Y%m%d %T"`);

&confirm if $phase eq "ordering"; 
&finished if $phase eq "confirmed"; 
 
# Set cookie 
 
$cookie = $cgi->cookie(-name=>'VISITOR'; -value=>$visitor;
-domain=>'.azfamily.com'; -path='/cgi-bin/glen/shop'; -expires=>'+3d');


print $cgi->header(-type=>'text/html', -cookie=>[$cookie]); 
 
&header; 
 
HTML_STUFF;
 
&footer; 
exit; 
 
REST_OF_SCRIPT...;




Sorry for the long and drawn out message but I love to talk about Perl
:)

The good thing with the above is that the cookie expire date is dynamic
so you don't have to worry about cookies being set with an expiration
date in the past (which I believe will delete a cookie). I did look and
CGI man pages and this is what it has for cookie expirations:

               +30s                              30 seconds from now
               +10m                              ten minutes from now
               +1h                               one hour from now
               -1d                               yesterday (i.e. "ASAP!")
               now                               immediately
               +3M                               in three months
               +10y                              in ten years time
               Thursday, 25-Apr-1999 00:40:33 GMT  at the indicated time & date




Shay




-------------------------------------------------------

>OK, I am going crazy. I have been trying all day to get a very easy
script
 >to work and it won't. The basic idea is just writing a cookie.
I have
 >tried it in the perlscript itself, and then, in desperation,
commented out
 >the perl cookie stuff and tried javascript. Everytime I
check the cookie
 >file, I get zilch. I try to call the cookie for the
info and I get the
 >name value, followed by a print
"Content-type:text/html\n\n";
 >
>I just want to make a damn cookie and add info to it. What am I doing
>wrong?
>
>
>Here is my kludge:
>
>#!/usr/bin/perl
>
>
>$method = $ENV{'REQUEST_METHOD'};
>
>if ($method eq "GET") {
>         $buffer = $ENV{'QUERY_STRING'};
>        }
>else {
>        read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
>        }
>
>@pairs = split(/&/, $buffer);
>
>foreach $pair (@pairs)
>{
>    ($name, $value) = split(/=/, $pair);
>    $value =~ tr/+/ /;
>    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
>
>     $FORM{$name} = $value;
>}
>
>
>$cookiestuff = $ENV{'HTTP_COOKIE'};
>
>$phase = $FORM{'phase'};
>$visitor = $FORM{'visitor'};
>$item = $FORM{'item'};
>
>$phase = "new" unless $phase;
>
>$expires = "Tuesday, 10-August-1999 06:55:00 GMT";
>
>$path = "/web/glen/shop";
>$cgipath = "/web/cgi-bin/glen/shop";
>$hostdomain = ".azfamily.com";
>$date = `date +"%Y%m%d %T"`;
>chomp $date;
>
>&confirm if ($phase eq "ordering");
>&finished if ($phase eq "confirmed");
>
>
># Set cookie
>
>print "Set-Cookie:VISITOR=$visitor; expires=$expires; path=$cgipath;
>domain=$hostdomain"||&error;
>#print "Set-Cookie:VISITOR=glen; path=/web/cgi-bin/glen/shop;
>domain=.azfamily.com"||&error;
>
>#print form
>
>print "Content-type:text/html\n\n";
>
>&header;
>
>
>print "<BR>$phase<BR>";
>
>print <<ORDERFORM;
>
><P><B>$date</B></P>
>
><P>
><BIG>Welcome to Sticky Widgets, Inc.</BIG><BR>
>Please enter your name and select the kind of widget you want:
></P>
>
><FORM ACTION="http://www.azfamily.com/cgi-bin/glen/shop/shoptest.pl"
>METHOD="post">
>
><INPUT TYPE="hidden" NAME="phase" VALUE="ordering">
>
><P>
>Name: <INPUT TYPE="text" NAME="visitor" SIZE="12" MAXLENGTH="24">
></P>
>
><P>
><INPUT TYPE="radio" NAME="item" VALUE="001">Widget Type 1<BR>
><INPUT TYPE="radio" NAME="item" VALUE="002">Widget Type 2<BR>
><INPUT TYPE="radio" NAME="item" VALUE="003">Widget Type 3<BR>
><INPUT TYPE="radio" NAME="item" VALUE="004">Widget Type 4<BR>
></P>
>
><P>
><INPUT TYPE="submit" VALUE="Submit this Form">
></P>
>
>
></FORM>
>
>ORDERFORM
>
>&footer;
>
>exit;
>
>
>###############
># subroutines #
>###############
>sub confirm{
>
># print "Set-Cookie:WIDGET=$item; VISITOR=$visitor\n";
>
>print "Content-type:text/html\n\n";
>print <<CONFIRM;
><HTML>
><HEAD>
>
><TITLE>Shop At Joe's</TITLE>
>
><SCRIPT LANGUAGE="JavaScript">
> document.cookie="VISITOR=glen; expires=Monday, 09-August-1999 06:55:00
>GMT; path=/web/cgi-bin/glen/shop; domain=.azfamily.com;
> </SCRIPT>
>
>
></HEAD>
>
><BODY TEXT="#000000" LINK="#003366" VLINK="#990000" ALINK="#FFFFFF"
>BGCOLOR="#FFFFFF">
>
><P>
><BIG>Yes, we got the order</BIG>
></P>
>
><P>
>You wanted to order a type $item Widget.
></P>
>
><FORM ACTION="http://www.azfamily.com/cgi-bin/glen/shop/shoptest.pl"
>METHOD="post">
>
><INPUT TYPE="hidden" NAME="phase" VALUE="confirmed">
>
><P>
><INPUT TYPE="submit" VALUE="Yes, this is my order.">
></P>
>
>
></FORM>
>
>
></BODY>
></HTML>
>
>CONFIRM
>exit;
>}
>
>sub finished{
>
># print "Set-Cookie: WIDGET=$item";
>
>print "Content-type:text/html\n\n";
>print <<FINISHED;
><HTML>
><HEAD>
>
><TITLE>Shop At Joe's</TITLE>
>
></HEAD>
>
><BODY TEXT="#000000" LINK="#003366" VLINK="#990000" ALINK="#FFFFFF"
>BGCOLOR="#FFFFFF">
>
><P>
>Finished. 
></P>
>
><P>
>$cookiestuff
></P>
>
><P>
>Thank you for your order. 
></P>
>
></BODY>
></HTML>
>
>FINISHED
>exit;
>}
>
>sub header{
>print <<HEADER;
><HTML>
><HEAD>
>
><TITLE>Shop At Joe's</TITLE>
>
></HEAD>
>
><BODY TEXT="#000000" LINK="#003366" VLINK="#990000" ALINK="#FFFFFF"
>BGCOLOR="#FFFFFF">
>
>HEADER
>}
>
>sub footer{
>
>print <<FOOTER;
>
></BODY>
></HTML>
>FOOTER
>}
>sub error{
>
>print "Content-type:text/html\n\n";
>print " Could not bake a cookie. :(";
>exit;
>
>}
>
>




More information about the Phoenix-pm mailing list