new CGI::Session creates a new session every visit. GRRR!!!

T

TonyV

I've been beating myself up over this one for a few days. If anyone
can help me out, I'd greatly appreciate it.

I'm running Windows Server 2003 with ActiveState Perl. The perl -v
command gives me this:

This is perl, v5.8.8 built for MSWin32-x86-multi-thread
....
Binary build 820 [274739] provided by ActiveState http://www.ActiveState.com
Built Jan 23 2007 15:57:46

I downloaded CGI-Session-3.95.zip from ppm.activestate.com and
installed it by running ppm install CGI-Session.ppd. The server is
IIS v6.0, and the local IIS user account has read/write access to my
sessions directory.

I'm trying to do something that I think should be stupidly simple:
Save a variable to a session and retrieve it. What's happening,
though, is that every time I visit the page, it's creating a new
session. Even simply refreshing the page creates a new session.

Here's my code, which I tried to boil down to a very simplified case.
----------------------------------------
use strict;
use CGI::Session;
use CGI;

my $cgi = new CGI;
my $session = new CGI::Session(undef, undef, {Directory=>'/websessions/
test'}) or die CGI::Session->errstr;
my $cookie = $cgi->cookie(CGISESSID => $session->id );

# Print the cookie header with the session ID in it.
print $cgi->header(-cookie => $cookie);

print $cgi->start_html(-title=>'Test Page');


# See if first_name is defined as a query parameter. If it is,
# set the first_name session parameter.
my $name = $cgi->param('first_name');
if (defined $name and $name ne '')
{ $session->param('first_name', $name); }

# If it's not, try getting it from the first_name session
# parameter.
else
{ $name = $session->param('first_name'); }

# If it's not in the query parameters or the session parameters,
# set it to a default.
if (!defined $name or $name eq '')
{
$name = 'stranger';
$session->param('first_name', $name);
}

# Greet the user.
print $cgi->h1("Hello, $name!");
print $cgi->end_html;
----------------------------------------

Like I said, when I load the page, a new session file is created in
the /websessions/test directory. If I hit the refresh key, a new
session is created. If I tag on a ?first_name=Foomonkey, I get
greeted with Hello, Foomonkey!, and a new session is created. Then if
I take it back off, yet another new session is created.

I do have cookies enabled in my browser, I've tried it with the same
result from Firefox and IE. The following is returned by my server in
the header Although, of course, the date and the CGISESSID are
different with each page load. The date should be. The CGISESSID
shouldn't be. >:-(

Set-Cookie: CGISESSID=3b2b11be7bf4de7d79a828c8389eb413; path=/
Date: Thu, 15 Mar 2007 22:14:01 GMT
Content-Type: text/html; charset=ISO-8859-1


I'm at my wit's end. Am I doing something stupid wrong in the code?
Does anyone know of any issues with my setup? (IIS 6.0 on Windows
Server 2003, ActiveState Perl 5.8.8, build 820, CGI-session 3.95.)
 
M

Mumia W.

I've been beating myself up over this one for a few days. If anyone
can help me out, I'd greatly appreciate it.

I'm running Windows Server 2003 with ActiveState Perl. The perl -v
command gives me this:

This is perl, v5.8.8 built for MSWin32-x86-multi-thread
....
Binary build 820 [274739] provided by ActiveState http://www.ActiveState.com
Built Jan 23 2007 15:57:46

I downloaded CGI-Session-3.95.zip from ppm.activestate.com and
installed it by running ppm install CGI-Session.ppd. The server is
IIS v6.0, and the local IIS user account has read/write access to my
sessions directory.

I'm trying to do something that I think should be stupidly simple:
Save a variable to a session and retrieve it. What's happening,
though, is that every time I visit the page, it's creating a new
session. Even simply refreshing the page creates a new session.

Here's my code, which I tried to boil down to a very simplified case.
----------------------------------------
use strict;
use CGI::Session;
use CGI;

my $cgi = new CGI;
my $session = new CGI::Session(undef, undef, {Directory=>'/websessions/
test'}) or die CGI::Session->errstr; [...]

This is from CGI::Session::Tutorial:
The second argument is session id to be initialized. If it's undef, it
will force CGI::Session to create a new session. Instead of passing a
session id, you can also pass a CGI.pm object, or any other object that
can implement either of cookie() or param() methods.

Your program will work properly if you make the change suggested above.
 
X

xhoster

Mumia W. said:
This is from CGI::Session::Tutorial:

While I'll be. That will teach me not to read the perldocs for my
locally installed version rather than the version the OP was talking about.

Version 4.x releases act quite differently, and of course are documented
differently.

Xho
 
T

TonyV

This is from CGI::Session::Tutorial:


Your program will work properly if you make the change suggested above.

I just tried this. I now have the following lines in my program:

my $cgi = new CGI;
my $session = new CGI::Session(undef, $cgi, {Directory=>'/websessions/
test'}) or die CGI::Session->errstr;
my $cookie = $cgi->cookie(CGISESSID => $session->id );

It does exactly the same thing: creates a new session every time the
page is loaded. >:-( I suppose I could try loading the cookie before
calling Session->new to try to get an existing session ID, but it's my
understanding that this is not only not required, but way too much
work. According to the CGI::Session::Tutorial:

"We didn't check for any session cookies [in the example] above, did
we? No, we didn't, but CGI::Session did. It looked for a cookie called
CGISESSID, and if it found it tried to load existing session from
server side storage (file in our case)." In *my* case, something is
broken, because although the cookie *is* being created and I've
verified that its name *is* CGISESSID, for some weird reason,
CGI::Session isn't reading it.

Any other ideas? It's still driving me crazy.
 
M

Mumia W.

While I'll be. That will teach me not to read the perldocs for my
locally installed version rather than the version the OP was talking about.

Version 4.x releases act quite differently, and of course are documented
differently.

Xho

I'm lucky I have CGI::Session 3.95 installed through my OS's package
installation utilities. The CGI::Session 4.20 seems to be a lot smarter;
it can get the session cookie without consulting a CGI.pm object. The
OP's code would probably work without modification with 4.20.
 
T

TonyV

I suppose I could try loading the cookie before
calling Session->new to try to get an existing session ID, but it's my
understanding that this is not only not required, but way too much
work.

Okay, I see what you mean about the differences between CGI-
Session-3.95 and CGI-Session-4.20. It looks like the 3.95 versions
*doesn't* check your cookies for a session ID, and that passing it a
CGI *won't* work. I've changed my code to the following, and it seems
to work a lot better:

my $sessid = $cgi->cookie('CGISESSID');
my $session = new CGI::Session(undef, $sessid, {Directory=>'/
websessions/test'}) or die CGI::Session->errstr;
my $cookie = $cgi->cookie('CGISESSID'=>$session->id());

Unfortunately, it looks like there isn't a CGI-Session-4.20 available
for Windows, at least not from ActiveState. :-( Oh well, at any
rate, in case anyone else finds this thread through your favorite
search engine *here* are the documents you should be looking at:
http://search.cpan.org/~sherzodr/CGI-Session-3.95/

Here are the ones you *shouldn't* be looking at:
http://search.cpan.org/~markstos/CGI-Session-4.20/
 
M

Mumia W.

I just tried this. I now have the following lines in my program:

my $cgi = new CGI;
my $session = new CGI::Session(undef, $cgi, {Directory=>'/websessions/
test'}) or die CGI::Session->errstr;
my $cookie = $cgi->cookie(CGISESSID => $session->id );

It does exactly the same thing: creates a new session every time the
page is loaded. >:-( [...]

Any other ideas? It's still driving me crazy.

I tried your original code with one modification: the one suggested in
CGI::Session::Tutorial, and it worked. It only created one session even
though I hit Reload several times in Firefox.

Here is a simpler script that works on my system:


use strict;
use warnings;
use CGI::Session;
use CGI;

my $cgi = new CGI;
my $session = new CGI::Session (undef, $cgi,
{ Directory => '/tmp/websessions' });

my $name = $session->param('name') || $cgi->param('first_name');
$session->param('name',$name) if ($name);

print $cgi->header(
'-content-type' => 'text/html',
-expires => '+20s'
);

print $cgi->start_html('CGI::Session Test Page'),
$cgi->h1("Hello user: $name"),
$cgi->end_html;

__END__

The script does not consider "0" to be a valid name :) , but I think it
demonstrates the technique simply.

I'm using this:
Debian 3.1
CGI 3.04
CGI::Session 3.95
 
T

TonyV

First of all, thanks for all of your replies.

Second of all, I'm not crazy, and I'm still experiencing problems. My
tests worked, but when I went back to my original program and made
changes, it was still doing the same thing, creating a new session on
every load.

After some more poking and LOTS of commenting out my original code,
slowly making it into my test case, I narrowed down the problem, and
it seems to be something screwy with a combination of DBI and global
variables. Weird, huh? Let me explain.

If I take Mumia W.'s code above and tweak it with my websessions
directory and the addition of the cookie, I get this:

------------------------------------------------------------
use strict;
use warnings;
use CGI;
use CGI::Session;

my $cgi = new CGI;
my $session = new CGI::Session (undef, $cgi,
{ Directory => '/websessions/test' });

my $name = $cgi->param('name') || $session->param('name');
$session->param('name',$name) if ($name);

my $cookie = $cgi->cookie(CGISESSID => $session->id);

print $cgi->header(
'-content-type' => 'text/html',
-expires => '+20s',
-cookie=> $cgi->cookie(CGISESSID=>$session->id)
);

print $cgi->start_html('CGI::Session Test Page'),
$cgi->h1("Hello user: $name"),
$cgi->end_html;
------------------------------------------------------------

This works like a charm. However, I need database functionality, so I
add DBI so that my use section looks like this:

use strict;
use warnings;
use CGI;
use CGI::Session;
use DBI;

So far, so good, and everything still works fine. So now, I want to
make my program a little more modular, so I put a lot of that stuff
into a Main function. I want my $cgi and $session variables to be
global, though. So now my program looks like this:

------------------------------------------------------------
use strict;
use warnings;
use CGI;
use CGI::Session;
use DBI;

my $cgi;
my $session;

Main();

sub Main
{
$cgi = new CGI;
$session = new CGI::Session (undef, $cgi,
{ Directory => '/websessions/test' });

my $name = $cgi->param('name') || $session->param('name');
$session->param('name',$name) if ($name);

my $cookie = $cgi->cookie(CGISESSID => $session->id);

print $cgi->header(
'-content-type' => 'text/html',
-expires => '+20s',
-cookie=> $cgi->cookie(CGISESSID=>$session->id)
);

print $cgi->start_html('CGI::Session Test Page'),
$cgi->h1("Hello user: $name"),
$cgi->end_html;
}
------------------------------------------------------------

BOOM!!! Now, it starts creating session after session after session.
If I remove the use DBI, everything works fine again. If I remove the
global $cgi and $session variables and make them local within Main
instead, everything works fine. I even thought that maybe DBI had
some kind of global variables that conflict with $cgi and/or $session,
so I renamed them to $zxcvb and $asdfg, but it still creates new
sessions only. Even if I specifically *tell* it the session ID, it
*still* creates new sessions only.

Am I doing something syntactically wrong, or is this a genuine bug?
 
M

Mumia W.

First of all, thanks for all of your replies.

Second of all, I'm not crazy, and I'm still experiencing problems. My
tests worked, but when I went back to my original program and made
changes, it was still doing the same thing, creating a new session on
every load.

After some more poking and LOTS of commenting out my original code,
slowly making it into my test case, I narrowed down the problem, and
it seems to be something screwy with a combination of DBI and global
variables. Weird, huh? Let me explain.

If I take Mumia W.'s code above and tweak it with my websessions
directory and the addition of the cookie, I get this:

------------------------------------------------------------
use strict;
use warnings;
use CGI;
use CGI::Session;

my $cgi = new CGI;
my $session = new CGI::Session (undef, $cgi,
{ Directory => '/websessions/test' });

my $name = $cgi->param('name') || $session->param('name');
$session->param('name',$name) if ($name);

my $cookie = $cgi->cookie(CGISESSID => $session->id);

print $cgi->header(
'-content-type' => 'text/html',
-expires => '+20s',
-cookie=> $cgi->cookie(CGISESSID=>$session->id)
);

print $cgi->start_html('CGI::Session Test Page'),
$cgi->h1("Hello user: $name"),
$cgi->end_html;
------------------------------------------------------------

This works like a charm. However, I need database functionality, so I
add DBI so that my use section looks like this:

use strict;
use warnings;
use CGI;
use CGI::Session;
use DBI;

So far, so good, and everything still works fine. So now, I want to
make my program a little more modular, so I put a lot of that stuff
into a Main function. I want my $cgi and $session variables to be
global, though. So now my program looks like this:

------------------------------------------------------------
use strict;
use warnings;
use CGI;
use CGI::Session;
use DBI;

my $cgi;
my $session;

Main();

sub Main
{
$cgi = new CGI;
$session = new CGI::Session (undef, $cgi,
{ Directory => '/websessions/test' });

my $name = $cgi->param('name') || $session->param('name');
$session->param('name',$name) if ($name);

my $cookie = $cgi->cookie(CGISESSID => $session->id);

print $cgi->header(
'-content-type' => 'text/html',
-expires => '+20s',
-cookie=> $cgi->cookie(CGISESSID=>$session->id)
);

print $cgi->start_html('CGI::Session Test Page'),
$cgi->h1("Hello user: $name"),
$cgi->end_html;
}
------------------------------------------------------------

BOOM!!! Now, it starts creating session after session after session.
If I remove the use DBI, everything works fine again. If I remove the
global $cgi and $session variables and make them local within Main
instead, everything works fine. I even thought that maybe DBI had
some kind of global variables that conflict with $cgi and/or $session,
so I renamed them to $zxcvb and $asdfg, but it still creates new
sessions only. Even if I specifically *tell* it the session ID, it
*still* creates new sessions only.

Am I doing something syntactically wrong, or is this a genuine bug?

The program above works perfectly on my system. I used copy and paste,
and the only thing I changed was the sessions directory.

BTW, you can simplify the program by reusing the cookie object when you
print the HTTP header:

-cookie => $cookie,

HTH
 
M

Mumia W.

[...]
BOOM!!! Now, it starts creating session after session after session.
If I remove the use DBI, everything works fine again. If I remove the
global $cgi and $session variables and make them local within Main
instead, everything works fine. I even thought that maybe DBI had
some kind of global variables that conflict with $cgi and/or $session,
so I renamed them to $zxcvb and $asdfg, but it still creates new
sessions only. Even if I specifically *tell* it the session ID, it
*still* creates new sessions only.

Am I doing something syntactically wrong, or is this a genuine bug?

I don't know what environment you're running under, but mod_perl seems
to complicate things. This script works on my Apache2, mod_perl_2 system:

use strict;
use warnings;
use CGI;
use DBI;
use Cwd;
use CGI::Session;
use File::Basename;
use Data::Dumper;

my $cgi;
my $session;

chdir(dirname($ENV{SCRIPT_FILENAME}));

my ($dsn, $user, $pass) = @{require 'dsn.pl'};
my $dbh = DBI->connect($dsn, $user, $pass) or die $DBI::errstr;


my $Main = sub {
$cgi = new CGI;
$session = new CGI::Session ('driver:MySQL', $cgi,
{ Handle => $dbh }) or die $CGI::Session::errstr;

my $name = $cgi->param('name') || $session->param('name');
$session->param('name',$name) if ($name);

my $cookie = $cgi->cookie(CGISESSID => $session->id);

print $cgi->header(
'-content-type' => 'text/html',
-expires => '+20s',
-cookie=> $cookie,
);

print $cgi->start_html('CGI::Session Test Page'),
$cgi->h1("Hello there user: $name"),
# $cgi->pre(CGI::escapeHTML(Dumper(\%ENV))),
$cgi->end_html;
};

$Main->();

$dbh->disconnect;
undef $dbh;

__END__

I decided to make Main a closure because I saw a warning in the Apache
error_log: "$cgi will not stay shared." And under mod_perl,
disconnecting from the database is a good idea because that won't happen
automatically like it should under true CGI.

I have no doubt that it gets even more complicated as you delve more
into databases, persistent connections and persistent Perl interpreters.
 
T

TonyV

I think there's been some confusion. I'm not actually storing the
session information in the database; I'm using the default file driver
for it. The database stuff is totally unrelated to the session stuff
I'm trying to get working.

It looks to me like one cannot copy the $session variable without
creating a new session from it. In other words, if you do something
like this:

my $session = new CGI::Session(undef, $cgi);

You're good to go. But if you do something like this:

my $session1 = new CGI::Session(undef, $cgi);
my $session2 = $session1;

This will create a new session. What I'm guessing is happening is
that by declaring my $session in one place and then calling
CGI::Session->new in another, it's "thinking" that you're copying a
session and creating a whole new one.

The thing that is really annoying me is that if I don't use DBI, it
doesn't do that. Only when I use DBI does it start exhibiting this
strange behavior. The DBI I'm using came with ActiveState Perl, and
I've also got DBD-Oracle 1.17 installed.

Just as a temporary hack, I've started using $session as a reference
to the session instead of the session variable itself. Uuuugly, but
at least it works. :-(
 
X

xhoster

Mumia W. said:
[...]
BOOM!!! Now, it starts creating session after session after session.
If I remove the use DBI, everything works fine again. If I remove the
global $cgi and $session variables and make them local within Main
instead, everything works fine. I even thought that maybe DBI had
some kind of global variables that conflict with $cgi and/or $session,
so I renamed them to $zxcvb and $asdfg, but it still creates new
sessions only. Even if I specifically *tell* it the session ID, it
*still* creates new sessions only.

Am I doing something syntactically wrong, or is this a genuine bug?

I don't know what environment you're running under, but mod_perl seems
to complicate things. This script works on my Apache2, mod_perl_2 system:

use strict;
use warnings;
use CGI;
use DBI;
use Cwd;
use CGI::Session;
use File::Basename;
use Data::Dumper;

my $cgi;
my $session;

chdir(dirname($ENV{SCRIPT_FILENAME}));

my ($dsn, $user, $pass) = @{require 'dsn.pl'};
my $dbh = DBI->connect($dsn, $user, $pass) or die $DBI::errstr;

my $Main = sub {
$cgi = new CGI;
$session = new CGI::Session ('driver:MySQL', $cgi,
{ Handle => $dbh }) or die $CGI::Session::errstr;

my $name = $cgi->param('name') || $session->param('name');
$session->param('name',$name) if ($name);

my $cookie = $cgi->cookie(CGISESSID => $session->id);

print $cgi->header(
'-content-type' => 'text/html',
-expires => '+20s',
-cookie=> $cookie,
);

print $cgi->start_html('CGI::Session Test Page'),
$cgi->h1("Hello there user: $name"),
# $cgi->pre(CGI::escapeHTML(Dumper(\%ENV))),
$cgi->end_html;
};

$Main->();

$dbh->disconnect;
undef $dbh;

__END__

I decided to make Main a closure because I saw a warning in the Apache
error_log: "$cgi will not stay shared."

Wouldn't it be better to move your declaration of $cgi, etc. into the
subroutine (as they aren't used anywhere outside the sub), and move the
$dbh disconnect into the sub as well? Then Main could be changed back
to a regular sub.

Xho
 
M

Mumia W.

[...]
use strict;
use CGI::Session;
use CGI;

my $cgi = new CGI;
my $session = new CGI::Session(undef, undef, {Directory=>'/websessions/

The second parameter should be a CGI object like so:

my $session = new CGI::Session(undef, $cgi, {Directory => ...

HTH
 
U

Uri Guttman

x> While I'll be. That will teach me not to read the perldocs for my
x> locally installed version rather than the version the OP was
x> talking about.

i am not sure if english is your first language so i will assume it is
not. the expression is, "well, i'll be ..." with ... being one of many
subphrases (damned, hornswoggled, etc. :).

uri
 
M

Mark Clements

Uri said:
x> While I'll be. That will teach me not to read the perldocs for my
x> locally installed version rather than the version the OP was
x> talking about.

i am not sure if english is your first language so i will assume it is
not. the expression is, "well, i'll be ..." with ... being one of many
subphrases (damned, hornswoggled, etc. :).

Very often it's just plain "Well I'll be," the expletive being implied.
It works fine on its own.
 
U

Uri Guttman

x> locally installed version rather than the version the OP was
x> talking about.
MC> Very often it's just plain "Well I'll be," the expletive being implied.
MC> It works fine on its own.

yeah, i should have also included that. anyhow my point was the
s/while/well/ for xhoster (who seems to know english quite well and i
thought he would appreciate this correction).

uri
 
X

xhoster

Uri Guttman said:
x> locally installed version rather than the version the OP was
x> talking about.

MC> Very often it's just plain "Well I'll be," the expletive being
implied. MC> It works fine on its own.

yeah, i should have also included that. anyhow my point was the
s/while/well/,

Oh, I didn't catch that until now. I thought you were talking about the
ellipsis versus just the period.
for xhoster (who seems to know english quite well and i
thought he would appreciate this correction).

Now that I understand it, thank you. My only excuse is that I was mentally
using a Hill-Billy-like accent in which "well" is pronounced like
"while".


Xho
 
M

Mark Clements

Uri said:
x> locally installed version rather than the version the OP was
x> talking about.

MC> Very often it's just plain "Well I'll be," the expletive being implied.
MC> It works fine on its own.

yeah, i should have also included that. anyhow my point was the
s/while/well/ for xhoster (who seems to know english quite well and i
thought he would appreciate this correction).

Oops - I'd missed that. My correction of your correction was, er,
incorrect. Sorry Uri!

Mark
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top