Tadashi Okoshi
slash****@users*****
2005年 12月 20日 (火) 01:42:00 JST
Index: affelio/extlib/CGI/Session/BluePrint.pm
diff -u affelio/extlib/CGI/Session/BluePrint.pm:1.2 affelio/extlib/CGI/Session/BluePrint.pm:1.3
--- affelio/extlib/CGI/Session/BluePrint.pm:1.2 Sun Dec 18 14:16:46 2005
+++ affelio/extlib/CGI/Session/BluePrint.pm Tue Dec 20 01:42:00 2005
@@ -1,6 +1,6 @@
package CGI::Session::BluePrint;
-# $Id: BluePrint.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: BluePrint.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
use strict;
use base qw(
@@ -55,7 +55,7 @@
-# $Id: BluePrint.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: BluePrint.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
1;
@@ -121,4 +121,4 @@
=cut
-# $Id: BluePrint.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: BluePrint.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
Index: affelio/extlib/CGI/Session/CookBook.pm
diff -u affelio/extlib/CGI/Session/CookBook.pm:1.2 affelio/extlib/CGI/Session/CookBook.pm:1.3
--- affelio/extlib/CGI/Session/CookBook.pm:1.2 Sun Dec 18 14:16:46 2005
+++ affelio/extlib/CGI/Session/CookBook.pm Tue Dec 20 01:42:00 2005
@@ -1,10 +1,10 @@
-# $Id: CookBook.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: CookBook.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
package CGI::Session::CookBook;
use vars ('$VERSION');
-($VERSION) = '$Revision: 1.2 $' =~ m/Revision:\s*(\S+)/;
+($VERSION) = '$Revision: 1.3 $' =~ m/Revision:\s*(\S+)/;
1;
Index: affelio/extlib/CGI/Session/DB_File.pm
diff -u affelio/extlib/CGI/Session/DB_File.pm:1.2 affelio/extlib/CGI/Session/DB_File.pm:1.3
--- affelio/extlib/CGI/Session/DB_File.pm:1.2 Sun Dec 18 14:16:46 2005
+++ affelio/extlib/CGI/Session/DB_File.pm Tue Dec 20 01:42:00 2005
@@ -1,6 +1,6 @@
package CGI::Session::DB_File;
-# $Id: DB_File.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: DB_File.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
use strict;
use base qw(
@@ -83,7 +83,7 @@
-# $Id: DB_File.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: DB_File.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
1;
@@ -165,4 +165,4 @@
=cut
-# $Id: DB_File.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: DB_File.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
Index: affelio/extlib/CGI/Session/ErrorHandler.pm
diff -u affelio/extlib/CGI/Session/ErrorHandler.pm:1.1 affelio/extlib/CGI/Session/ErrorHandler.pm:removed
--- affelio/extlib/CGI/Session/ErrorHandler.pm:1.1 Sun Dec 18 14:16:46 2005
+++ affelio/extlib/CGI/Session/ErrorHandler.pm Tue Dec 20 01:42:00 2005
@@ -1,72 +0,0 @@
-package CGI::Session::ErrorHandler;
-
-# $Id: ErrorHandler.pm,v 1.1 2005/12/18 05:16:46 slash5234 Exp $
-
-use strict;
-$CGI::Session::ErrorHandler::VERSION = "4.01";
-
-=pod
-
-=head1 NAME
-
-CGI::Session::ErrorHandler - error handling routines for CGI::Session
-
-=head1 SYNOPSIS
-
- require CGI::Session::ErrorHandler
- @ISA = qw( CGI::Session::ErrorHandler );
-
- sub some_method {
- my $self = shift;
- unless ( $some_condition ) {
- return $self->set_error("some_method(): \$some_condition isn't met");
- }
- }
-
-=head1 DESCRIPTION
-
-CGI::Session::ErrorHandler provides set_error() and errstr() methods for setting and accessing error messages from within CGI::Session's components. This method should be used by driver developers for providing CGI::Session-standard error handling routines for their code
-
-=head2 METHODS
-
-=over 4
-
-=item set_error($message)
-
-Implicitly defines $pkg_name::errstr and sets its value to $message. Return value is B<always> undef.
-
-=cut
-
-sub set_error {
- my $class = shift;
- $class = ref($class) || $class;
- no strict 'refs';
- ${ "$class\::errstr" } = $_[0] || "";
- return;
-}
-
-=item errstr()
-
-Returns whatever value was set by the most recent call to set_error(). If no message as has been set yet, the empty string is returned so the message can still concatenate without a warning.
-
-=back
-
-=cut
-
-*error = \&errstr;
-sub errstr {
- my $class = shift;
- $class = ref( $class ) || $class;
-
- no strict 'refs';
- return ${ "$class\::errstr" } || '';
-}
-
-=head1 LICENSING
-
-For support and licensing information see L<CGI::Session|CGI::Session>.
-
-=cut
-
-1;
-
Index: affelio/extlib/CGI/Session/Example.pm
diff -u affelio/extlib/CGI/Session/Example.pm:1.2 affelio/extlib/CGI/Session/Example.pm:1.3
--- affelio/extlib/CGI/Session/Example.pm:1.2 Sun Dec 18 14:16:46 2005
+++ affelio/extlib/CGI/Session/Example.pm Tue Dec 20 01:42:00 2005
@@ -1,6 +1,6 @@
package CGI::Session::Example;
-# $Id: Example.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: Example.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
use strict;
#use diagnostics;
Index: affelio/extlib/CGI/Session/File.pm
diff -u affelio/extlib/CGI/Session/File.pm:1.2 affelio/extlib/CGI/Session/File.pm:1.3
--- affelio/extlib/CGI/Session/File.pm:1.2 Sun Dec 18 14:16:46 2005
+++ affelio/extlib/CGI/Session/File.pm Tue Dec 20 01:42:00 2005
@@ -1,6 +1,6 @@
package CGI::Session::File;
-# $Id: File.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: File.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
use strict;
use File::Spec;
@@ -13,7 +13,7 @@
use vars qw($FileName $VERSION);
-($VERSION) = '$Revision: 1.2 $' =~ m/Revision:\s*(\S+)/;
+($VERSION) = '$Revision: 1.3 $' =~ m/Revision:\s*(\S+)/;
$FileName = 'cgisess_%s';
sub store {
@@ -99,7 +99,7 @@
-# $Id: File.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: File.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
1;
@@ -111,7 +111,7 @@
=head1 REVISION
-This manual refers to $Revision: 1.2 $
+This manual refers to $Revision: 1.3 $
=head1 SYNOPSIS
@@ -187,4 +187,4 @@
=cut
-# $Id: File.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: File.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
Index: affelio/extlib/CGI/Session/MySQL.pm
diff -u affelio/extlib/CGI/Session/MySQL.pm:1.2 affelio/extlib/CGI/Session/MySQL.pm:1.3
--- affelio/extlib/CGI/Session/MySQL.pm:1.2 Sun Dec 18 14:16:46 2005
+++ affelio/extlib/CGI/Session/MySQL.pm Tue Dec 20 01:42:00 2005
@@ -1,6 +1,6 @@
package CGI::Session::MySQL;
-# $Id: MySQL.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: MySQL.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
use strict;
# Inheriting necessary functionalities from the
@@ -17,7 +17,7 @@
use vars qw($VERSION $TABLE_NAME);
-($VERSION) = '$Revision: 1.2 $' =~ m/Revision:\s*(\S+)/;
+($VERSION) = '$Revision: 1.3 $' =~ m/Revision:\s*(\S+)/;
$TABLE_NAME = 'sessions';
@@ -144,7 +144,7 @@
-# $Id: MySQL.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: MySQL.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
1;
=pod
@@ -236,4 +236,4 @@
-# $Id: MySQL.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: MySQL.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
Index: affelio/extlib/CGI/Session/PostgreSQL.pm
diff -u affelio/extlib/CGI/Session/PostgreSQL.pm:1.2 affelio/extlib/CGI/Session/PostgreSQL.pm:1.3
--- affelio/extlib/CGI/Session/PostgreSQL.pm:1.2 Sun Dec 18 14:16:46 2005
+++ affelio/extlib/CGI/Session/PostgreSQL.pm Tue Dec 20 01:42:00 2005
@@ -12,7 +12,7 @@
# 2003/03/01 cosim****@cpan*****
# Added `FOR UPDATE' sql clauses to enable database row lock management
#
-# $Id: PostgreSQL.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: PostgreSQL.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
package CGI::Session::PostgreSQL;
@@ -31,7 +31,7 @@
use vars qw($VERSION $TABLE_NAME);
-($VERSION) = '$Revision: 1.2 $' =~ m/Revision:\s*(\S+)/;
+($VERSION) = '$Revision: 1.3 $' =~ m/Revision:\s*(\S+)/;
$TABLE_NAME = 'sessions';
########################
@@ -204,7 +204,7 @@
-# $Id: PostgreSQL.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+# $Id: PostgreSQL.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
1;
Index: affelio/extlib/CGI/Session/Tutorial.pm
diff -u affelio/extlib/CGI/Session/Tutorial.pm:1.2 affelio/extlib/CGI/Session/Tutorial.pm:1.3
--- affelio/extlib/CGI/Session/Tutorial.pm:1.2 Sun Dec 18 14:16:46 2005
+++ affelio/extlib/CGI/Session/Tutorial.pm Tue Dec 20 01:42:00 2005
@@ -1,46 +1,52 @@
+# $Id: Tutorial.pm,v 1.3 2005/12/19 16:42:00 slash5234 Exp $
+
package CGI::Session::Tutorial;
-# $Id: Tutorial.pm,v 1.2 2005/12/18 05:16:46 slash5234 Exp $
+use vars ('$VERSION');
+
+($VERSION) = '$Revision: 1.3 $' =~ m/Revision:\s*(\S+)/
+
+1;
-$CGI::Session::Tutorial::VERSION = '3.41';
+__END__;
=pod
=head1 NAME
-CGI::Session::Tutorial - Extended CGI::Session manual
+Tutorial - extended CGI::Session manual
-=head1 STATE MAINTENANCE OVERVIEW
+=head1 STATE MAINTANANCE OVERVIEW
-Since HTTP is a stateless protocol, each subsequent click to a web site is treated as new request by the Web server. The server does not relate a visit with a previous one, thus all the state information from the previous requests are lost. This makes creating such applications as shopping carts, web sites requiring users to authenticate, impossible. So people had to do something about this despair situation HTTP was putting us in.
+Since HTTP is a stateless protocol, each subsequent click to a web site is treated as new by the web server. The server does not relate the visits with previous one, thus all the state information from the previous requests are lost. This makes creating such applications as shopping carts, login/authentication routines, secure restricted services in the web impossible. So people had to do something against this despair situation HTTP was putting us in.
-For our rescue come such technologies as I<HTTP Cookies> and I<QUERY_STRING>s that help us save the users' session for a certain period. Since I<HTTP Cookies> and I<QUERY_STRING>s alone cannot take us too far (B<RFC 2965, Section 5, "Implementation Limitations">), several other libraries have been developed to extend their capabilities and promise a more reliable solution. L<CGI::Session|CGI::Session> is one of them.
+For our rescue come such technologies as HTTP Cookies and QUERY_STRINGs that help us save the users' session for a certain period. Since cookies and query_strings alone cannot take us too far B<RFC 2965, Section 5, "Implementation Limitations">, several other libraries/technologies have been developed to extend their capabilities and promise a more reliable and a more persistent system. CGI::Session is one of them.
Before we discuss this library, let's look at some alternative solutions.
-=head2 COOKIE
+=head2 COOOKIE
-Cookie is a piece of text-information that a web server is entitled to place in the user's hard disk, assuming a user agent (such as Internet Explorer, Mozilla, etc) is compatible with the specification. After the cookie is placed, user agents are required to send these cookies back to the server as part of the HTTP request. This way the server application ( CGI, for example ) will have a way of relating previous requests by the same user agent, thus overcoming statelessness of HTTP.
+Cookie is a piece of text-information that a web server is entitled to place in the user's hard disk, assuming a user agent (i.e.. Web Browser) is compatible with the specification. After the cookie being placed, user agents are required to send these cookies back to the server as part of the HTTP request. This way the server application ( CGI ) will have a way of relating previous requests by the same user agent, thus overcoming statelessness of HTTP.
-Although I<HTTP Cookies> seem to be promising solution for the statelessness of HTTP, they do carry certain limitations, such as limited number of cookies per domain and per user agent and limited size on each cookie. User Agents are required to store at least 300 cookies at a time, 20 cookies per domain and allow 4096 bytes of storage for each cookie. They also rise several Privacy and Security concerns, the lists of which can be found on the sections B<6-"Privacy"> and B<7-"Security Considerations"> of B<RFC 2965>.
+Although cookies seem to be promising solutions for the statelessness of HTTP, they do carry certain limitations, such as limited number of cookies per domain and per user agent and limited size on each cookie. User Agents are required to store at least 300 cookies at a time, 20 cookies per domain and allow 4096 bytes of storage for each cookie. They also rise several Privacy and Security concerns, the lists of which can be found on the sections 6-B<"Privacy" and 7-"Security Considerations"> of B<RFC 2965> respectively.
=head2 QUERY STRING
Query string is a string appended to URL following a question mark (?) such as:
- http://my.dot.com/login.cgi?user=sherzodr;password=top-secret
+ http://my.dot.com/login.cgi?user=sherzodr&password=topSecret
-As you probably guessed, it can also help you pass state information from a click to another, but how secure is it do you think, considering these URLs tend to get cached by most of the user agents and also logged in the servers access log, to which everyone can have access.
+As you probably guessed already, it can also help you to pass state information from a click to another, but how secure is it do you think? Considering these URLs tend to get cached by most of the user agents and also logged in the servers access log, to which everyone can have access to, it is not secure.
=head2 HIDDEN FIELDS
-Hidden field is another alternative to using query strings and they come in two flavors: hidden fields used in POST methods and the ones in GET. The ones used in GET methods will turn into a true query strings once submitted, so all the disadvantages of QUERY_STRINGs apply. Although POST requests do not have limitations of its sister-GET, the pages that hold them get cached by Web browser, and are available within the source code of the page (obviously). They also become unwieldily to manage when one has oodles of state information to keep track of ( for instance, a shopping cart or an advanced search engine).
+Hidden field is another alternative to using query strings and they come in two flavors: hidden fields used in POST methods and the ones in GET. The ones used in GET methods will turn into a true query string once submitted, so all the disadvantages of QUERY_STRINGs do apply. Although POST requests do not have limitations of its sister-GET, the pages that hold them do the cached by web browser, and are available within the source code of the page (obviously). They also become unwieldily to manage when one has oodles of state information to keep track of ( for instance, a shopping cart or an advanced search engine).
Query strings and hidden fields are also lost easily by closing the browser, or by clicking the browser's "Back" button.
=head2 SERVER SIDE SESSION MANAGEMENT
-This technique is built upon the aforementioned technologies plus a server-side storage device, which saves the state data on the server side. Each session has a unique id associated with the data in the server. This id is also associated with the user agent either in the form of a I<HTTP Cookie>, a I<QUERY_STRING>, hidden field or any combination of the above. This is necessary to make the connection with the client and his data.
+This technique is built upon the aforementioned technologies plus a server-side storage device, which saves the state data for a particular session. Each session has a unique id associated with the data in the server. This id is also associated with the user agent in either the form of a cookie, a query_string parameter, a hidden field or all at the same time.
Advantages:
@@ -48,178 +54,177 @@
=item *
-We no longer need to depend on User Agent constraints in cookie size.
+We no longer need to depend on the User Agent constraints in cookie amounts and sizes
=item *
-Sensitive data no longer need to be traveling across the network at each request (which is the case with query strings, cookies and hidden fields). The only thing that travels is the unique id generated for the session (B<5767393932698093d0b75ef614376314>, for instance), which should make no sense to third parties.
+Sensitive data like user's username, email address, preferences and such no longer need to be traveling across the network at each request (which is the case with query strings, cookies and hidden_fields). Only thing that travels across the network is the unique id generated for the session ("ID-1234", for instance), which should make no sense to bad guys whatsoever.
=item *
-User will not have sensitive data stored in his/her computer in unsecured file (which is a cookie file).
+User will not have sensitive data stored in his computer in an unsecured plain text format (which is a cookie file).
=item *
-It's possible to handle very big and even complex data structures transparently (which I<HTTP Cookies> do not handle).
+It's possible to handle very big and even complex (in-memory) data structures transparently.
=back
-That's what CGI::Session is all about - implementing server side session management. Now is a good time to get feet wet.
+That's what CGI::Session is all about - implementing server side session management. Now is a very good time to get the feet wet.
=head1 PROGRAMMING STYLE
-Server side session management system might be seeming awfully convoluted if you have never dealt with it. Fortunately, with L<CGI::Session|CGI::Session> all the complexity is handled by the library transparently. This section of the manual can be treated as an introductory tutorial to both logic behind session management, and to CGI::Session programming style.
+Server side session management system might be seeming awfully convoluted if you have never dealt with it. Fortunately, with CGI::Session this cumbersome task can be achieved in much elegent way, all the complexity being handled by the library transparently. This section of the manual can be treated as an introductory tutorial to both logic behind session management, and to CGI::Session programming style.
-All applications making use of server side session management rely on the following pattern of operation regardless of the way the system is implemented:
+=head1 WHAT YOU NEED TO KNOW FIRST
-=over 4
+Before you start using the library, you will need to decide where and how you want the session data to be stored in disk. In other words, you will need to tell what driver to use. You can choose either of "File", "DB_File" and "MySQL" drivers, which are shipped with the distribution by default. Examples in this document will be using "File" driver exclusively to make sure the examples are accessible in all machines with the least requirements. To do this, we create the session object like so:
-=item 1
+ use CGI::Session;
+ $session = new CGI::Session("driver:File", $cgi, {Directory=>'/tmp'});
-Check if the user has session cookie dropped in his computer from previous request
+The first argument is called Data Source Name (DSN in short). If it's undef, the library will use the default driver, which is "File". So instead of being explicit about the driver as in the above example, we could simply say:
-=item 2
+ $session = new CGI::Session(undef, $cgi, {Directory=>'/tmp'});
-If the cookie does not exist, create a new session identifier, and drop it as cookie to the user's computer.
+and we're guaranteed it will fall back to default settings.
-=item 3
+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. In this case, the library will try to retrieve the session id from either B<CGISESSID> cookie or B<CGISESSID> CGI parameter (query string)
-If session cookie exists, read the session ID from the cookie and load any previously saved session data from the server side storage. If session had any expiration date set it's useful to re-drop the same cookie to the user's computer so its expiration time will be reset to be relative to user's last activity time.
+The third argument should be in the form of hashref. This will be used by specific CGI::Session driver only. For the list of all the available attributes, consult respective CGI::Session driver. If you want to write a code
+which is expected to run in various operating systems, and want to reference that particular system's
+temporary folder, use tmpdir() method documented in File::Spec:
-=item 4
+ $session = new CGI::Session(undef, $cgi, {Directory=>File::Spec->tmpdir});
-Store any necessary data in the session that you want to make available for the next HTTP request.
+Following drivers are available:
-=back
+=over 4
-CGI::Session will handle all of the above steps. All you have to do is to choose what to store in the session.
+=item *
-=head2 GETTING STARTED
+L<File|CGI::Session::File> - default driver for storing session data in plain files. Full name: B<CGI::Session::File>
-To make L<CGI::Session|CGI::Session>'s functionality available in your program do either of the following somewhere on top of your program file:
+=item *
- use CGI::Session;
- # or
- require CGI::Session;
+L<DB_File|CGI::Session::DB_File> - for storing session data in BerkelyDB. Requires: L<DB_File>. Full name: B<CGI::Session::DB_File>
-Whenever you're ready to create a new session in your application, do the following:
+=item *
- $session = new CGI::Session() or die CGI::Session->errstr;
+L<MySQL|CGI::Session::MySQL> - for storing session data in MySQL tables. Requires L<DBI|DBI> and L<DBD::mysql|DBD::mysql>. Full name: B<CGI::Session::MySQL>
-Above line will first try to re-initialize an existing session by consulting cookies and necessary QUERY_STRING parameters. If it fails will create a brand new session with a unique ID, which is normally called I<session ID>, I<SID> for short, and can be accessed through L<id()|CGI::Session/id()> - object method.
+=back
-We didn't check for any session cookies above, did we? No, we didn't, but CGI::Session did. It looked for a cookie called C<CGISESSID>, and if it found it tried to load existing session from server side storage (B<file> in our case). If cookie didn't exist it looked for a QUERY_STRING parameter called C<CGISESSID>. If all the attempts to recover session ID failed, it created a new session.
+Note: You can also write your own driver for the library. Consult respective
+section of this manual for details.
-NOTE: For the above syntax to work as intended your application needs to have write access to your computer's I<TEMPDIR> folder, which is usually F</tmp> in UNIX. If it doesn't, or if you wish to store this application's session files in a different place, you may pass the third argument like so:
+=head1 CREATING NEW SESSION
- $session = new CGI::Session(undef, undef, {Directory=>'../tmp/sessions'});
+To generate a brand new session for a user, just pass an undefined value as the second argument to the constructor - new():
-Now it will store all the newly created sessions in (and will attempt to initialize requested sessions from) that folder. Don't worry if the directory hierarchy you want to use doesn't already exist. It will be created for you. For details on how session data are stored refer to L<CGI::Session::Driver::file|CGI::Session::Driver::file>, which is the default driver used in our above example.
+ $session = new CGI::Session("driver:File", undef, {Directory=>"/tmp"});
-There is one small, but very important thing your application needs to perform after creating CGI::Session object as above. It needs to drop Session ID as an I<HTTP cookie> into the user's computer. CGI::Session will use this cookie to identify the user at his/her next request and will be able to load his/her previously stored session data.
+Directory refers to a place where the session files and their locks will be stored in the form of separate files. When you generate the session object, as we did above, you will have:
-To make sure CGI::Session will be able to read your cookie at next request you need to consult its C<name()> method for cookie's suggested name:
+=over 4
- $cookie = $query->cookie( -name => $session->name,
- -value => $session->id );
- print $query->header( -cookie=>$cookie );
+=item 1
-C<name()> returns C<CGISESSID> by default. If you prefer a different cookie name, you can change it as easily too, but you have to do it before CGI::Session object is created:
+Session ID generated for you and
- CGI::Session->name("SID");
- $session = new CGI::Session();
+=item 2
-Baking the cookie wasn't too difficult, was it? But there is an even easier way to send a cookie using CGI::Session:
+Storage file associated with the id in the directory you specified.
- print $session->header();
+=back
-The above will create the cookie using L<CGI::Cookie|CGI::Cookie> and will return proper http headers using L<CGI.pm|CGI>'s L<CGI|CGI/header()> method. Any arguments to L<CGI::Session|CGI::Session/header()> will be passed to L<CGI::header()|CGI/header()>.
+From now on, in case you want to access the newly generated session id just do:
-Of course, this method of initialization will only work if client is accepting cookies. If not you would have to pass session ID in each URL of your application as QUERY_STRING. For CGI::Session to detect it the name of the parameter should be the same as returned by L<name()|CGI::Session/name()>:
+ $sid = $session->id();
- printf ("<a href=\"$ENV{SCRIPT_NAME}?%s=%s\">click me</a>", $session->name, $session->id);
+It returns a string something similar to B<a983c8302e7a678a2e53c65e8bd3316> which you can now send as a cookie or use as a query string or in your forms' hidden fields. Using standard L<CGI> library we can send the session id as a cookie to the user's browser like so:
-If you already have session id to be initialized you may pass it as the only argument, or the second argument of multi-argument syntax:
+ $cookie = $cgi->cookie(CGISESSID => $session->id);
+ print $cgi->header( -cookie=>$cookie );
- $session = new CGI::Session( $sid );
- $session = new CGI::Session( "serializer:freezethaw", $sid );
- $session = new CGI::Session( "driver:mysql", $sid, {Handle=>$dbh} );
+If anything in the above example doesn't make sense, please consult L<CGI> for the details.
-By default CGI::Session uses standard L<CGI|CGI> to parse queries and cookies. If you prefer to use a different, but compatible object you can pass that object in place of $sid:
+=head2 INITIALIZING EXISTING SESSIONS
- $cgi = new CGI::Simple();
- $session = new CGI::Session ( $cgi );
- $session = new CGI::Session( "driver:db_file;serializer:storable", $cgi);
- # etc
+When a user clicks another link or re-visits the site after a short while should we be creating a new session again? Absolutely not. This would defeat the whole purpose of state maintenance. Since we already send the id as a cookie, all we need is to pass that id as the seconds argument while creating a session object:
-See L<CGI::Simple|CGI::Simple>
+ $sid = $cgi->cookie("CGISESSID") || undef;
+ $session = new CGI::Session(undef, $sid, {Directory=>'/tmp'});
-=head2 STORING DATA
+The above syntax will first try to initialize an existing session data, if it fails ( if the session doesn't exist ) creates a new session: just what we want. But what if the user doesn't support cookies? In that case we would need to append the session id to all the urls as a query string, and look for them in addition to cookie:
-L<CGI::Session|CGI::Session> offers L<param() method|CGI::Session/param()>, which behaves exactly as L<CGI.pm's param()|CGI/param()> with identical syntax. L<param()|CGI::Session/param()> is used for storing data in session as well as for accessing already stored data.
+ $sid = $cgi->cookie('CGISESSID') || $cgi->param('CGISESSID') || undef;
+ $session = new CGI::Session(undef, $sid, {Directory=>'/tmp'});
-Imagine your customer submitted a login form on your Web site. You, as a good host, wanted to remember the guest's name, so you can a) greet him accordingly when he visits your site again, or b) to be helpful by filling out I<user name> part of his login form, so the customer can jump right to the I<password> field without having to type his username again.
+Assuming you have CGI object handy, you can minimize the above two lines into one:
- my $name = $cgi->param('username');
- $session->param('username', $name);
+ $session = new CGI::Session(undef, $cgi, {Directory=>"/tmp"});
-Notice, we're grabbing I<username> value of the field using CGI.pm's (or another compatible library's) C<param()> method, and storing it in session using L<CGI::Session|CGI::Session>'s L<param()|CGI::Session/param()> method.
+If you pass an object, instead of a string as the second argument, as we did above, CGI::Session will try to retrieve the session id from either the cookie or query string and initialize the session accordingly. Name of the cookie and query string parameters are assumed to be B<CGISESSID> by default. To change this setting, you will need to invoke C<name()> class method on either CGI::Session or its object:
-If you have too many stuff to transfer into session, you may find yourself typing the above code over and over again. I've done it, and believe me, it gets very boring too soon, and is also error-prone. So we introduced the following handy method:
+ CGI::Session->name("MY_SID");
+ # or
+ $session->name("MY_SID");
- $session->save_param(['name']);
+ $session = new CGI::Session(undef, $cgi, {Directory=>'/tmp'});
-If you wanted to store multiple form fields just include them all in the second list:
+=head2 STORING DATA IN THE SESSION
- $session->save_param(['name', 'email']);
+To store a single variable in the object use C<param()> method:
-If you want to store all the available I<QUERY_STRING> parameters you can omit the arguments:
+ $session->param("my_name", $name);
- $session->save_param();
+You can use C<param()> method to store complex data such as arrays, hashes, objects and so forth. While storing arrays and hashes, make sure to pass them as a reference:
-See L<save_param()|CGI::Session/save_param> for more details.
+ @my_array = ("apple", "grapes", "melon", "casaba");
+ $session->param("fruits", \@my_array);
-When storing data in the session you're not limited to strings. You can store arrays, hashes and even most objects. You will need to pass them as references (except objects).
+You can store objects as well:
-For example, to get all the selected values of a scrolling list and store it in the session:
+ $session->param("cgi", $cgi); # stores CGI.pm object
- my @fruits = $cgi->param('fruits');
- $session->param('fruits', \@fruits);
+Sometimes you wish there was a way of storing all the CGI parameters in the session object. You would start dreaming of this feature after having to save dozens of query parameters from each form element to your session object. Consider the following syntax:
-For parameters with multiple values save_param() will do the right thing too. So the above is the same as:
+ $session->save_param($cgi, ["keyword", "category", "author", "orderby"]);
- $session->save_param($cgi, ['fruits']);
+save_param() makes sure that all the above CGI parameters get saved in the session object. It's the same as saying:
-All the updates to the session data using above methods will not reflect in the data store until your application exits, or C<$session> goes out of scope. If, for some reason, you need to commit the changes to the data store before your application exits you need to call L<flush()|CGI::Session/flush()> method:
+ $session->param("keyword", $cgi->param("keyword"));
+ $session->param("category", $cgi->param("category"));
+ # etc... for all the form elements
- $session->flush();
+In case you want to save all the CGI parameters. Just omit the second argument to C<save_param()>:
-I've written a lot of code, and never felt need for using C<flush()> method, since CGI::Session calls this method at the end of each request. There are, however, occasions I can think of one may need to call L<flush()|CGI::Session/flush()>.
+ $session->save_param($cgi);
-=head2 ACCESSING STORED DATA
+The above syntax saves all the available/accessible CGI parameters
-There's no point of storing data if you cannot access it. You can access stored session data by using the same L<param() method|CGI::Session/param()> you once used to store them. Remember the Username field from the previous section that we stored in the session? Let's read it back so we can partially fill the Login form for the user:
+=head2 ACCESSING STORED DATA
- $name = $session->param("name");
- printf "<input type=\"text\" name=\"name\" value=\"%s\" />", $name;
+There's no point of storing data if you cannot access it. You can access stored session data by using the same C<param()> method you once used to store them:
-To retrieve previously stored @fruits do not forget to de reference it:
+ $name = $session->param("my_name");
- @fruits = @{ $session->param('fruits') };
+Above form of param() retrieves session parameter previously stored as "my_name". To retrieve previously stored @my_array:
-Very frequently, you may find yourself having to create pre-filled and pre-selected forms, like radio buttons, checkboxes and drop down menus according to the user's preferences or previous action. With text and textareas it's not a big deal - you can simply retrieve a single parameter from the session and hard code the value into the text field. But how would you do it when you have a group of radio buttons, checkboxes and scrolling lists? For this purpose, CGI::Session provides L<load_param()|CGI::Session/load_param()> method, which loads given session parameters to a CGI object (assuming they have been previously saved with L<save_param()|CGI::Session/save_param()> or alternative):
+ $my_array = $session->param("fruits");
- $session->load_param($cgi, ["fruits"]);
+It will return a reference to the array, and can be dereferenced as @{$my_array}.
-Now when you say:
+Very frequently, you may find yourself having to create a pre-filled and pre-selected forms, like radio buttons, checkboxes and drop down menus according to the user's preferences or previous action. With text and textareas it's not a big deal: you can simply retrieve a single parameter from the session and hardcode the value into the text field. But how would you do it when you have a group of radio buttons, checkboxes and scrolling lists? For this purpose, CGI::Session provides load_param() method, which loads given session parameters to a CGI object (assuming they have been previously saved with save_param() method or alternative):
- print $cgi->checkbox_group(fruits=>['apple', 'banana', 'apricot']);
+ $session->load_param($cgi, ["fruits"]);
-See L<load_param()|CGI::Session/load_param()> for details.
+Now you can use CGI.pm to generate those preselected checkboxes:
-Generated checkboxes will be pre-filled using previously saved information. To see example of a real session-powered application consider http://handalak.com/cgi-bin/subscriptions.cgi
+ print $cgi->checkbox_group(fruits=>['apple', 'banana', 'appricot']);
-If you're making use of L<HTML::Template|HTML::Template> to separate the code from the skin, you can as well associate L<CGI::Session|CGI::Session> object with HTML::Template and access all the parameters from within HTML files. We love this trick!
+If you're making use of HTML::Template to separate the code from the skins, you can as well associate CGI::Session object with HTML::Template and access all the parameters from within HTML files. We love this trick!
$template = new HTML::Template(filename=>"some.tmpl", associate=>$session);
print $template->output();
@@ -228,11 +233,23 @@
Hello <a href="mailto:<TMPL_VAR email>"> <TMPL_VAR first_name> </a>!
-See L<HTML::Template's online manual|HTML::Template> for details.
+For more tricks with HTML::Template, please refer to the library's manual (L<HTML::Template>) and L<CGI Session CookBook|CGI::Session::CookBook>.
+
+=head2 CLOSING THE SESSION
+
+Normally you don't have to close the session explicitly. It gets closed when your program terminates or session object goes out of scope. However in some few instances you might want to close the session explicitly by calling CGI::Session's C<close()> method or undefining the object. What is closing all about - you'd ask. While session is active, updates to session object doesn't get stored in the disk right away. It stores them in the memory until you either choose to flush the buffer by calling C<flush()> method or destroy the session object by either terminating the program or calling close() method explicitly.
+
+In some circumstances you might want to close the session but at the same time don't want to terminate the process for a while. Might be the case with GUI and in daemon applications. In this case close() is what you want. Note: we prefer simpl undefing the session rather than calling close() method. close() is less efficient):
+
+ undef($session);
+
+If you want to keep the session object but for any reason want to synchronize the data in the buffer with the one in the disk, C<flush()> method is what you need.
+
+Note: close() calls flush() as well. So there's no need to call flush() before calling close()
=head2 CLEARING SESSION DATA
-You store session data, you access session data and at some point you will want to clear certain session data, if not all. For this purpose L<CGI::Session|CGI::Session> provides L<clear()|CGI::Session/clear()> method which optionally takes one argument as an arrayref indicating which session parameters should be deleted from the session object:
+You store session data, you access session data and at some point you will want to clear certain session data, if not all. For this purpose CGI::Session provides C<clear()> method which optionally takes one argument as an arrayref indicating which session parameters should be deleted from the session object:
$session->clear(["~logged-in", "email"]);
@@ -240,9 +257,7 @@
$email = $session->param("email");
-it returns undef. If you omit the argument to L<clear()|CGI::Session/clear()>, be warned that all the session parameters you ever stored in the session object will get deleted. Note that it does not delete the session itself. Session stays open and accessible. It's just the parameters you stored in it gets deleted
-
-See L<clear()|CGI::Session/clear()> for details.
+it returns undef. If you omit the argument to C<clear()>, be warned that all the session parameters you ever stored in the session object will get deleted. Note that it does not delete the session itself. Session stays open and accessible. It's just the parameters you stored in it gets deleted
=head2 DELETING A SESSION
@@ -250,108 +265,242 @@
$session->delete();
-The above call to L<delete()|CGI::Session/delete()> deletes the session from the disk for good. Do not confuse it with L<clear()|CGI::Session/clear()>, which only clears certain session parameters but keeps the session open.
-
-See L<delete()|CGI::Session/delete()> for details.
+The above call to C<delete()> deletes the session from the disk for good. Do not confuse it with C<clear()>, which only clears certain session parameters but keeps the session open.
=head2 EXPIRATION
-L<CGI::Session|CGI::Session> provides limited means to expire sessions. Expiring a session is the same as deleting it via delete(), but deletion takes place automatically. To expire a session, you need to tell the library how long the session would be valid after the last access time. When that time is met, CGI::Session refuses to retrieve the session. It deletes the session and returns a brand new one. To assign expiration ticker for a session, use L<expire()|CGI::Session/expire()>:
+CGI::Session also provides limited means to expire session data. Expiring session is the same as deleting it via delete(), but deletion takes place automaticly. To expire a session, you need to tell the library how long the session would be valid after the last access time. When that time is met, CGI::Session refuses to retrieve the session. It deletes the session and returns a brand new one. To assign expiration ticker for a session, use the expire() method:
$session->expire(3600); # expire after 3600 seconds
$session->expire('+1h'); # expire after 1 hour
$session->expire('+15m'); # expire after 15 minutes
$session->expire('+1M'); # expire after a month and so on.
-When session is set to expire at some time in the future, but session was not requested at or after that time has passed it will remain in the disk. When expired session is requested CGI::Session will remove the data from disk, and will initialize a brand new session.
+But sometimes, it makes perfect sense to expire a certain session parameter, instead of the whole session. The author usually does this in his login/authentication enabled sites, where after the user logs in successfully, sets a "_logged_in" flag to true, and assigns an expiration ticker on that flag to something like 30 minutes. It means, after 30 idle minutes CGI::Session will clear() "_logged_in" flag, indicating the user should log in over again. I aggree, the same effect can be achieved by simply expiring() the session itself, but in thise we would loose other session parameters, such as user's shopping cart, session-preferences and the like.
-See L<expire()|CGI::Session/expire()> for details.
+This feature can also be used to simulate layered security/authentication, such as, you can keep the user's access to his/her personal profile information for as long as 10 idle hours after successful login, but expire his/her access to his credit card information after 10 idle minutes. To achieve this effect, we will use expire() method again, but with a slightly different syntax:
-Before CGI::Session 4.x there was no way of intercepting requests to expired sessions. CGI::Session 4.x introduced new kind of constructor, L<load()|CGI::Session/load()>, which is identical in use to L<new()|CGI::Session/new()>, but is not allowed to create sessions. It can only load them. If session is found to be expired, or session does not exist it will return an empty CGI::Session object. And if session is expired, in addition to being empty, its status will also be set to expired. You can check against these conditions using L<empty()|CGI::Session/empty()> and L<is_expired()|CGI::Session/is_expired()> methods. If session was loaded successfully object returned by C<load()> is as good a session as the one returned by C<new()>:
+ $session->expire(_profile_access, '+10h');
+ $session->expire(_cc_access, '+10m');
- $session = CGI::Session->load() or die CGI::Session->errstr;
- if ( $session->is_expired ) {
- die "Your session expired. Please refresh your browser to re-start your session";
- }
- if ( $session->is_empty ) {
- $session = $session->new();
- }
+With the above syntax, the person will still have access to his personal information even after 5 idle hours. But when he tries to access or update his/her credit card information, he may be displayed a "login again, please" screen.
-Above example is worth an attention. Remember, all expired sessions are empty sessions, but not all empty sessions are expired sessions. Following this rule we have to check with C<is_expired()> before checking with C<is_empty()>. There is another thing about the above example. Notice how its creating new session when un existing session was requested? By calling C<new()> as an object method! Handy thing about that is, when you call C<new()> on a session object new object will be created using the same configuration as the previous object.
+This concludes our discussion of CGI::Session programming style for now (at least till the new releases of the library ). The rest of the manual covers some L<"SECUIRITY"> issues and L<"DRIVER SPECIFICATIONS"> for those want to implement their own drivers or understand the library architecture.
-For example:
+=head1 SECURITY
- $session = CGI::Session->load("driver:mysql;serializer:storable", undef, {Handle=>$dbh});
- if ( $session->is_expired ) {
- die "Your session is expired. Please refresh your browser to re-start your session";
- }
- if ( $session->is_empty ) {
- $session = $session->new();
- }
+"How secure is using CGI::Session?", "Can others hack down people's sessions using another browser if they can get the session id of the user?", "Are the session ids guessable?" are the questions I find myself answering over and over again.
-Initial C<$session> object was configured with B<mysql> as the driver, B<storable> as the serializer and B<$dbh> as the database handle. Calling C< new() > on this object will return an object of the same configuration. So C< $session > object returned from C< new() > in the above example will use B<mysql> as the driver, B<storable> as the serializer and B<$dbh> as the database handle.
+=head2 STORAGE
-See L<is_expired()|CGI::Session/is_expired()>, L<is_empty()|CGI::Session/is_empty()>, L<load()|CGI::Session/load()> for details.
+Security of the library does in many aspects depend on the implementation. After making use of this library, you no longer have to send all the information to the user's cookie except for the session id. But, you still have to store the data in the server side. So another set of questions arise, can an evil person have access to session data in your server, even if they do, can they make sense out of the data in the session file, and even if they can, can they reuse the information against a person who created that session. As you see, the answer depends on yourself who is implementing it.
-Sometimes it makes perfect sense to expire a certain session parameter, instead of the whole session. I usually do this in my login enabled sites, where after the user logs in successfully, I set his/her "_logged_in" session parameter to true, and assign an expiration ticker on that flag to something like 30 minutes. It means, after 30 idle minutes CGI::Session will L<clear|CGI::Session/clear()> "_logged_in" flag, indicating the user should log in over again. I agree, the same effect can be achieved by simply expiring() the session itself, but by doing this we would loose other session parameters, such as user's shopping cart, session-preferences and the like.
+First rule of thumb, do not save the users' passwords or other sensitive data in the session. If you can persuade yourself that this is necessary, make sure that evil eyes don't have access to session files in your server. If you're using RDBMS driver such as MySQL, the database will be protected with a username/password pair. But if it will be storing in the file system in the form of plain files, make sure no one except you can have access to those files.
-This feature can also be used to simulate layered authentication, such as, you can keep the user's access to his/her personal profile information for as long as 60 minutes after a successful login, but expire his/her access to his credit card information after 5 idle minutes. To achieve this effect, we will use L<expire()|CGI::Session/expire()> method again:
+Default configuration of the driver makes use of Data::Dumper class to serialize data to make it possible to save it in the disk. Data::Dumper's result is a human readable data structure, which if opened, can be interpreted against you. If you configure your session object to use either Storable or FreezeThaw as a serializer, this would make more difficult for bad guys to make sense out of session data. But don't use this as the only precaution for security. Since evil fingers can type a quick program using Storable or FreezeThaw which deciphers that session file very easily.
- $session->expire(_profile_access, '1h');
- $session->expire(_cc_access, '5m');
+Also, do not allow sick minds to update the contents of session files. Of course CGI::Session makes sure it doesn't happen, but your cautiousness does no harm either.
-With the above syntax, the person will still have access to his personal information even after 5 idle hours. But when he tries to access or update his/her credit card information, he may be displayed a "login again, please" screen.
+Do not keep sessions open with sensitive information for very long period. This will increase the possibility that some bad guy may have someone's valid session id at a given time (acquired somehow).
-See L<expire()|CGI::Session/expire()> for details.
+ALWAYS USE "-ip-match" SWITCH!!!
-This concludes our discussion of CGI::Session programming style. The rest of the manual covers some L<"SECURITY"> issues. Driver specs from the previous manual were moved to L<CGI::Session::Driver|CGI::Session::Driver>.
+Read on for the details of "-ip-match".
-=head1 SECURITY
+=head2 SESSION IDs
-"How secure is using CGI::Session?", "Can others hack down people's sessions using another browser if they can get the session id of the user?", "Are the session ids easy to guess?" are the questions I find myself answering over and over again.
+Session ids are not easily guessable (unless you're using Incr Id generator)! Default configuration of CGI::Session uses Digest::MD5 which takes process id, time in seconds since epoch and a random number, generates a 32 character long digest out of it. Although this string cannot be guessable by others, if they find it out somehow, can they use this identifier against the other person?
-=head2 STORAGE
+Consider the scenario, where you just give someone either via email or an instant messaging a link to your online-account profile, where you're currently logged in. The URL you give to that person contains a session id as part of a query string. If the site was initializing the session solely using query string parameter, after clicking on that link that person now appears to that site as you, and might have access to all of your private data instantly. How scary and how unwise implementation. And what a poor kid who didn't know that pasting URLs with session ids could be an accident waiting to happen.
+
+Even if you're solely using cookies as the session id transporters, it's not that difficult to plant a cookie in the cookie file with the same id and trick the web browser to send that particular session id to the server. So key for security is to check if the person who's asking us to retrieve a session data is indeed the person who initially created the session data. CGI::Session helps you to watch out for such cases by enabling "-ip_match" switch while "use"ing the library:
+
+ use CGI::Session qw/-ip-match/;
+
+or alternatively, setting $CGI::Session::IP_MATCH to a true value, say to 1. This makes sure that before initializing a previously stored session, it checks if the ip address stored in the session matches the ip address of the user asking for that session. In which case the library returns the session, otherwise it dies with a proper error message.
+
+=head1 DRIVER SPECIFICATIONS
+
+This section is for driver authors who want to implement their own storing mechanism for the library. Those who enjoy sub-classing stuff should find this section useful as well. Here we discuss the architecture of CGI::Session and its drivers.
+
+=head2 LIBRARY OVERVIEW
-Security of the library does in many aspects depend on the implementation. After making use of this library, you no longer have to send all the information to the user's cookie except for the session id. But, you still have to store the data in the server side. So another set of questions arise, can an evil person get access to session data in your server, even if he does, can he make sense out of the data in the session file, and even if he can, can he reuse the information against a person who created that session. As you see, the answer depends on yourself who is implementing it.
+Library provides all the base methods listed in the L<METHODS> section. The only methods CGI::Session doesn't bother providing are the ones that need to deal with writing the session data in the disk, retrieving the data from the disk, and deleting the data. These are the methods specific to the driver, so that's where they should belong.
+
+In other words, driver is just another Perl library which uses CGI::Session as a base class, and provides several additional methods that deal with disk access.
+
+=head2 SERIALIZATION
+
+Before getting to driver specs, let's talk about how the data should be stored. When flush() is called, or the program terminates, CGI::Session asks a driver to store the data somewhere in the disk, and passes the data in the form of a hash reference. Then it's the driver's obligation to serialize the data so that it can be stored in the disk.
+
+Although you are free to implement your own serializing engine for your driver, CGI::Session distribution comes with several libraries you can inherit from and call freeze() method on the object to serialize the data and store it. Those libraries are:
=over 4
-=item *
+=item L<CGI::Session::Serialize::Default|CGI::Session::Serialize::Default>
-First rule of thumb, do not store users' passwords or other sensitive data in the session, please. If you have to, use one-way encryption, such as md5, or SHA-1-1. For my own experience I can assure you that in properly implemented session-powered Web applications there is never a need for it.
+=item L<CGI::Session::Serialize::Storable|CGI::Session::Serialize::Storable>
-=item *
+=item L<CGI::Session::Serialize::FreezeThaw|CGI::Session::Serialize::FreezeThaw>
-Default configuration of the driver makes use of L<Data::Dumper|Data::Dumper> class to serialize data to make it possible to save it in the disk. Data::Dumper's result is a human readable data structure, which, if opened, can be interpreted easily. If you configure your session object to use either L<Storable|CGI::Session::Serialize::storable> or L<FreezeThaw|CGI::Session::Serialize::freezethaw> as a serializer, this would make it more difficult for bad guys to make sense out of session data. But don't use this as the only precaution. Since evil fingers can type a quick program using L<Storable|Storable> or L<FreezeThaw|FreezeThaw> to decipher session files very easily.
+=back
-=item *
+Example:
-Do not allow anyone to update contents of session files. If you're using L<default serializer|CGI::Session::Serialize::default> serialized data string needs to be eval()ed to bring the original data structure back to life. Of course, we use L<Safe|Safe> to do it safely, but your cautiousness does no harm either.
+ # $data is a hashref that needs to be stored
+ my $storable_data = $self->freeze($data)
-=item *
+$storable_data can now be saved in the disk safely.
+
+When the driver is asked to retrieve the data from the disk, that serialized data should be accordingly de-serialized. The aforementioned serializers also provides thaw() method, which takes serialized data as the first argument and returns Perl data structure, as it was before saved. Example:
+
+ my $hashref = $self->thaw($stored_data);
+
+=head2 DRIVER METHODS
+
+Driver is just another Perl library, which uses CGI::Session as a base class and is required to provide the following methods:
+
+=over 4
+
+=item C<retrieve($self, $sid, $options)>
-Do not keep sessions open for very long. This will increase the possibility that some bad guy may have someone's valid session id at a given time (acquired somehow). To do this use L<expire()|CGI::Session/expire()> method to set expiration ticker. The more sensitive the information on your Web site is, the sooner the session should be set to expire.
+retrieve() is called by CGI::Session with the above 3 arguments when it's asked to retrieve the session data from the disk. $self is the session object, $sid is the session id, and $options is the list of the arguments passed to new() in the form of a hashref. Method should return un-serialized session data, or undef indicating the failure. If an error occurs, instead of calling die() or croak(), we suggest setting the error message to error() and returning undef:
+
+ unless ( sysopen(FH, $options->{FileName}, O_RDONLY) ) {
+ $self->error("Couldn't read from $options->{FileName}: $!");
+ return undef;
+ }
+
+If the driver detects that it's been asked for a non-existing session, it should not generate any error message, but simply return undef. This will signal CGI::Session to create a new session id.
+
+=item C<store($self, $sid, $options, $data)>
+
+store() is called by CGI::Session when session data needs to be stored. Data to be stored is passed as the third argument to the method, and is a reference to a hash. Should return any true value indicating success, undef otherwise. Error message should be passed to error().
+
+=item C<remove($self, $sid, $options)>
+
+remove() called when CGI::Session is asked to remove the session data from the disk via delete() method. Should return true indicating success, undef otherwise, setting the error message to error()
+
+=item C<teardown($self, $sid, $options)>
+
+called when session object is about to get destroyed, either explicitly via close() or implicitly when the program terminates
=back
-=head2 SESSION IDs
+=head2 GENERATING ID
+
+CGI::Session also requires the driver to provide a generate_id() method, which returns an id for a new session. Again, you are welcome to re-invent your own wheel, but note, that CGI::Session distribution comes with couple of id generating libraries that provide you with generate_id(). You should simply inherit from them. Following ID generators are available:
+
+=over 4
+
+=item L<CGI::Session::ID::MD5|CGI::Session::ID::MD5>
+
+=item L<CGI::Session::ID::Incr|CGI::Session::ID::Incr>
+
+=back
-Session ids are not easily guessed (unless you're using L<incr ID generator|CGI::Session::ID::incr>)! Default configuration of CGI::Session uses L<Digest::MD5|CGI::Session::ID::md5> to generate random, 32 character long identifier. Although this string cannot be guessed as easily by others, if they find it out somehow, can they use this identifier against the other person?
+Refer to their respective manuals for more details.
-Consider the scenario, where you just give someone either via email or an instant messaging a link to a Web site where you're currently logged in. The URL you give to that person contains a session id as part of a query string. If the site was initializing the session solely using query string parameter, after clicking on that link that person now appears to that site as you, and might have access to all of your private data instantly.
+In case you want to have your own style of ids, you can define a generate_id() method explicitly without inheriting from the above libraries. Or write your own B<CGI::Session::ID::YourID> library, that simply defines "generate_id()" method, which returns a session id, then give the name to the constructor as part of the DSN:
-Even if you're solely using cookies as the session id transporters, it's not that difficult to plant a cookie in the cookie file with the same id and trick the web browser to send that particular session id to the server. So key for security is to check if the person who's asking us to retrieve a session data is indeed the person who initially created the session data.
+ $session = new CGI::Session("id:YourID", undef, {Neccessary=>Attributes});
-One way to help with this is by also checking that the IP address that the session is being used from is always same. However, this turns out not to be practical in common cases because some large ISPs (such as AOL) use proxies which cause each and every request from the same user to come from different IP address.
+=head2 BLUEPRINT
-If you have an application where you are sure your users' IPs are constant during a session, you can consider enabling an option to make this check:
+Your CGI::Session distribution comes with a Session/Blueprint.pm file
+which can be used as a starting point for your driver:
- use CGI::Session ( '-ip_match' );
+ package CGI::Session::BluePrint;
-For backwards compatibility, you can also achieve this by setting $CGI::Session::IP_MATCH to a true value. This makes sure that before initializing a previously stored session, it checks if the ip address stored in the session matches the ip address of the user asking for that session. In which case the library returns the session, otherwise it dies with a proper error message.
+ use strict;
+ use base qw(
+ CGI::Session
+ CGI::Session::ID::MD5
+ CGI::Session::Serialize::Default
+ );
-=head1 LICENSING
+ # Load neccessary libraries below
-For support and licensing see L<CGI::Session|CGI::Session>
+ use vars qw($VERSION);
+
+ $VERSION = '0.1';
+
+ sub store {
+ my ($self, $sid, $options, $data) = @_;
+
+ my $storable_data = $self->freeze($data);
+
+ #now you need to store the $storable_data into the disk
+ }
+
+ sub retrieve {
+ my ($self, $sid, $options) = @_;
+
+ # you will need to retrieve the stored data, and
+ # deserialize it using $self->thaw() method
+ }
+
+ sub remove {
+ my ($self, $sid, $options) = @_;
+
+ # you simply need to remove the data associated
+ # with the id
+ }
+
+
+
+ sub teardown {
+ my ($self, $sid, $options) = @_;
+
+ # this is called just before session object is destroyed
+ }
+
+ 1;
+
+ __END__;
+
+
+After filling in the above blanks, you can do:
+
+ $session = new CGI::Session("driver:MyDriver", $sid, {Option=>"Value"});
+
+and follow CGI::Session manual.
+
+
+=head1 COPYRIGHT
+
+Copyright (C) 2002 Sherzod Ruzmetov. All rights reserved.
+
+This library is free software. You can modify and distribute it under the same terms as Perl itself.
+
+=head1 AUTHOR
+
+Sherzod Ruzmetov <sherz****@cpan*****>. Suggestions, feedbacks and patches are welcome.
+
+=head1 SEE ALSO
+
+=over 4
+
+=item *
+
+L<CGI::Session|CGI::Session> - CGI::Session manual
+
+=item *
+
+L<CGI::Session::CookBook|CGI::Session::CookBook> - practical solutions for real life problems
+
+=item *
+
+B<RFC 2965> - "HTTP State Management Mechanism" found at ftp://ftp.isi.edu/in-notes/rfc2965.txt
+
+=item *
+
+L<CGI|CGI> - standard CGI library
+
+=item *
+
+L<Apache::Session|Apache::Session> - another fine alternative to CGI::Session
+
+=back
=cut