CGI-Application-Plugin-Session
view release on metacpan or search on metacpan
lib/CGI/Application/Plugin/Session.pm view on Meta::CPAN
sub session_config {
my $self = shift;
if (@_) {
die "Calling session_config after the session has already been created" if (defined $self->{__CAP__SESSION_OBJ});
my $props;
if (ref($_[0]) eq 'HASH') {
$props = $self->_cap_hash($_[0]);
} else {
$props = $self->_cap_hash({ @_ });
}
# Check for CGI_SESSION_OPTIONS
if ($props->{CGI_SESSION_OPTIONS}) {
die "session_config error: parameter CGI_SESSION_OPTIONS is not an array reference" if ref $props->{CGI_SESSION_OPTIONS} ne 'ARRAY';
$self->{__CAP__SESSION_CONFIG}->{CGI_SESSION_OPTIONS} = delete $props->{CGI_SESSION_OPTIONS};
}
# Check for COOKIE_PARAMS
if ($props->{COOKIE_PARAMS}) {
die "session_config error: parameter COOKIE_PARAMS is not a hash reference" if ref $props->{COOKIE_PARAMS} ne 'HASH';
$self->{__CAP__SESSION_CONFIG}->{COOKIE_PARAMS} = delete $props->{COOKIE_PARAMS};
}
# Check for SEND_COOKIE
if (defined $props->{SEND_COOKIE}) {
$self->{__CAP__SESSION_CONFIG}->{SEND_COOKIE} = (delete $props->{SEND_COOKIE}) ? 1 : 0;
}
# Check for DEFAULT_EXPIRY
if (defined $props->{DEFAULT_EXPIRY}) {
$self->{__CAP__SESSION_CONFIG}->{DEFAULT_EXPIRY} = delete $props->{DEFAULT_EXPIRY};
}
# If there are still entries left in $props then they are invalid
die "Invalid option(s) (".join(', ', keys %$props).") passed to session_config" if %$props;
}
$self->{__CAP__SESSION_CONFIG};
}
sub session_cookie {
my $self = shift;
my %options = @_;
# merge in any parameters set by config_session
if ($self->{__CAP__SESSION_CONFIG}->{COOKIE_PARAMS}) {
%options = (%{ $self->{__CAP__SESSION_CONFIG}->{COOKIE_PARAMS} }, %options);
}
if (!$self->{__CAP__SESSION_OBJ}) {
# The session object has not been created yet, so make sure we at least call it once
my $tmp = $self->session;
}
## check cookie option -name with session name
## if different these may cause problems/confusion
if ( exists $options{'-name'} and
$options{'-name'} ne $self->session->name ) {
warn sprintf( "Cookie '%s' and Session '%s' name don't match.\n",
$options{'-name'}, $self->session->name )
}
## setup the values for cookie
$options{'-name'} ||= $self->session->name;
$options{'-value'} ||= $self->session->id;
if(defined($self->session->expires()) && !defined($options{'-expires'})) {
$options{'-expires'} = _build_exp_time( $self->session->expires() );
}
my $cookie = $self->query->cookie(%options);
# Look for a cookie header in the existing headers
my %headers = $self->header_props;
my $cookie_set = 0;
if (my $cookies = $headers{'-cookie'}) {
if (ref($cookies) eq 'ARRAY') {
# multiple cookie headers so check them all
for (my $i=0; $i < @$cookies; $i++) {
# replace the cookie inline if we find a match
if (substr($cookies->[$i], 0, length($options{'-name'})) eq $options{'-name'}) {
$cookies->[$i] = $cookie;
$cookie_set++;
}
}
} elsif (substr($cookies, 0, length($options{'-name'})) eq $options{'-name'}) {
# only one cookie and it is ours, so overwrite it
$self->header_add(-cookie => $cookie);
$cookie_set++;
}
}
$self->header_add(-cookie => [$cookie]) unless $cookie_set;
return 1;
}
sub _build_exp_time {
my $secs_until_expiry = shift;
return unless defined $secs_until_expiry;
# Add a plus sign unless the number is negative
my $prefix = ($secs_until_expiry >= 0) ? '+' : '';
# Add an 's' for "seconds".
return $prefix.$secs_until_expiry.'s';
}
sub session_delete {
my $self = shift;
if ( my $session = $self->session ) {
$session->delete;
$session->flush;
if ( $self->{'__CAP__SESSION_CONFIG'}->{'SEND_COOKIE'} ) {
my %options;
if ( $self->{'__CAP__SESSION_CONFIG'}->{'COOKIE_PARAMS'} ) {
%options = ( %{ $self->{'__CAP__SESSION_CONFIG'}->{'COOKIE_PARAMS'} }, %options );
}
$options{'name'} ||= $session->name;
$options{'value'} = '';
$options{'-expires'} = '-1d';
my $newcookie = $self->query->cookie(\%options);
# See if a session cookie has already been set (this will happen if
# this is a new session). We keep all existing cookies except the
# session cookie, which we replace with the timed out session
# cookie
my @keep;
my %headers = $self->header_props;
my $cookies = $headers{'-cookie'} || [];
$cookies = [$cookies] unless ref $cookies eq 'ARRAY';
foreach my $cookie (@$cookies) {
if ( ref($cookie) ne 'CGI::Cookie' || $cookie->name ne $session->name ) {
# keep this cookie
push @keep, $cookie;
}
}
push @keep, $newcookie;
# We have to set the cookies this way, because CGI::Application has
# an annoying interface to the headers (why can't we have
# 'header_set as well as header_add?). The first call replaces all
# cookie headers with the one new cookie header, and the next call
# adds in the rest of the cookies if there are any.
$self->header_add( -cookie => shift @keep );
$self->header_add( -cookie => \@keep ) if @keep;
}
}
}
sub session_loaded {
my $self = shift;
return defined $self->{__CAP__SESSION_OBJ};
}
sub session_recreate {
my $self = shift;
my $data = {};
# Copy all values from existing session and delete it
if (session_loaded($self)) {
$data = $self->session->param_hashref;
$self->session->delete;
$self->session->flush;
$self->{__CAP__SESSION_OBJ} = undef;
}
# create a new session and populate it
# (This should also send out a new cookie if so configured)
my $session = $self->session;
while(my($k,$v) = each %$data) {
next if index($k, '_SESSION_') == 0;
$session->param($k => $v);
}
$session->flush;
return 1;
}
## all a hack to adjust for problems with cgi::session and
## it not playing with non-CGI.pm objects
sub __locate_session_name {
my $self = shift;
my $sess_opts = $self->{__CAP__SESSION_CONFIG}->{CGI_SESSION_OPTIONS};
## search for 'name' cgi session option
if ( $sess_opts and $sess_opts->[4]
and ref $sess_opts->[4] eq 'HASH'
and exists $sess_opts->[4]->{name} ) {
return $sess_opts->[4]->{name};
}
lib/CGI/Application/Plugin/Session.pm view on Meta::CPAN
CGI::Application::Plugin::Session - Add CGI::Session support to CGI::Application
=head1 METHODS
=head2 session
This method will return the current L<CGI::Session> object. The L<CGI::Session> object is created on
the first call to this method, and any subsequent calls will return the same object. This effectively
creates a singleton session object for the duration of the request. L<CGI::Session> will look for a cookie
or param containing the session ID, and create a new session if none is found. If C<session_config>
has not been called before the first call to C<session>, then it will choose some sane defaults to
create the session object.
# retrieve the session object
my $session = $self->session;
- or -
# use the session object directly
my $language = $self->session->param('language');
=head2 session_config
This method can be used to customize the functionality of the CGI::Application::Plugin::Session module.
Calling this method does not mean that a new session object will be immediately created.
The session object will not be created until the first call to $self->session. This
'lazy loading' can prevent expensive file system or database calls from being made if
the session is not needed during this request.
The recommended place to call C<session_config> is in the C<cgiapp_init>
stage of L<CGI::Application>. If this method is called after the session object
has already been accessed, then it will die with an error message.
If this method is not called at all then a reasonable set of defaults
will be used (the exact default values are defined below).
The following parameters are accepted:
=over 4
=item CGI_SESSION_OPTIONS
This allows you to customize how the L<CGI::Session> object is created by providing a list of
options that will be passed to the L<CGI::Session> constructor. Please see the documentation
for L<CGI::Session> for the exact syntax of the parameters.
=item DEFAULT_EXPIRY
L<CGI::Session> Allows you to set an expiry time for the session. You can set the
DEFAULT_EXPIRY option to have a default expiry time set for all newly created sessions.
It takes the same format as the $session->expiry method of L<CGI::Session> takes.
Note that it is only set for new session, not when a session is reloaded from the store.
=item COOKIE_PARAMS
This allows you to customize the options that are used when creating the session cookie.
For example you could provide an expiry time for the cookie by passing -expiry => '+24h'.
The -name and -value parameters for the cookie will be added automatically unless
you specifically override them by providing -name and/or -value parameters.
See the L<CGI::Cookie> docs for the exact syntax of the parameters.
NOTE: You can do the following to get both the cookie name and the internal name of the CGI::Session object to be changed:
$self->session_config(
CGI_SESSION_OPTIONS => [
$driver,
$self->query,
\%driver_options,
{ name => 'new_cookie_name' } # change cookie and session name
]
);
Also, if '-name' parameter and 'name' of session don't match a warning will
be emitted.
=item SEND_COOKIE
If set to a true value, the module will automatically add a cookie header to
the outgoing headers if a new session is created (Since the session module is
lazy loaded, this will only happen if you make a call to $self->session at some
point to create the session object). This option defaults to true. If it is
set to false, then no session cookies will be sent, which may be useful if you
prefer URL based sessions (it is up to you to pass the session ID in this
case).
=back
The following example shows what options are set by default (ie this is what you
would get if you do not call session_config).
$self->session_config(
CGI_SESSION_OPTIONS => [ "driver:File", $self->query, {Directory=>'/tmp'} ],
COOKIE_PARAMS => {
-path => '/',
},
SEND_COOKIE => 1,
);
Here is a more customized example that uses the PostgreSQL driver and sets an
expiry and domain on the cookie.
$self->session_config(
CGI_SESSION_OPTIONS => [ "driver:PostgreSQL;serializer:Storable", $self->query, {Handle=>$dbh} ],
COOKIE_PARAMS => {
-domain => 'mydomain.com',
-expires => '+24h',
-path => '/',
-secure => 1,
},
);
=head2 session_cookie
This method will add a cookie to the outgoing headers containing
the session ID that was assigned by the CGI::Session module.
This method is called automatically the first time $self->session is accessed
if SEND_COOKIE was set true, which is the default, so it will most likely never
need to be called manually.
( run in 0.856 second using v1.01-cache-2.11-cpan-e1769b4cff6 )