NAME
    CGI::Session - Perl extension for persistent session management

SYNOPSIS
        # OO interface
        use CGI::Session::File;
        use CGI;

        $cgi = new CGI;
        $sid = $cgi->cookie("SID") || $cgi->param("sid") || undef;
        $session = new CGI::Session::File($sid,
                    { Directory => "/tmp"  });

        # Let's update the session id:
        $sid = $session->id;

        # Let's get the first name of the user from the form
        # and save it in the session:
        $f_name = $cgi->param( "f_name" );
        $session->param( "f_name", $f_name );

        # Later we can just initialize the user's session
        # and retrieve his first name from session data:
        $f_name = $session->param( "f_name" );

        # tie() interface:
        use CGI::Session::File;
        use CGI;

        $cgi = new CGI;
        $sid = $cgi->cookie("SID") || $cgi->param("sid") || undef;
        tie %session, "CGI::Session::File", $sid,
                    { Directory => "/tmp" };

        # Let's update the session id:
        $sid = $session{ _session_id };

        # Let's get the first name of the user from the form
        # and save it in the session:
        $f_name = $cgi->param( "f_name" );
        $session{f_name} = $f_name;

        # Later we can just initialize the user's session
        # and retrieve his first name from session data:
        $f_name = $session{f_name};

        # Tricks are endless!

WARNING
    If you have a version prior to 2.91 please upgrade it to the latest
    release ASAP!

NOTE
    As of this release there seems to be two different CGI::Session
    libraries on CPAN. This manual refers to CGI::Session by Sherzod
    Ruzmetov

DESCRIPTION
    "CGI::Session" is Perl5 library that provides an easy persistent session
    management system across HTTP requests. Session persistence is a very
    important issue in web applications. Shopping carts, user-recognition
    features, login and authentication methods and etc. all require
    persistent session management mechanism, which is both secure and
    reliable. "CGI::Session" provides with just that. You can read the whole
    documentation as a tutorial on session management. But if you are
    already familiar with "CGI::Session" go to the methods section for the
    list of all the methods available.

INTERFACE
    As of version 2.6 CGI::Session offers two distinct interfaces: 1) Object
    Oriented and 2) tied hash access. In Object Oriented Interface you will
    first create an object of CGI::Session's derived class (driver) and
    manipulate session data by calling special methods. Usage of the library
    if similar to that of CGI.pm. Example:

        # Creating a new session object:
        $session = new CGI::Session::File(undef,
                            { Directory=>"/tmp" });

        print "Your session id is ", $session->id();

    In tied hash method, you will tie() a regular hash variable to the
    CGI::Session's derived class and from that point on you will be treating
    a session just as a hash variable. And Perl will do all other job for
    you transparently:

        # Creating a new session object:
        tie %session, "CGI::Session::File", undef, {
                            { Directory=>"/tmp" };

        print "Your session id is ", $session{_session_id};

    In the examples throughout the manual I will give syntax and notes for
    both interfaces wherever applicable. Which interface to use is totally
    up to you. I personally prefer Object Oriented Interface for it is full
    of features.

    Also, somewhere in this manual I will talk about the section on "SPECIAL
    NAMES" which are not accessible via "param()" method for neither writing
    nor reading. But this rule differs in tied hash access method, where all
    those the section on "SPECIAL NAMES" but few are writable

REFRESHER ON SESSION MANAGEMENT
    Since HTTP is a stateless protocol, web programs need a way of
    recognizing clients across different HTTP requests. Each click to a site
    by the same user is considered brand new request for your web
    applications, and all the state information from the previous requests
    are lost. These constraints make it difficult to write web applications
    such as shopping carts, users' browsing history, login/authentication
    routines, users' preferences among hundreds of others.

    But all of these constraints can be overcome by making use of
    CGI::Session

WORKING WITH SESSIONS
    Note: Before working with sessions, you will need to decide what kind of
    storage best suits your needs. If your application makes extensive use
    of MySQL, Oracle or other RDBMS, go with that storage. But plain file or
    DB_File should be adequate for almost all the situations. Examples in
    this manual will be using plain files as the session storage device for
    they are available for all the users. But you can choose any
    CGI::Session::* driver available.

  CREATING A NEW SESSION

    To create a new session, you will pass CGI::Session::File a false
    expression as the first argument:

        # OO interface
        $session = new CGI::Session::File(undef,
            {
                Directory    => "/tmp/sessions",
        });

        # tie() interface
        tie %session, "CGI::Session::File", undef, {
                Directory    => "/tmp/sessions"  };

    We're passing two arguments, the fist one is session id, which is
    undefined in our case, and the second one is the anonymous hash

        {
            Directory    => "/tmp/sessions",
        }

    which points to the locations where session files and their lock files
    should be created. You might want to choose a more secure location than
    I did in this example.

    Note: second hashref argument is dependant on the driver. Please check
    with the driver manual.

    If the session id is undefined, the library will generate a new id, and
    you can access it's value via id() method: (see methods)

        # OO:
        $sid = $session->id();

        # tie():
        $sid = $session{_session_id};

  INITIALIZING EXISTING SESSIONS

    We create new sessions when new visitors visit our site. What if they
    click on a link in our site, should we create another session again?
    Absolutely not! The sole purpose of the session management is to keep
    the session open as along as the user is surfing our site. Sometimes we
    might want to choose to keep the session for several days, weeks or
    months so that we can recognize the user and/or re-create his
    preferences if required.

    So how do we know if the user already opened a session or not? At their
    first visit, we should "mark" the users with the session id we created
    in the above example. So, how do we "mark" the user? There are several
    ways of "marking".

   IDENTIFYING THE USER VIA CGI QUERY

    One way of doing it is to append the session id to every single link in
    the web site:

        # get the session id...
        my $sid = $session->id();

        # printing the link
        print qq<a href="$ENV{SCRIPT_NAME}?sid=$sid">click here</a>~;

    When the user clicks on the link, we just check the value of "sid" CGI
    parameter. And if it exists, we consider it as an existing session id
    and pass it to the "CGI::Session"'s constructor:

        use CGI::Session::File;
        use CGI;

        my $cgi = new CGI;
        my $sid = $cgi->param("sid") || undef;
        my $session = new CGI::Session::File($sid,
            {
                Directory    => "/tmp/sessions"
            });

    If the "sid" CGI parameter is present, the "CGI::Session" will try to
    initialize the object with previously created session data. If "sid"
    parameter is not present in the URL, it will default to undef, forcing
    the "CGI::Session" to create a new session just like in our first
    example. Also, when the user is asked to submit a form, we should
    include the session id in the HIDDEN field of the form, so that it will
    be sent to the application and will be available via $cgi->param("sid")
    syntax: (see methods )

        # get the session id...
        my $sid = $session->id();

        # print the hidden field
        print qq~<input type="hidden" name="sid" value="$sid">~;

    This session management technique stays good as long as the user is
    browsing our site. What if the user clicks on an external link, or
    visits some other site before checking out his shopping cart? Then when
    he comes back to our site within next 5 minutes or so, he will be
    surprised to find out that his shopping cart is gone! Because when they
    visit the site next time by typing the URL, "sid" parameter will not be
    present in the URL, and our application will not recognize the user
    resulting in the creation of a new session id, and all the links in the
    web site will have that new session id appended to them. Too bad,
    because the client has to start everything over again.

   IDENTIFYING THE USER VIA COOKIES

    We can deal with the above problem by sending the client a cookie. This
    cookie will hold the session id only! Thus if the client visits some
    other site, or even closes the browser accidentally, we can still keep
    his session open till the next time he/she visits the site. While the
    implementation is concerned, it will not the different then the one
    above, with some minor changes:

        use constant SESSION_COOKIE => "MY_SITE_SID";

        use CGI::Session::File;
        use CGI;

        my $cgi = new CGI;
        my $sid = $cgi->cookie(SESSION_COOKIE) || undef;
        my $session = new CGI::Session::File($sid,
            {
                Directory    => "/tmp/sessions"
            });

        # now, do not forget to send the cookie back to the client:
        {
            my $cookie = $cgi->cookie(-name   => SESSION_COOKIE,
                                     -value  => $session->id,
                                     -expires=> "+1M");
            print $cgi->header(-cookie=>$cookie);
        }

    I can hear critics saying "what if the user disabled cookies? The above
    technique will fail!". Surprisingly, they are absolutely right. If the
    client disabled cookies in his/her browser (which is less likely) the
    above technique of ours is even worse than the previous one. It will not
    work AT ALL. So we should combine both of the techniques together. This
    will require the change only in one line from the above code:

        my $sid = $cgi->cookie(SESSION_COOKIE) || $cgi->param("sid") || undef;

    and the reset of the code stays the same. As you see, it will first try
    to get the session id from the cookie, if it does not exist, it will
    look for the "sid" parameter in the URL, and if that fails, then it will
    default to undef, which will force "CGI::Session" to create a new id for
    the client.

   IDENTIFYING THE USER VIA PATH_INFO

    The least common, but at the same time quite convenient way of "marking"
    users with a session id is appending the session id to the url of the
    script as a "PATH_INFO". "PATH_INFO" is somewhat similar to
    "QUERY_STRING", but unlike "QUERY_STRING" it does not come after the
    question mark ("?"), but it comes before it, and is separated from the
    script url with a slash ("/") just like a folder. Suppose our script
    resides in /cgi-bin/session.cgi. And after we append session id to the
    url as a "PATH_INFO" if will look something like:

        /cgi-bin/session.cgi/KUQa0zT1rY-X9knH1waQug

    and the query string would follow "PATH_INFO":

        /cgi-bin/session.cgi/KUQa0zT1rY-X9knH1waQug?_cmd=logout

    You can see examples of this in the examples section of the manual.

    And when it comes to initializing the session id from the "PATH_INFO",
    consider the following code:

        my ($sid) = $cgi->path_info =~ /\/([^\?\/]+)/;

        my $session = new CGI::Session::File($sid, {
                                            Directory    => "/tmp"});

    CGI.pm's "path_info()" method returns the PATH_INFO environmental
    variable with a leading slash ("/"). And we are using regex to get rid
    of the leading slash and retrieve the session id only. The rest of the
    code is identical to the previous examples.

  ERROR HANDLING

    "CGI::Session" itself never die()s (at least tries not to die), neither
    should its drivers. But the methods' return value indicates the
    success/failure of the call, and "$CGI::Session::errstr" global variable
    will be set to an error message in case something goes wrong. So you
    should always check the return value of the methods to see if they
    succeeded:

        my $session = new CGI::Session::File($sid,
            {
                Directory    => "/tmp/sessions"
            }) or die $CGI::Session::errstr;

  STORING DATA IN THE SESSION

    1   After you create a session id or initialize existing one you can now
        save data in the session using "param()" method: (see methods)

            $session->param('email', 'sherzodr@cpan.org');

        This will save the email address sherzodr@cpan.org in the "email"
        session parameter. A little different syntax that also allows you to
        do this is:

            $session->param(-name=>'email', -value=>'sherzodr@cpan.org');

            # tie() interface
            $session{email} = 'sherzodr@cpan.org';

    2   If you want to store more values in the same session parameter, you
        can pass a reference to an array or a hash. This is the most
        frequently exercised technique in shopping cart applications, or for
        storing users' browsing history. Here is the example where we store
        the user's shopping cart as a reference to a hash-table, keys
        holding the item name, and their values indicating the number of
        items in the cart. ( I would go with item id rather than item names,
        but we choose item names here to make the things clearer for the
        reader):

            # OO Interface
            $session->param(-name=>'cart', -value=>{
                                            "She Bang Hat"    => 1,
                                            "The Came T-shirt"=> 1,
                                            "Perl Mug"        => 2
                                           });

            # tie() Interface
            $session{cart} = {  "She Bang Hat"      => 1,
                                 "The Came T-shirt" => 1,
                                 "Perl Mug"         => 2 };

        the same assignment could be performed in the following two steps as
        well:

            my $cart = {
                "She Bang Hat"    => 1,
                "The Came T-shirt"=> 1,
                "Perl Mug"        => 2
            };

            # OO Interface
            $session->param(-name=>'cart', -value=>$cart);

            # tie() Interface
            $session{cart} = $cart;

    3   Sometimes, you want to store the contents of a form the user
        submitted, or want to copy the contents of the CGI query into the
        session object to be able to restore them later. For that purpose
        "CGI::Session" provides with "save_param()" method which does just
        that.

        Suppose, a user filled in lots of fields in an advanced search form
        in your web site. After he submits the form, you might want to save
        the generated CGI query (either via GET or POST method) into the
        session object, so that you can keep the forms filled in with the
        previously submitted data throughout his session. Here is the
        portion of the code after the user submits the form:

            # if the user submitted the form..
            if ( $cgi->param("_cmd") eq "search") {
                # save the generated CGI query in the session:
                $session->save_param($cgi);
            }

            # tie() Interface: n/a

        It means, if the search form had a text field with the name
        "keyword":

            <input type="textfield" name="keyword" />

        after calling save_param($cgi), the value of the text field will be
        available via the section on "$session-"param("keyword")|"METHODS">,
        and you can re-write the above text field like the following:

            my $keyword = $session->param("keyword");
            print qq~<INPUT TYPE="textfield" name="keyword" value="$keyword" />~;

    4   Sometimes you don't want to save all the CGI parameters, but want to
        pick from the list. save_param() method optionally accepts an
        arrayref as the second argument telling it which the CGI manpage
        parameters it should save in the session:

            $session->save_param($cgi, [ "keyword", "order_by",
                                         "order_type", "category" ]);

        Now only the above listed parameters will be saved in the session
        for future access. Inverse of the save_param() is load_param().

   SPECIAL NAMES

    When you create a fresh-blank session, it's not blank as it seems. It is
    initialized with the following 4 parameters, which are serialized
    together with other session data. We call these the section on "SPECIAL
    NAMES".

    *   "_session_id" - stores the ID of the session

    *   "_session_ctime" - stores the creation date of the session

    *   "_session_atime" - stores the last access time for the session

    *   "_session_etime" - stores expiration date for the session

    So you shouldn't be using parameter names with leading underscore,
    because "CGI::Session" preserves them for internal use. They are
    required for the library to function properly. Even though you try to do
    something like:

        $session->param(-name=>"_some_param", -value=>"Some value");

    "param()" returns "undef", indicating the failure and assigns the error
    message in the "$CGI::Session::errstr", which reads:

        Names with leading underscore are preserved for internal use by CGI::Session.
        _some_param - illegal name

    You cannot access these the section on "SPECIAL NAMES" directly via
    "param()" either, but you can do so by provided accessory methods,
    "id()", "ctime()", "atime()" and "expires()" (see methods).

    If you are using tied hash access interface, these rules differ
    slightly, where you can read all these name from the hash, but you can
    set only _session_etime and _session_atime names:

        printf ("Session last accessed on %s\n", localtime($session{_session_atime}));

        # updating last access time. You don't have to do it, it will be done
        # automatically though
        $session{_session_atime} = time();

        # setting expiration date, setting in 2 months
        $session{_session_etime} = "2M";

  ACCESSING SESSION DATA

    1   Now the client has to check the items out of his/her shopping cart,
        and we need to access our session parameters.

        The same method used for storing the data, param(), can be used to
        access them:

            my $login = $session->param("login");

        This example will get the user's login name from the previously
        stored session. This could be achieved with a slightly different
        syntax that "param()" supports:

            my $login = $session->param(-name=>"login");

        Which syntax to use is up to you! Now let's dump the user's shopping
        cart that was created earlier:

            # remember, it was a hashref?
            my $cart = $session->param(-name=>"cart");

            while ( my ($name, $qty) = each %{$cart} ) {
                print "Item: $name ($qty)", "<br />";
            }

    2   Another commonly usable way of accessing the session data is via
        "load_param()" method, which is the inverse of save_param(). This
        loads the parameters saved in the session object into the CGI
        object. It's very helpful when you want the CGI manpage object to
        have access to those parameters:

            $session->load_param($cgi);

        After the above line, CGI has access to all the session parameters.
        We talked about filling out the search form with the data user
        previously entered. But how can we present the user pre-checked
        group of radio buttons according to his/her previous selection? How
        about checkboxes or popup menus? This is quite challenging unless we
        call CGI library for help, which provides a sticky behavior for most
        of the form elements generated with CGI.pm

            # load the session parameters into the CGI object first:
            $session->load_param($cgi, ["checked_items"]);

            # now print the group of radio buttons,it CGI.pm will check them
            # according to the previously saved session data
            print $cgi->group_radio(-name=>"checked_items",
                                    -values => ["eenie", "meenie", "minie", "moe"]);

        Notice the second argument passed to the load_param(). In this case
        it is loading only the "checked_items" parameter from the session.
        If it were missing it would load the whole session data.

  CLEARING THE SESSION DATA

    When the user click on the "clear the cart" button or purchases the
    contents of the shopping cart, that's a clue that we have to clear the
    cart. "CGI::Session"'s clear() method deals with clearing the session
    data:

        # OO Interface
        $session->clear("cart");

        # tie() Interface
        delete $session{cart};

    What happens is, it deletes the given parameter from the session for
    good. If you do not pass any arguments to "clear()", then all the
    parameters of the session will be deleted. Remember that "clear()"
    method DOES NOT delete the session. Session stays open, only the
    contents of the session data will be deleted.

  DELETING THE SESSOIN

    If you want to delete the session for good together with all of its
    contents, then delete() method is the way to go. After you call this
    method, the "CGI::Session" will not have access to the pervious session
    at all, because it was deleted from the disk for good. So it will have
    to generate a new session id instead:

        # OO Interface
        $session->delete();

        # tie() Interface:
        tied(%session)->delete();

  CLEAR OR DELETE?

    So, should we delete() the session when the user finishes browsing the
    site or clicks on the "sign out" link? Or should we "clear()" it? And
    I'll answer the question with another question; bright mind should be
    able to see me through! If the user click on the "sign out" link, does
    it mean he is done browsing the site? Absolutely not. The user might
    keep surfing the site even after he signs out or clears his shopping
    cart. He might even continue his shopping after several hours, or
    several days. So for the comfort of the visitors of our site, we still
    should keep their session data at their fingertips, and only "clear()"
    unwanted session parameters, for example, the user's shopping cart,
    after he checks out. Sessions should be deleted if they haven't been
    accessed for a certain period of time, in which case we don't want
    unused session data occupying the storage in our disk.

  EXPIRING SESSIONS

    While I was coding this feature of the "CGI::Session", I wasn't quite
    sure how to implement auto-expiring sessions in more friendly way. So I
    decided to leave to the programmer implementing "CGI::Session" and
    introduced 3 brand new methods to the library, expires(), atime() and
    ctime();

    ctime() method returns the "time()" value when the session was created
    for the first time. the atime()"METHODS" entry elsewhere in this
    document method returns the "time()" value when then session data was
    accessed for the last time. If we use "expires()" without any arguments,
    it returns the time() value of the date when the session should expire.
    Returns undef if it's non-expiring session. If you use it with an
    argument, then it will set the expiration date for the session. For the
    list of possible arguments expires() expects, please check out the the
    section on "METHODS" section below.

    Remember, even though you set an expiration date, "CGI::Session 2.0"
    itself doesn't deal with expiring sessions, the above 3 method just
    provide you with all the required tools to implement your expiring
    sessions. I will put some more effort on this issue in the next releases
    of the library. But if you have any bright ideas or patches, scroll down
    to the the AUTHOR entry elsewhere in this document section and get in
    touch.

    The following script is best suited for a cron job, and will be deleting
    the sessions that haven't accessed for the last one year.

        use constant YEAR => 86400 * 365; # in seconds

        use CGI::Session::File;
        use IO::Dir;

        tie my %dir, "IO::Dir", "/tmp/sessions", DIR_UNLINK or die $!;

        my $session;
        my $options = {Directory=>"/tmp/sessions"};

        while ( my ($file, $info) = each %db ) {

            my ($sid) = $file =~ m/CGI-Session-([^\.]+)\.dat) or next;
            $session = CGI::Session::File->new($sid, $options);

            if ( (time - $session->atime) > YEAR ) {

                $session->delete();

            }
        }

        untie %dir;

EXAMPLES
  SESSION PREFERENCES

    This example will show how to remember users' preference/choices for the
    duration of their session while they are browsing the site.

    URL: http://modules.ultracgis.com/cgi-bin/session
    DESCRIPTION
        This example is marking the user both with a cookie and with a
        "PATH_INFO" appended to every url. Thus even though the application
        is at /cgi-bin/session, the url looks something like
        /cgi-bin/session/KUQa0zT1rY-X9knH1waQug?_cmd=profile, which tricks
        untrained eyes into thinking that "/cgi-bin/session" is a folder,
        and the script has a quite long and unpleasant name. But
        "CGI::Session" users should easily be able to guess that we're just
        appending a path to the url.

METHODS
    new()
        constructor method. Requires two arguments, first one is the session
        id the object has to initialize, and the second one is the hashref
        to driver specific options. If session is evaluates to "undef", the
        CGI::Session will generate a new session id stores it automatically.
        If defined session id is passed, but the library fails to
        initializes the object with that session, then new session will be
        created instead. If an error occurs either in storing the session in
        the disk, or retrieving the session from the disk, "new()" returns
        undef, and sets the error message in the "$CGI::Session::errstr"
        global variable. Example:

            use CGI::Session::DB_File;
            my $session = new CGI::Session::DB_File(undef,
                {
                    LockDirectory=>'/tmp',
                    FileName        => '/tmp/sessions.db'
            }) or die "Session couldn't be initialized: $CGI::Session::errstr";

    id()
        returns the session id for the current session.

    error()
        returns the error message. Works only after the session object was
        initialized successfully. Other times, please use
        "$CGI::Session::errstr" variable to access the error message

    param()
        the most important method of the library. It is used for accessing
        the session parameters, and setting their values. It supports
        several syntax, all of which are discussed here.

        *     "param()" - if passed no arguments, returns the list of all
              the existing session parameters

        *     "param("first_name")" returns the session value for the
              "first_name" parameter.

        *     "param(-name=>"first_name")" - the same as
              "param("first_name")", returns the value of "first_name"
              parameter

        *     "param("first_name", "Sherzod")" - assigns "Sherzod" to the
              "first_name" session parameter. Later you can retrieve the
              "first_name" with either "param("first_name")" or
              "param(-name=>"first_name")" syntax. Second argument can be
              either a string, or it can be reference to a more complex data
              structure like arrayref, hashref, or even a file handle.
              Example,

                  $session->param("shopping_cart_items", [1, 3, 66, 2, 43]);

              later, if you wish to retrieve the above arrayref form the
              "shopping_cart_items" parameter:

                  my $cart = $session->param("shopping_cart_items");

              now $cart holds "[1, 3, 66, 2, 43]".

        *     "param(-name=>"first_name", -value=>"Sherzod")" - the same as
              "param("first_name", "Sherzod")", assigns "Sherzod" to
              "first_name" parameter.

    save_param()
        Saves the CGI object parameters into the session object. It's very
        helpful if you want to save the user's form entries, like email
        address and/or username in the session, for later use. The first
        argument has to be a CGI.pm object as returned from the "CGI->new()"
        method, and the second argument (optional) is expected to be a
        reference to an array holding the names of CGI parameters that need
        to be saved in the session object. If the second argument is
        missing, it will save all the existing CGI parameters, skipping the
        ones that start with an underscore (_). Example,

            $session->save_param($cgi, ["login_name", "email_address"]);

        Now, if the user submitted the text field with his "login_name", his
        login is saved in our session already. Unlike CGI parameters,
        Session parameters do not disappear, they will be saved in the disk
        for a lot longer period unless you choose to delete them. So when
        the user is asked to login after several weeks, we just fill the
        login_name text field with the values of the field submitted when
        the user visited us previously. Example:

            # let's get his login_name which was saved via save_param() method:
            my $login_name = $session->param("login_name");

            # now let's present the text field with login_name already typed in:
            print $cgi->textfield(-name=>"login_name", -value=>$login_name);

    load_param()
        This is the opposite of the above "save_param()" method. It loads
        the previously saved session parameters into the CGI object. The
        first argument to the method has to be a CGI.pm object returned from
        CGI->new() method. The second argument, if exists, is expected to be
        a reference to an array holding the names of the parameters that
        need to be loaded to the CGI object. If the second argument is
        missing, it will load all the session parameters into the CGI
        object, skipping the ones that start with an underscore (_). If
        we're using CGI.pm to produce our HTML forms, the above example
        could also be written like the following:

            $session->load_param($cgi);
            print $cgi->textfield(-name=>"login_name");

        This method is quite handy when you have checkboxes or multiple
        section boxes which assign array of values for a single element. To
        keep those selection the way your visitor chooses throughout his/her
        session is quite challenging task. But CGI.pm's "sticky" behavior
        comes quite handy here.

        All you need to do is to load the parameters from the session to
        your CGI object, then CGI.pm automatically restores the previous
        selection of checkboxes:

            # load it from the disk to the CGI.pm object
            $session->load_param($cgi, "lists");

            # now we can just print the checkbox, and previously saved checks
            # would remain selected:
            print $cgi->checkbox_group(-name=>"lists", -values=>["CGI-Perl", "Perl5-Porters", "CGI-Session"]);

        Note: "load_param()" and "save_param()" methods didn't work on
        parameters that return multiple values. This problem was fixed in
        version 2.6 of the library.

    clear()
        this method clears the session data. Do not confuse it with
        "delete()", which deletes the session data together with the
        session_id. "clear()" only deletes the data stored in the session,
        but keeps the session open. If you want to clear/delete certain
        parameters from the session, you just pass an arrayref to the
        method. For example, here is the revised copy of the code I used in
        one of my applications that clear the contents of the user's
        shopping cart when he/she click on the 'clear the cart' link:

            $session->clear(["SHOPPING_CART"]);

            # tie() Interface
            delete $session{"SHOPPING_CART"};

        I could as well use "clear()" with no arguments, in which case it
        would delete all the data from the session, not only the
        SHOPPING_CART:

            # OO Interface
            $session->clear();

            # tie() Interface
            %session = ();

    expires()
        When a session is created, it's expiration date is undefined, which
        means, it never expires. If you want to set an expiration date to a
        session, "expires()" method can be used. If it's called without
        arguments, will return the time() value of the expiration date,
        which is the number of seconds since the epoch. If you pass an
        argument, it will consider it either as a number of seconds, or a
        special shortcut for date values. For example:

            # will it ever expire?
            unless ( $session->expires ) {
                print "Your session will never expired\n";
            }

            # how many seconds left?
            my $expires_in = $session->expires() - time();
            print "Your session will expire in $expires_in seconds\n";

            # when exactly will it expire?
            my $date = scalar(localtime( $session->expires ));
            print "Your session will expire on $date\n";

            # let the session expire in 60 seconds...
            $session->expires(60);

            # the same
            $session->expires("60s");

            # expires in 30 minutes
            $session->expires("30m");

            #expires in 1 month
            $session->expires("1M");

        For tie() interface you will need to update one of the the section
        on "SPECIAL NAMES" "_session_etime":

            $session{_session_etime} = "2d";

            printf("Your session will expires in %d seconds\n",
                $session{_session_etime} - time);

        Here is the table of the shortcuts available for "expires()":

            +===========+===============+
            | shortcut  |   meaning     |
            +===========+===============+
            |     s     |   Second      |
            |     m     |   Minute      |
            |     h     |   Hour        |
            |     w     |   Week        |
            |     M     |   Month       |
            |     y     |   Year        |
            +-----------+---------------+

        see expiring sessions for more on this.

    ctime()
        Returns the time() value of the date when the session was created:

            # OO Interface
            printf("Session was created on %s\n", localtime($session->ctime));

            # tie() Interface
            printf("Session was created on %s\n", localtime($session{_session_ctime});

    atime()
        Returns the time() value of the date when the session was last
        accessed:

            # OO Interface
            printf("Session was last accessed on %s\n", localtime($session->atime));
            printf("Session was last accessed %d seconds ago\n", time() - $session->atime);

            # tie() Interface
            printf("Session was last accessed on %s\n", localtime($session{_session_atime}));
            printf("Session was last accessed %d seconds ago\n", time() - $session{_session_atime});

    delete()
        deletes the session data from the disk permanantly:

            # OO Interface
            $session->delete();

            # tie() Interface
            tied(%session)->delete();

DEVELOPER SECTION
    If you noticed, "CGI::Session" has never been accessed directly, but we
    did so using its available drivers. As of version 2.0 "CGI:Session"
    comes with drivers for File, DB_File and MySQL databases. If you want to
    write your own driver for different storage type ( for example, Oracle,
    Sybase, Postgres so forth) or if you want to implement your own driver,
    this section is for you. Read on!

  HOW IS THE LIBRARY DESIGNED?

    "CGI::Session" itself doesn't deal with such things as storing the data
    in the disk (or other device), retrieving the data or deleting it from
    the persistent storage. These are the issues specific to the storage
    type you want to use and that's what the driver is for. So driver is
    just another Perl library, which uses "CGI::Session" as a base class,
    and provides three additional methods, "store()", "retrieve()" and
    "tear_down()". As long as you provide these three methods,
    "CGI::Session" will handle all the other part.

  WHAT ARE THE SPECS?

    Specifications for those methods we a little complex in previous
    versions of CGI::Session. But as of 2.8 I decided to pick a slightly
    different approach. Now all the driver methods receive two arguments,
    $self, and $sid. To give access to driver developers for other
    underlying data, I added two more methods to the library: <opions()> and
    "raw_data()". "options()" returns a hashref that contains the options
    passed to the constructor. For CGI::Session::DB_File driver for example,
    this has contains:

        $options = {
            sid => $sid,
            FileName => 'some-file.db',
            LockDirectory => '/tmp'
        };

    Although it contains session id, DO NOT use that session id from w/in
    your methods.

    "raw_data()" method on the other hand provides the driver methods with a
    raw data. Mostly this data is required for the "store()" method, which
    needs to store the data in the disk. Raw data is an antonymous hash
    which holds key/value pairs of the session data. As for the session id,
    it could be acquired via the public "id()" method.

    If you open the dev/ folder in the "CGI::Session" distribution, you will
    find a blueprint for the driver, MyDriver.pm, which looks something like
    this:

        package CGI::Session::MyDriver;

        use strict;
        use vars qw($VERSION);
        use base qw(CGI::Session CGI::Session::MD5);

        # all other driver specific libraries go below

        sub store {
            my ($self, $sid) = shift;

            my $options = $self->options();
            my $data    = $session->raw_data();

            return 1;
        }

        sub retrieve {
            my ($self, $sid)    = @_;
            my $options = $self->options();
            my $sid     = $self->id();

            return {};
        }

        sub tear_down {
            my ($self, $sid) = @_;

            my $options = $self->raw_data();

            return 1;
        }

    It is inheriting from two classes, "CGI::Session" and
    "CGI::Session::MD5". The second library just provides "generate_id()"
    method that returns a sting which will be used as a session id. Default
    "generate_id()" uses Digest::MD5 library to generate a unique identifier
    for the session. If you want to implement your own "generate_id()"
    method, you can override it by including one in your module as the
    fourth method.

    *   "generate_id()" receives only one argument, "$self", which is the
        object itself. The method is expected to return a string to be used
        as the session id for new sessions.

    The challenging part might seem to store the "ra_data" and to be able to
    restore it back. But there are already libraries that you can make use
    of to do this job very easily. Drivers that come with "CGI::Session"
    depend on Data::Dumper, but you can as well go with the Storable manpage
    or the FreezeThaw manpage libraries which allow you to "freeze()" the
    Perl data and "thaw()" it later, thus you will be able to re-create the
    the "$hashref". The reason we preferred Data::Dumper is, it comes
    standard with Perl.

  LOCKING

    Writing and reading from the disk requires a locking mechanism to
    prevent corrupted data. Since CGI::Session itself does not deal with
    disk access, it's the drivers' task to implement their own locking. For
    more information please refer to the driver manuals distributed with the
    package.

  OTHER NOTES

    Don't forget to include an empty DESTROY() method in your driver for
    CGI::Session's AUTOLOAD would be looking for it thus wasting its
    precious time.

TODO
    I still have lots of features in mind that I want to add and/or fix.
    Here is a short list for now. Feel free to email me your fantasies and
    patches.

    1   Fix "expires()" and implement expiring sessions in more friendly way

    2   Implement more sophisticated locking mechanism for session data.

    3   Customizable session id generator. It currently uses b64digest().
        But some people might prefer hexdigest(). So we have to make them
        happy too.

    4   Making use of some passive client identification methods.

FREQUANTLY ASKED QUESTIONS
    The following section of the library lists answers to some frequently
    asked questions:

    Q: Can I use CGI::Session in my shell scripts, or is it just for CGI
    Applications?
    A: Yes, you can!
        CGI::Session does not depend on the presence of the Web Server, so
        you can use it on all kinds of applications, crons, shell scripts,
        you name it

    Q: What if the user ask for the session which was deleted from the disk?
    A: New session will be initialized!
        Previous version of CGI::Session had a bug, and returned no id for
        the session if the session didn't exist in the disk. But latest
        version of the library should create a new session if the session
        data cannot be initialized!

    Q: Is it safe to store sensitive information in the session?
    A: Yes, it is safe, but read on
        If you noticed in the manual, we were sending on the session id to
        the client either in the form of cookie or a URL parameter. And all
        other session data is stored in the server side. So if you want to
        store sensitive information in your session, I advise you to pick a
        very safe location for your "Directory" so that no one will be able
        to access session files to find out the users' passwords, etc.

SUPPORT
    I might not be able to answer all of your questions regarding
    "CGI::Session", so please subscribe to CGI::Session mailing list. Visit
    http://ultracgis.com/mailman/listinfo/cgi-session_ultracgis.com to
    subscribe.

    For commercial support and/or custom programming, contact UltraCgis team
    ( send email to support@ultracgis.com )

HISTORY
    Initial release of the library was just a front-end to Jeffrey Baker
    <jwbaker@acm.org>'s Apache::Session and provided CGI.pm-like syntax for
    Apache::Session hashes. But as of version 2.0, the class is independent
    of third party libraries and comes with File, DB_File and MySQL drivers.
    It also allows developers to write their own drivers for other storage
    mechanisms very easily.

    Since CGI::Session used to depend on the Apache::Session manpage, the
    session data used to be serialized using the Storable manpage. Now it
    relies on standard Data::Dumper module to "freeze" and "thaw" the data.

CREDITS
    Following people contributed with their patches and/or ideas to the
    development of this library. List is in ascending chronological order.

    Andy Lester <alester@flr.follett.com>
        Thanks for his patience for helping me to fix the bug in
        CGI::Session::File, which kept failing in Solaris.

    Brian King <mrbbking@mac.com>
        Helped to fix the t/mysql.t test suite that was failing on MacOS X

    Olivier Dragon <dragon@shadnet.shad.ca>
        Fixed "expires()" method.

BUGS
AUTHOR
    Sherzod B. Ruzmetov <sherzodr@cpan.org>

SEE ALSO
    the CGI::Session::File manpage, the CGI::Session::DB_File manpage, the
    CGI::Session::MySQL manpage the Apache::Session manpage, the
    Data::Dumper manpage, the Digest::MD5 manpage, the FreezeThaw manpage,
    the Storable manpage, the CGI manpage

