# CGI::Session::Tutorial - phpMan

## NAME
    [CGI::Session::Tutorial] - Extended [CGI::Session] manual

## STATE MAINTENANCE 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.

    For our rescue come such technologies as *HTTP Cookies* and
    *QUERY_STRING*s that help us save the users' session for a certain
    period. Since *HTTP Cookies* and *QUERY_STRING*s alone cannot take us
    too far (RFC 2965, Section 5, "Implementation Limitations"), several
    other libraries have been developed to extend their capabilities and
    promise a more reliable solution. [CGI::Session] is one of them.

    Before we discuss this library, let's look at some alternative
    solutions.

  COOKIE
    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.

    Although *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 6-"Privacy" and 7-"Security
    Considerations" of RFC 2965.

  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>

    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.

  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).

    Query strings and hidden fields are also lost easily by closing the
    browser, or by clicking the browser's "Back" button.

  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 *HTTP Cookie*, a *QUERY_STRING*, hidden field or any
    combination of the above. This is necessary to make the connection with
    the client and his data.

    Advantages:

    *   We no longer need to depend on User Agent constraints in cookie
        size.

    *   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 (5767393932698093d0b75ef614376314, for
        instance), which should make no sense to third parties.

    *   User will not have sensitive data stored in his/her computer in
        unsecured file (which is a cookie file).

    *   It's possible to handle very big and even complex data structures
        transparently (which *HTTP Cookies* do not handle).

    That's what [CGI::Session] is all about - implementing server side session
    management. Now is a good time to get feet wet.

## PROGRAMMING STYLE
    Server side session management system might be seeming awfully
    convoluted if you have never dealt with it. Fortunately, with
    [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.

    All applications making use of server side session management rely on
    the following pattern of operation regardless of the way the system is
    implemented:

    1   Check if the user has session cookie dropped in his computer from
        previous request

    2   If the cookie does not exist, create a new session identifier, and
        drop it as cookie to the user's computer.

    3   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.

    4   Store any necessary data in the session that you want to make
        available for the next HTTP request.

    [CGI::Session] will handle all of the above steps. All you have to do is
    to choose what to store in the session.

  GETTING STARTED
    To make [CGI::Session]'s functionality available in your program do either
    of the following somewhere on top of your program file:

        use [CGI::Session];
        # or
        require [CGI::Session];

    Whenever you're ready to create a new session in your application, do
    the following:

        $session = [CGI::Session]->new () or die [CGI::Session]->errstr;

    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 *session ID*, *SID* for short, and can be accessed through id() -
    object method.

    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 "CGISESSID", and if
    it found it tried to load existing session from server side storage
    (file in our case). If cookie didn't exist it looked for a QUERY_STRING
    parameter called "CGISESSID". If all the attempts to recover session ID
    failed, it created a new session.

    NOTE: For the above syntax to work as intended your application needs to
    have write access to your computer's *TEMPDIR* folder, which is usually
    /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:

        $session = [CGI::Session]->new(undef, undef, {Directory=>'../tmp/sessions'});

    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
    [CGI::Session::Driver::file], which is the default driver used in our
    above example.

    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 *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.

    To make sure [CGI::Session] will be able to read your cookie at next
    request you need to consult its "name()" method for cookie's suggested
    name:

        $cookie = $query->cookie( -name   => $session->name,
                                  -value  => $session->id );
        print $query->header( -cookie=>$cookie );

    "name()" returns "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:

        [CGI::Session]->name("SID");
        $session = [CGI::Session]->new();

    Baking the cookie wasn't too difficult, was it? But there is an even
    easier way to send a cookie using [CGI::Session]:

        print $session->header();

    The above will create the cookie using [CGI::Cookie] and will return
    proper http headers using CGI.pm's CGI method. Any arguments to
    [CGI::Session] will be passed to [CGI::header]().

    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 name():

        printf ("<a href=\"$ENV{SCRIPT_NAME}?%s=%s\">click me</a>", $session->name, $session->id);

    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:

        $session = [CGI::Session]->new( $sid );
        $session = [CGI::Session]->new( "serializer:freezethaw", $sid );
        $session = [CGI::Session]->new( "driver:mysql", $sid, {Handle=>$dbh} );

    By default [CGI::Session] uses standard 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:

        $cgi     = [CGI::Simple]->new();
        $session = [CGI::Session]->new( $cgi );
        $session = [CGI::Session]->new( "driver:db_file;serializer:storable", $cgi);
        # etc

    See [CGI::Simple]

  STORING DATA
    [CGI::Session] offers param() method, which behaves exactly as CGI.pm's
    param() with identical syntax. param() is used for storing data in
    session as well as for accessing already stored data.

    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 *user name* part of his login form, so the customer can jump
    right to the *password* field without having to type his username again.

        my $name = $cgi->param('username');
        $session->param('username', $name);

    Notice, we're grabbing *username* value of the field using CGI.pm's (or
    another compatible library's) "param()" method, and storing it in
    session using [CGI::Session]'s param() method.

    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:

        $session->save_param(['name']);

    If you wanted to store multiple form fields just include them all in the
    second list:

        $session->save_param(['name', 'email']);

    If you want to store all the available *QUERY_STRING* parameters you can
    omit the arguments:

        $session->save_param();

    See save_param() for more details.

    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).

    For example, to get all the selected values of a scrolling list and
    store it in the session:

        my @fruits = $cgi->param('fruits');
        $session->param('fruits', \@fruits);

    For parameters with multiple values save_param() will do the right thing
    too. So the above is the same as:

        $session->save_param($cgi, ['fruits']);

    All the updates to the session data using above methods will not reflect
    in the data store until your application exits, or $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 flush() method:

        $session->flush();

    I've written a lot of code, and never felt need for using "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
    flush().

  ACCESSING STORED DATA
    There's no point of storing data if you cannot access it. You can access
    stored session data by using the same param() method 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:

        $name = $session->param("name");
        printf "<input type=\"text\" name=\"name\" value=\"%s\" />", $name;

    To retrieve previously stored @fruits do not forget to de reference it:

        @fruits = @{ $session->param('fruits') };

    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
    load_param() method, which loads given session parameters to a CGI
    object (assuming they have been previously saved with save_param() or
    alternative):

        $session->load_param($cgi, ["fruits"]);

    Now when you say:

        print $cgi->checkbox_group(fruits=>['apple', 'banana', 'apricot']);

    See load_param() for details.

    Generated checkboxes will be pre-filled using previously saved
    information.

    If you're making use of [HTML::Template] to separate the code from the
    skin, 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 = [HTML::Template]->new(filename=>"some.tmpl", associate=>$session);
        print $template->output();

    Assuming the session object stored "first_name" and "email" parameters
    while being associated with [HTML::Template], you can access those values
    from within your "some.tmpl" file now:

        Hello <a href="mailto:<TMPL_VAR email>"> <TMPL_VAR first_name> </a>!

    See [HTML::Template]'s online manual for details.

  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
    [CGI::Session] provides 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"]);

    Above line deletes "~logged-in" and "email" session parameters from the
    session. And next time you say:

        $email = $session->param("email");

    it returns undef. If you omit the argument to 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 clear() for details.

  DELETING A SESSION
    If there's a start there's an end. If session could be created, it
    should be possible to delete it from the disk for good:

        $session->delete();

    The above call to delete() deletes the session from the disk for good.
    Do not confuse it with clear(), which only clears certain session
    parameters but keeps the session open.

    See delete() for details.

  EXPIRATION
    [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 expire():

        $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.

    See expire() for details.

    Before [CGI::Session] 4.x there was no way of intercepting requests to
    expired sessions. [CGI::Session] 4.x introduced new kind of constructor,
    load(), which is identical in use to 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 empty()
    and is_expired() methods. If session was loaded successfully object
    returned by "load()" is as good a session as the one returned by
    "new()":

        $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();
        }

    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 "is_expired()" before checking
    with "is_empty()". There is another thing about the above example.
    Notice how its creating new session when un existing session was
    requested? By calling "new()" as an object method! Handy thing about
    that is, when you call "new()" on a session object new object will be
    created using the same configuration as the previous object.

    For example:

        $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();
        }

    Initial $session object was configured with mysql as the driver,
    storable as the serializer and $dbh as the database handle. Calling "
    new() " on this object will return an object of the same configuration.
    So $session object returned from " new() " in the above example will use
    mysql as the driver, storable as the serializer and $dbh as the database
    handle.

    See is_expired(), is_empty(), load() for details.

    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 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.

    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 expire() method again:

        $session->expire(_profile_access, '1h');
        $session->expire(_cc_access, '5m');

    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.

    See expire() for details.

    This concludes our discussion of [CGI::Session] programming style. The
    rest of the manual covers some "SECURITY" issues. Driver specs from the
    previous manual were moved to [CGI::Session::Driver].

## SECURITY
    "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.

  STORAGE
    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.

    *   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.

    *   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 easily. If you configure your session
        object to use either Storable or 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 Storable or FreezeThaw to
        decipher session files very easily.

    *   Do not allow anyone to update contents of session files. If you're
        using default serializer serialized data string needs to be eval()ed
        to bring the original data structure back to life. Of course, we use
        Safe to do it safely, but your cautiousness does no harm either.

    *   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 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.

  SESSION IDs
    Session ids are not easily guessed (unless you're using incr ID
    generator)! Default configuration of [CGI::Session] uses [Digest::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?

    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.

    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.

    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.

    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:

        use [CGI::Session] '-ip_match';

    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.

## LICENSING
    For support and licensing see [CGI::Session]

