Here is the code snippet I usually use, I hope it's not hard
for you with PHP background to follow:
my %who = (); # tied hash
my %c = fetch CGI::Cookie; # received session cookie
my $sid; # session id
my $sc; # session cookie to sent
if (%c) { # check existence of cookie
# print STDERR Dumper %c;
if (exists $c{sid}) { # check existence of session id in cookie
$sid = $c{sid}->value;
# untaint:
($sid) = $sid =~ /(.+)/;
}
}
if ($sid) {
# attempt to retrieve user information from session id
eval {
tie %who, 'Apache::Session::File', $sid,
{
Directory => $session_dir,
LockDirectory => $session_lock_dir,
};
};
if ($@) {
# can't revive session id, probably already garbage-collected
$sc = create_cookie($sid, "expires");
undef $sid;
}
}
# if login is submitted, tie a session and retrieve $sid
if (param('login')) {
my $uname = param('uname');
my $upass = param('upass');
my ($uinfo, $mesg) = $db->auth_user($uname, $upass);
unless ($uinfo) {
# failed authentication. do smth and exit.
} else {
# generate session and send cookie in header
eval {
tie %who, 'Apache::Session::File', undef,
{
Directory => $session_dir,
LockDirectory => $session_lock_dir,
};
};
if ($@) {
die "Can't create session: $@";
}
$sid = $who{_session_id};
# store anything valuable
$who{name} = $uinfo->{name};
$who{gname} = $uinfo->{gname};
}
}
if (exists $who{name}) { # if (%who) doesn't work here! why?
# a user is currently logged in.
# do smth he/she is allowed to do
} else {
# user is not logged in
}
I don't know the fundamental difference between
Apache::Session and
CGI::Session.
Both looks quite similar, with an important difference that
CGI::Session
uses
Data::Dumper which is a standard module
for its data serialization.
Apache::Session
uses
Storable which requires separate installation,
and a C compiler (it has XS code).
Yesterday I had a bad time with Apache::Session
which fails to store data and ended with warnings in
error log such as this:
(in cleanup) Can't call method "update" on an undefined value at
/usr/local/lib/perl5/site_perl/5.6.1/Apache/Session.pm line 508 during
global destruction.
(in cleanup) Can't call method "close" on an undefined value at
/usr/local/lib/perl5/site_perl/5.6.1/Apache/Session/File.pm line 41
during global destruction.
The strange thing is this happens only with an application
I'm currently working on, I have several other applications
running
Apache::Session without problem.
The logic for sessions storing and retrieval is the same,
and that is the same code snippet as above.
After several hours wasted to locate the problem,
I tried
CGI::Session. The interface is quite
similar to
Apache::Session, so changes is quite minimal:
s/Apache/CGI/. And.. the problem disappeared (!)
I just couldn't believe that this is a problem with
Apache::Session which is already out there for
a couple of years. But now I'm sure that CGI::Session
is a very good alternative to Apache::Session.