A fundamental characteristic of the Web is the stateless interaction between browsers and web servers. As discussed in Chapter 1, HTTP is a stateless protocol. Each HTTP request a browser sends to a web server is independent of any other request. The stateless nature of HTTP allows users to browse the Web by following hypertext links and visiting pages in any order. HTTP also allows applications to distribute or even replicate content across multiple servers to balance the load generated by a high number of requests. These features are possible because of the stateless nature of HTTP.
This stateless nature suits applications that allow users to browse or search collections of documents. However, applications that require complex user interaction can’t be implemented as a series of unrelated, stateless web pages. An often-cited example is a shopping cart in which items are added to the cart while searching or browsing a catalog. The state of the shopping cart—the selected items—needs to be stored somewhere. When the user requests the order page, the items for that user need to be displayed.
Stateful web database applications can be built using sessions, and session management is the topic of this chapter. In this chapter we:
Discuss how sessions are managed in the stateless environment of the Web and introduce the three characteristics of server-side session management
Introduce cookies for storing state
Show how to use and configure the PHP session management library
Use PHP session management to improve the client entry
<form>
in the winestore case study
Provide a brief list of reasons for using, or avoiding, session management over the Web
The focus of this chapter is on the session management provided by PHP. However, other techniques to keep state are briefly discussed, including the use of cookies.
Applications sometimes need to use the result of one request when processing another. For example, a request that adds an item to a shopping cart needs to be remembered when the request is made to create the order. In other words, the state of the application needs to be stored between HTTP requests. There are two ways to achieve this: variables that hold the state can be stored in the browser and included with each request or variables can be stored on the server.
Most of this chapter is devoted to the second alternative, where the middle tier stores and manages the application state using sessions. However, in this section we briefly discuss solutions that store state in the client tier. One technique described in this section is the use of cookies. While cookies can store state in the client tier, they are also used in middle-tier session management, as described later in this chapter.
Data sent with the GET
or POST
methods can include the application state
with each HTTP request. An illustration of this approach can be seen
in the previous and next browsing features developed in Chapter 5. In this example, there are two pieces, or
states, that need to be considered when a page
is browsed: the query parameters the user provided and which page
should be displayed.
The solution developed in Chapter 5 encodes the query and an offset as an embedded link. An example URL that displays the fourth page of results may be as follows:
http://localhost/example.5-10.php?regionName=All&offset=40
This solution allows navigation through large search result sets. Similar solutions are used in the URLs generated to jump between the results pages of web search engines such as Google or Altavista. Cookies can be used for the same purpose.
Encoding the variables that hold state with each HTTP request
increases the amount of data that has to be transmitted over the Web,
and when data is encoded using the GET
method,
applications can generate long URLs. While HTTP
doesn’t restrict the
length of URLs, some older browsers and
proxy servers do enforce limits.
When state variables are encoded as part of the URL, or even when they are included as cookies, it is possible for the user to change the values that are sent with the request. For example, a user can enter the following URL manually if she wants to see the records starting from row #7 in the result set:
http://localhost/example.5-10.php?regionName=All&offset=7
Changing the offset in a results page is harmless, but changing the item price of a bottle of wine is more serious. As discussed in Chapter 6 and Chapter 7, an application can’t rely on data that is sent from the browser.
Cookies
are often used to store application state in a web browser. As with
data sent with the GET
or POST
methods, cookies are sent with HTTP requests made by a browser. A
cookie is a named piece of information that is
stored in a web browser. A browser can create a cookie using
JavaScript, but a cookie is usually sent from the web server to the
client in the Set-Cookie
header field as part of
an HTTP response. Consider an example HTTP response:
HTTP/1.0 200 Content-Length: 1276 Content-Type: text/html Date: Tue, 06 Nov 2001 04:12:49 GMT Expires: Tue, 06 Nov 2001 04:12:59 GMT Server: simwebs/3.1.6 Set-Cookie: animal=egg-laying-mammal <html>...</html>
The web browser that receives this response remembers the cookie and
includes it as the header field Cookie
in
subsequent HTTP requests to the same web server. For example, if a
browser receives the response just shown, a subsequent request has
the following format:
GET /duck/bill.php HTTP/1.0 Connection: Keep-Alive Cookie: animal=egg-laying-mammal Host: www.webdatabasebook.com Referer: http://www.webdatabasebook.com/
There are several additional parameters used with the
Set-Cookie
header that define when a cookie can be
included in a request:
A cookie can have a date and time at which it expires. The browser includes the cookie in requests up until that date and time. If no expiry date is given, the cookie is remembered only while the browser is running. Cookies that are kept only while the browser is running are known as session cookies .
A domain
limits the sites to which a browser can
send the cookie. If no domain
is set, the browser
includes the cookie only in requests sent to the server that set the
cookie.
Browsers don’t include the cookie in requests for
resources that aren’t in the specified
path
. This is useful if only part of a web site
requires that a cookie be sent. For example, if the path is set to
/admin
, requests for resources in that path,
such as http://localhost/admin/home.php
include
the cookie, while requests for resources in other paths, such as
http://localhost/winestore/home.php
, do not.
A cookie can also be marked as secure
, instructing
the browser to send the cookie only when using a secure connection
through the Secure Sockets Layer protocol. This prevents sensitive
data stored in a cookie from being transmitted in an insecure form.
Encryption using the SSL software is discussed in Chapter 9.
Cookies can be included in an HTTP response using the
header( )
function; however, the developer needs to know
how to encode the cookie name, value, and the other parameters
described earlier in the Set-Cookie
header field.
To simplify cookie creation, PHP provides the setcookie( )
function that generates a correct header field.
When an HTTP request that contains cookies is processed, PHP makes
the values of the cookies available to the script in the global
associative array $HTTP_COOKIE_VARS
. If
register_globals
is enabled, a variable with the
name of the cookie is also initialized by PHP; the
register_globals
feature in the
php.ini
file is discussed in Chapter 5.Example 8-1 tests to see if
the variable $count
has been set from a cookie,
and either sets the value to 0 or increments
$count
accordingly. The script also creates a
cookie named start
, with the value set to the
current time, when the $count
is set to 0. The
cookie start
is set only at the beginning of this
stateful interaction.
Example 8-1. Setting a cookie using PHP
<?php // See if the HTTP request has set $count as the // result of a Cookie called "count" if(!isset($count)) { // No cookie called count, set the counter to zero $count = 0; // .. and set a cookie with the "start" time // of this stateful interaction $start = time( ); setcookie("start", $start, time( )+600, "/", "", 0); } else { $count++; } // Set a cookie "count" with the current value setcookie("count", $count, time( )+600, "/", "", 0); ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head><title>Cookies</title></head> <body> <p>This page comes with cookies: Enjoy! <br>count = <?=$count ?>. <br>start = <?=$start ?>. <p>This session has lasted <?php $duration = time( ) - $start; echo "$duration"; ?> seconds. </body> </html>
The setcookie( )
function is called with six
arguments, although only the first—the name—is required:
int setcookie(stringname
, [stringvalue]
, [int
expire], [stringpath]
, stringdomain
, [int
secure])
The two calls to setcookie( )
in Example 8-1 add the Set-Cookie
header
field to the HTTP response. The first encodes the
start
cookie with the value of the current time as
an integer returned from the time( )
function. The second encodes the count
cookie with
the value of the variable $count
. Both cookies are
set with the expiry date of the current time plus 600 seconds; that
is, 10 minutes. With the path parameter set to
/
, the browser includes the cookies with all
requests to the site. By passing an empty string for the domain, the
browser includes the cookies only with requests to the domain of the
machine serving this page. The final parameter 0
allows the browser to transmit the cookies over both secure and
insecure connections.
Cookies can be used for simple applications that don’t require complex data to be kept between requests. However, there is a limit on the number and size of cookies that can be set: a browser can keep only the last 20 cookies sent from a particular domain, and the values that a cookie can hold are limited to 4 KB in size. Also, there are arguments about both the privacy and the security of applications that use cookies, and users often disable cookie support in their browsers. We discuss some of the security issues of cookies in Chapter 9.
3.12.76.164