In this set of notes we will describe some basic ways to keep track of state information during a session with a user. A session is loosely defined as one or more web interactions with a browser that have a common goal, such as completing a survey or an e-commerce transaction.
We've seen how Perl can be used to handle simple CGI forms. More complicated forms may span several pages and require the maintenance of state information. For example, a survey might take several pages, with a Next button being used to advance to each page of the survey. As another example, an e-commerce site might allow you to add items to a basket and then take you through several forms during the checkout process.
The problem that multi-page forms pose is that the http protocal is not designed with the notion of a session and hence it is not possible to keep a script running as a user moves through a multi-page form. Instead http is designed so that each page interaction starts a new script. Even if the same script is called by a form, it will be a new invocation of the script, rather than an old invocation. The problem then is for the set of scripts associated with a particular multi-page form to maintain state information.
There are both client-side and server-side approaches to saving this state information. The easiest client-side approaches involve either hidden fields or cookies. The easiest server-side approaches involve maintaining a session id, storing state information in a file or database, and using the session id to access this information.
We have already seen how hidden fields can encode information on a form. The basic idea is that information is cumulatively built up and stored in hidden fields on the form that the user is currently interacting with. When a script is activated it can access the hidden fields and restore any state information it needs.
For example, suppose at an e-commerce site that a user starts adding items to a shopping cart. Each item that is added to the cart can be concatenated to the end of a string, along with its quantity. For example, if a user has selected 2 tubes of suntan lotion with stock code 368 and 1 red polo shirt with stock code 5831, a script could create the following hidden field and insert it into subsequent forms:
Hidden values have a number of disadvantages:
A second approach involves using cookies. A cookie is essentially a name-value pair that gets stored on the user's computer and that can be accessed by specified scripts. A cookie can be created using a Perl CGI function named cookie. For example:
$cart = cookie( -name => "cart", -value => "368 2 5831 1" );The parameters are named parameters and hence can be presented in any order to the function.
You can now transmit the cookie to the browser using the header function:
print header(-cookie => $cart);You must transmit all cookies to the browser before transmitting any html markup to the browser. In other words, create and transmit all your cookies before calling start_html.
You can transmit multiple cookies using an anonymous array:
print header(-cookie => [$cart, $prices]);A script can also retrieve the cookie using the cookie function:
$cart_value = cookie("cart"); # returns the value of cartThe cookie name may be omitted, in which case the cookie function returns all the cookies that have been set by scripts on this server:
@cookie_names = cookie(); # returns the names of all cookies set by this serverWhen cookies are created in the manner just shown, they are accessable by any script stored on the server, not just the script that created the cookie. Hence, a script associated with one form can store information in a cookie and a script associated with another form can subsequently retrieve the cookie.
Cookies created in the manner just shown also exist for the life of the browser session and are then deleted when the user quits the browser. To extend the life of a cookie across browser sessions, one can provide the -expires parameter to the cookie function:
$cart = cookie( -name => "cart", -value => "368 2 5831 1", -expires => "+7d" ); # create a cookie that lasts a weekThe -expires parameter is a request to the browser, not an absolute command. The browser can choose to delete the cookie for any number of reasons, such as limited cookie space or a clearing of the cookie cache by the user. Options for the expire parameter include the following:
|Seconds||+30s||Save for 30 seconds|
|Minutes||+30m||Save for 30 minutes|
|Hours||+30h||Save for 30 hours|
|Days||+30d||Save for 30 days|
|Months||+30m||Save for 30 months|
|Years||+30y||Save for 30 years|
|Specific Time||Monday, 03-Feb-2008 06:00:00 GMT||Format: Day, DD-Mon-YYYY HH:MM:SS GMT|
You can also restrict the scripts on the server that have access to the cookie by specifying the -path parameter to the cookie function. For example:
# restrict the cookie to scripts residing in the /books directory $cart = cookie( -name => "cart", -value => "368 2 5831 1", -path => '/books' ); # restrict the cookie to this particular script. It does not restrict access # however to only this invocation of the script. Any invocation of this # script will have access to the cookie $cart = cookie( ... -path => script_name() );The path is taken from the top-level cgi-bin directory. For example, if the -path parameter is '/books' and if my cgi directory is ~bvz/www-home/cgi-bin/, then only scripts stored in ~bvz/www-home/cgi-bin/books can access the cookie.
The web-page cookie-demo gives you an opportunity to create a simple cookie. Enter a color and then press the "Submit Form" button. A script called cookie1.cgi creates a cookie and then dynamically generates a web-page that gives information about the cookie. If you press the Press Me button a script called cookie2.cgi retrieves the cookie and prints its value. The two scripts are shown below:
Cookies have the advantage of requiring less time to load a web page because some of the information the web page requires is already stored on the client's computer. Unfortunately cookies still have a number of disadvantages including:
The obvious approach would be to store the state information in a file. Unfortunately, browsers do not
Server-side state management involves assigning a browser a session id, storing the session information in a file or database, and using that session id as a key to access the information. The session id will typically be stored on the client side in either a cookie, or, if cookies are disabled, using a fairly complicated technique known as URL encoding or URL re-writing. URL encoding is beyond the scope of this course but typically involves embedding a session id with each link in pages that are served to the user's browser. In other words, the URL for each link will have a session id associated with it. When the user clicks the link, the URL is sent to the server and the server can extract the session id. Many companies have developed tools that make URL re-writing easier to perform, but it is a poor second choice to using cookies.
These notes have provided a brief introduction to the basic concepts used in maintaining state information during a session. Rather than implementing these concepts from scratch, it may be easier to use one of the high-level Perl modules that have been developed over the years to deal with session variables, cookies, or hidden data. If you look at the Comprehensive Perl Archive Network (CPAN) site, you will find different modules that may accomplish your intended task.