Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I've never written a CGI script that uses cookies before and I'm having trouble with my first attempt. I tested with Netscape and had Netscape ask me before accepting any cookies. Here's my setting code:
my $cookie = $cgi->cookie( -name=>'botLogin', -value=>"$username:$trueName:$Hash"); print $cgi->header(-cookie=>[$cookie,$cookie]),$cgi->start_html(-title +=>'Login');
Then I tried to retrieve the cookie using a variety of different methods:
#first method..this attempts to just get anything out there and sh +ow it to me print $cgi->h3("First cookie retrieval method..."); my %cookies = parse CGI::Cookie($ENV{COOKIE}); foreach (keys %cookies) { print $cgi->h2("START $_ => $cookies{$_}"); } print $cgi->h3("End first method."); #second method...like the first, doesn't look for a particular coo +kie print $cgi->h3("Second retrieval method..."); %cookies = fetch CGI::Cookie; foreach (keys %cookies) { print $cgi->h3("START $_ => $cookies{$_}"); } print $cgi->h3("End second method"); #this was my original method...tries to get only the cookie that I + set #then parses it's value to retrieve the data I wanted from it if(defined(my $cookieHolder = $cgi->cookie(-name=>'botLogin'))){ print $cgi->h3("Retrieved cookie named botLoginName: $cookieHo +lder"); } else{ print $cgi->h3("No cookie retrieved."); }
Using Netscape (version 4.77, or IE 5.5 for that matter), I ran the setting code. Sure enough, the browser asked me if I wanted to accept the cookie. The name and value were right. I accepted. Then I tried to retrieve it--no dice. Eventually I discovered that I had to run the setting script twice in a row before I was able to retreive the cookies. What am I doing wrong? Why aren't my cookies taking the first time?

Replies are listed 'Best First'.
Re: Cookies Not Getting Set First Time
by buck_mulligan (Novice) on Jul 12, 2001 at 10:01 UTC
    I'm not the most experienced with HTTP/CGI so someone correct me if I'm wrong (please!), but I'm thinking that this could be due to the timing here if the second snippet you included is in the same script as the first.

    My logic is thus: setting a cookie is just including a header line with the desired contents of the cookie to the client. However, since the clients' cookies are sent upon request of a page (and before the http header returned by the server), it wouldn't be available upon the first execution of the script. That would explain why you have to try twice before successfully fetching it - once to set the cookie, and once again to retrieve it.

    If this is truly the problem, there's really no recourse to having to call the thing twice, whether it's with the cookie-setting and the cookie-fetching being in the same script or different scripts. Or if you can find a way to travel faster than light you can bypass the causality constraints.

    If you manage to do the latter with Perl, make sure you post it to CUFP...

Re: Cookies Not Getting Set First Time
by cLive ;-) (Prior) on Jul 12, 2001 at 20:23 UTC

    If you are reading it in the same script that you set it in (and on that run - it will be available if the script is called again), it will not contain the cookie you set.

    Nothing wrong with your initial method of retrieval, as far as i can see.

    Look at your cookie header code. any reason why you are setting $cookie twice? See docs - looks like you mis-copied their example that set two cookies.

    But in answer to *why* it's not there, you need to look at the cgi.pm module itself. When retrieving cookies, cgi calls CGI::Cookie->fetch, when setting, it returns a cookie object created by CGI::Cookie(@param).

    Don't make the mistake of thinking of the $cgi->cookie call as being an object - it's a method, context depending on how it's called.

    If you wanted it to work as you expect, you'd need to fix things a little. I suggest you create a %cookie hash and add name value pairs to it and then use an array to send to CGI. EG,

    #!/usr/bin/perl use strict; use CGI; use CGI::Carp 'fatalsToBrowser'; my $cgi = new CGI; # grab existing %cookie my %cookie; for ($cgi->cookie()) { $cookie{$_} = $cgi->cookie($_); } # set a couple of cookies; $cookie{'botLoginName'} = "XXXXX:YYYYY:ZZZZZ"; $cookie{'Other_cookie'} = 'whatever'; # create cookies for CGI my @cookies; for (keys %cookie) { push @cookies, $cgi->cookie( -name => $_, -value => $cookie{$_} ); } # print amended header print $cgi->header(-cookie=>[@cookies]),$cgi->start_html(-title=>'Logi +n'); # use our hash to check "cookie" if(defined(my $cookieHolder = $cookie{'botLoginName'})){ print $cgi->h3("Retrieved cookie named botLoginName: $cookieHo +lder"); } else{ print $cgi->h3("No cookie retrieved."); } # display all stored print $cgi->h4('Stored Cookies'); for (keys %cookie) { print "$_ = $cookie{$_}".$cgi->br; }

    But, having said that, it's probably better to write your code so that on first run (or run where username is sent) that you just check the param() rather than cookie()

    HTH

    cLive ;-)

Re: Cookies Not Getting Set First Time
by BMaximus (Chaplain) on Jul 12, 2001 at 11:08 UTC
    Your not seting the -domain=> It's not set automaticaly.

    Update: My bad. It is set automaticaly. Terrible. I must be tired today.

    I'm not sure if your just checking or the presence of the cookie object but you need to use $cookie{$_}->value if you want the value of the cookie.

    Try just printing out the keys of the cookies you do receive. If you don't get any try setting the domain to be generic like .domain.com instead of a full one.

    Also, why are you setting two?

    BMaximus

    Update (again): Cowards abound on the board again. A -1 for me and not a reason why nor a correction. Don't vote down if you can't post an answer.
      Ah. Looks like I'm not getting enough sleep either. Allow me to clear up a couple of things about the code I posted for the benefit of everyone trying (very kindly!) to help me out.

      First, the reason that I was setting two cookies (actually, the same cookie twice) was that after things didn't work, I was hoping that maybe if I just set the cookie twice I could having to run the whole script twice. I meant to change it back to just a single cookie before I posted the code, but obviously, I forgot. =)

      Secondly, the setting code and the fetching code were indeed run in seperate scripts, which were run several seconds apart...i.e. I ran the setting code, took a moment to look at some output, then typed the URL for the fetching script and ran it. So the problem isn't a timing issue. Good call though, to those who suggested that might be it

      After working on the code a little more, I found a solution: the setting code works fine the first time IF I don't use CGI::Cookie. Instead I just do:
      print"Set-Cookie: botLogin=$username:$trueName:$Hash\n"; print "Content-Type: text/html\n\n";
      Instead of:
      my $cookie = $cgi->cookie( -name=>'botLogin', -value=>"$username:$trueName:$Hash"); print $cgi->header(-cookie=>[$cookie,$cookie]), $cgi->start_html(-title=>'Login');
      Try as I might, I could never get it to work on the first run using CGI::Cookie. Any thoughts on why?