CHP-11>
No, we are not going teach you how to make a delicious tofu and soybean stew. But this is almost as good. This chapter shows how to do some common Mason tasks, some of them with more than one implementation.
CHP-11-SECT-1>
For many of our
sessions>
session examples, we will be using the
Apache::Session
Apache::Session
module>
modules;Apache::Session>
module. Despite its name, this module doesn't
actually require mod_perl
or Apache, though that
is the context in which it was born and in which
it's most often used. It implements a simple tied
hash interface to a persistent object.N<If you are not
familiar with Perl's tied variable feature, we
suggest reading the perltie manpages (perldoc
perltie
).> It has one major
gotcha: you must make sure that the session object gets cleaned up
properly (usually by letting it go out of scope), so that it will be
written to disk after each access.
CHP-11-SECT-1.1> httpd.conf files>
Here is an example that doesn't involve changing any of your Apache configuration settings. The following code should be placed in a top-level autohandler. Any component that needs to use the session will have to inherit from this component, either directly or via a longer inheritance chain.
It uses cookies;storing sessions with> > sessions;storing> cookies to store the session.
<%once> use Apache::Cookie; use Apache::Session::File; </%once> <%init> my %c = Apache::Cookie->fetch; my $session_id = exists $c{masonbook_session} ? $c{masonbook_session}->value : undef;
First, it loads the necessary
modules;loading>
modules.
Normally we recommend that you do this at server startup via a
PerlModule
directive>
PerlModule directive in your
httpd.conf file or in your
handler.pl file to save memory, but we load them
here just to show you which ones we are using. The component uses the
Apache::Cookie
module to fetch any cookies that
might have been sent by the browser. Then we check for the existence
of a cookie called masonbook_session
, which if it
exists should contain a valid session ID.
local *MasonBook::Session; eval { tie %MasonBook::Session, 'Apache::Session::File', $session_id, { Directory => '/tmp/sessions', LockDirectory => '/tmp/sessions', }; }; if ($@) { die $@ unless $@ =~ /Object does not exist/; # Re-throw $m->redirect('/bad_session.html'); }
The first line ensures that when this component ends, the session
variable will go out of scope, which triggers
Apache::Session
's cleanup
mechanisms. This is quite important, as otherwise the data will never
be written to disk. Even worse, Apache::Session
may still be maintaining various locks internally, leading to
deadlock. We use local(
)
local( ) method>
to localize the symbol table entry
*MasonBook::Session
; it's not
enough to localize just the hash
%MasonBook::Session
, because the tie(
)
tie( ) method>
magic is attached to the symbol table entry. It's also worth mentioning that we use a global variable rather than a lexical one, because we want this variable to be available to all components.
If the value in the $session_id
variable is
undef
, that is not a problem. The
Apache::Session
__FOX_NLBF__>
__FOX_NLBF__>
module simply creates a new session
ID. However, if $session_id
is defined but does
not represent a valid session, an exception will be thrown. This
means either that the user's session has expired or
that she's trying to feed us a bogus ID. Either way,
we want to tell her what's happened, so we redirect
to another page that will explain things. To trap the exception, we
wrap the tie( )
in an eval {}
block.
If an exception is thrown, we check $@
to see
whether the message indicates that the session isn't
valid. Any other error is fatal. If the session
isn't valid, we use the redirect(
)
method provided by the request object.
Finally, we send the user a cookie:
Apache::Cookie->new( $r, name => 'masonbook_session', value => $MasonBook::Session{_session_id}, path => '/', expires => '+1d', )->bake;
This simply uses the
Apache::Cookie
Apache::Cookie
module>
modules;Apache::Cookie>
module to ensure that a cookie will be sent to the client with the
response headers. This cookie is called
'masonbook_session'
and is the one
we checked for earlier. It doesn't hurt to send the
cookie every time a page is viewed, though this will reset the
expiration time of the cookie each time it is set. If you want the
cookie to persist for only a certain fixed length of time after the
session is created, don't resend the __FOX_NLBF__>
__FOX_NLBF__>
__FOX_NLBF__>
cookie.
$m->call_next; </%init>
This line simply calls the next component in the inheritance chain.
Presumably, other components down the line may change the contents of
%MasonBook::Session
, and those modifications will
be written to disk at the end of the request.
A<CHP-11-EX-1>Example 11-1 shows the entire component.