Search the Catalog
Web Database Applications with PHP & MySQL

Web Database Applications with PHP & MySQL

By David Lane, Hugh E. Williams
March 2002
0-596-00041-3, Order Number: 0413
582 pages, $44.95 US $69.95 CA £31.95 UK

Chapter 8
Sessions

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:

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.

Building Applications That Keep State

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.

Managing State in the Client Tier

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 Chapters 6 and 7, an application can't rely on data that is sent from the browser.

Cookies

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:

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(string name, [string value], [int expire], [string path], string domain, [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.

Session Management Over the Web

Storing the state in the web server--the middle tier--can solve the problem of increased request size and protect the state of an application from accidental or intentional changes a user might make.

A session is a way to identify and manage the state--the session variables--for a particular user. When a user sends an HTTP request, the middle tier must process the current request in the context of the user's session. When a session is started, the client is given a session identifier--often a cookie--that is included with subsequent requests to the server. The server uses the session identifier to locate the corresponding session before processing the request.

Rather than storing all the variables needed to maintain state and include them with each request, the browser stores a single session identifier that finds and initializes the variables stored on the server. The session identifier is like the ticket given at a cloak room. The ticket is much easier to carry around and ensures that the holder gets her own hat and coat.

One implication of storing session variables in the middle tier is that data needs to be stored for each session. The question is, for how long? Because HTTP is stateless, there is no way to know when a user has finished with a session. Ideally, the user logs out of an application, and the logout script ends the session. However, because a server can never be sure if a user is still there, the server needs to clean up old sessions that have not been used for a period of time. This last point is important, because sessions consume resources on the server, and dormant sessions may present a security risk. How long the timeout should be depends on the needs of the application, and we discuss this in more detail later in this chapter.

In summary, there are three characteristics session management over the Web must exhibit:

PHP Session Management

With the release of PHP4, session management was introduced as an extension to the PHP language. PHP provides several session-related functions, and developing applications that use PHP sessions is straightforward. The three important features of session management are mostly taken care of by the PHP scripting engine.

In this section, we present how to use PHP sessions, showing how sessions are started and ended and how session variables are used. We list the PHP functions for building session-based web applications. Because not all browsers support cookies, and some users actively disable them, we describe how to use PHP sessions without relying on cookies. Finally, we show how to configure PHP session management with a discussion on the garbage collection used to remove old sessions and other configuration parameters.

Overview

An overview of PHP session management is shown in Figure 8-1. When a user first enters the session-based application by making a request to a page that starts a session, PHP generates a session ID and creates a file that stores the session-related variables. PHP sets a cookie to hold the session ID in the response the script generates. The browser then records the cookie and includes it in subsequent requests. In the example shown in Figure 8-1, the script welcome.php records session variables in the session store, and a request to next.php then has access to those variables because of the session ID.

Figure 8-1. The interaction between the browser and the server when initial requests are made to a session-based application

 

The out-of-the-box configuration of PHP session management uses disk-based files to store session variables. Using files as the session store is adequate for most applications in which the numbers of concurrent sessions are limited. A more scalable solution that uses a MySQL database as a session store is provided in Appendix D.

Starting a Session

PHP provides a session_start( ) function that creates a new session and subsequently identifies and establishes an existing one. Either way, a call to the session_start( ) function initializes a session.

The first time a PHP script calls session_start( ), a session identifier is generated, and, by default, a Set-Cookie header field is included in the response. The response sets up a session cookie in the browser with the name PHPSESSID and the value of the session identifier. The PHP session management automatically includes the cookie without the need to call to the setcookie( ) or header( ) functions.

The session identifier (ID) is a random string of 32 hexadecimal digits, such as fcc17f071bca9bf7f85ca281094390b4. As with other cookies, the value of the session ID is made available to PHP scripts in the $HTTP_COOKIE_VARS associative array and in the $PHPSESSID variable.

When a new session is started, PHP creates a session file. With the default configuration, session files are written in the /tmp directory using the session identifier, prefixed with sess_, for the filename. The filename associated with our example session ID is /tmp/sess_fcc17f071bca9bf7f85ca281094390b4.

If a call is made to session_start( ), and the request contains the PHPSESSID cookie, PHP attempts to find the session file and initialize the associated session variables as discussed in the next section. However, if the identified session file can't be found, session_start( ) creates an empty session file.

Using Session Variables

Variables need to be registered with the session_register( ) function that's used in a session. If a session has not been initialized, the session_register( ) function calls session_start( ) to open the session file. Variables can be registered--added to the session file--with the session_register( ) call as follows:

// Register the variable named "foo"
session_register("foo");
$foo = "bar";

Note that it is the name of the variable that is passed to the session_register( ) function, not the variable itself. Once registered, session variables are made persistent and are available to scripts that initialize the session. PHP tracks the values of session variables and saves their values to the session file: there is no need to explicitly save a session variable before a script ends. In the previous example, the variable $foo is automatically saved in the session store with its value bar.

Variables can be removed from a session with the session_unregister( ) function call; again, the name of the variable is passed as the argument, not the variable itself. A variable that is unregistered is no longer available to other scripts that initialize the session. However, the variable is still available to the rest of the script immediately after the session_unregister( ) function call.

Scripts that initialize a session have access to the session variables through the associative array $HTTP_SESSION_VARS, and PHP automatically initializes the named session variables if register_globals is enabled.

Example 8-2 shows a simple script that registers two variables: an integer $count, which is incremented each time the script is called, and $start, which is set to the current time from the library function time( ) when the session is first initialized. The script tests if the variable $count has been registered to determine if a new session has been created. If the variable $count has been registered already, the script increments its value.

Do not use the existence of $PHPSESSID as indicative of a new session, or as a method to access the session ID. The first time a script is called and the session is created, the PHPSESSID cookie may not be set. Only subsequent requests are guaranteed to contain the PHPSESSID cookie. PHP provides a session_id( ) function that returns the session ID for the initialized session.

The script shown in Example 8-2 displays both variables: $count shows how many times the script has been called, and time( ) - $start shows how many seconds the session has lasted.

Example 8-2: Simple PHP script that uses a session

<?php
  // Initialize a session. This call either creates 
  // a new session or re-establishes an existing one.
  session_start(  );
 
  // If this is a new session, then the variable
  // $count will not be registered
  if (!session_is_registered("count")) 
  {
    session_register("count");
    session_register("start");
 
    $count = 0;
    $start = time(  );
  } 
  else 
  {
    $count++;
  }
 
  $sessionId = session_id(  );
 
?>
<!DOCTYPE HTML PUBLIC 
   "-//W3C//DTD HTML 4.0 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd" >
<html>
  <head><title>Sessions</title></head>
  <body>
    <p>This page points at a session 
        (<?=$sessionId?>)
    <br>count = <?=$count?>.
    <br>start = <?=$start?>.
    <p>This session has lasted 
      <?php 
        $duration = time(  ) - $start; 
	echo "$duration"; 
      ?> 
      seconds.
  </body>
</html>

Session variables can be of the type Boolean, integer, double, string, object, or arrays of those variable types. Care must be taken when using object session variables, because PHP needs access to the class definitions of registered objects when initializing an existing session. If objects are to be stored as session variables, you should include class definitions for those objects in all scripts that initialize sessions, whether the scripts use the class or not. Objects and classes are described in Chapter 2.

PHP stores session variables in the session file by serializing the values. The serialized representation of a variable includes the name, the type, and the value as a stream of characters suitable for writing to a file. Here's an example of a file that was created when the script shown in Example 8-2 was run several times:

count|i:6;start|i:986096496;

A PHP developer need not worry how serialization occurs; PHP session management takes care of reading and writing session variables automatically.

Ending a Session

At some point in an application, sessions may need to be destroyed. For example, when a user logs out of an application, a call to the session_destroy( ) function can be made. A call to session_destroy( ) removes the session file from the system but doesn't remove the PHPSESSID cookie from the browser.

Example 8-3 shows how the session_destroy( ) function is called. A session must be initialized before the session_destroy( ) call can be made. You should also test to see if $PHPSESSID is a set variable before killing the session. This prevents the code from creating a session, then immediately destroying it if the script is called without identifying a session. However, if the user has previously held a session cookie, PHP initializes the $PHPSESSID variable, and the code redundantly creates and destroys a session.

Example 8-3: Ending a session

<?php
  // Only attempt to end the session if there 
  // is a $PHPSESSID set by the request.
  if(isset($PHPSESSID)) {
    $message = "<p>End of session ($PHPSESSID).";
    session_start(  );
    session_destroy(  );
  } else {
    $message = "<p>There was no session to destroy!";
  }
?>
<!DOCTYPE HTML PUBLIC 
   "-//W3C//DTD HTML 4.0 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd" >
<html>
  <head><title>Sessions</title></head>
  <body>
    <?=$message?>
  </body>
</html>

Functions for Accessing Sessions in PHP

In this section we list the key functions used to build session-based applications in PHP. Greater control over sessions can be achieved through the configuration of PHP--as we discuss in the "Configuration of PHP Session Management" section--or by using GET variables to encode the session ID, as discussed in the next section.

Boolean session_start( )
Initializes a session by either creating a new session or using an identified one. Checks for the variable $PHPSESSID in the HTTP request. If a session identifier isn't included in the request, or an identified session isn't found, a new session is created. If a session ID is included in the request, and a session isn't found, a new session is created with the PHPSESSID encoded in the request. When an existing session is found, the session variables are read from the session store and initialized. Using PHP's default settings, a new session is created as a file in the /tmp directory. This function always returns true.

string session_id([string id])
Can be used in two ways: to return the ID of an initialized session and to set the value of a session ID before a session is created. When used to return the session ID, the function must be called without arguments after a session has been initialized. When used to set the value of the session ID, the function must be called with the ID as the parameter before the session has been initialized.

Boolean session_register(mixed name [, mixed ...])
Registers one or more variables in the session store. Each argument is the name of a variable, or an array of variable names, not the variable itself. Once a variable is registered, it becomes available to any script that identifies that session. This function calls the session_start( ) code internally if a session has not been initialized. The session_unregister( ) function is called to remove a variable from the session. Returns true when the variables are successfully registered.

Boolean session_is_registered(string variable_name)
Returns true if the named variable has been registered with the current session and false otherwise. Using this function to test if a variable is registered is a useful way to determine if a script has created a new session or initialized an existing one.

session_unregister(string variable_name)
Unregisters a variable with the initialized session. Like the session_register( ) function, the argument is the name of the variable, not the variable itself. Unlike the session_register( ) function, the session needs to be initialized before calling this function. Once a variable has been removed from a session with this call, it is no longer available to other scripts that initialize the session. However, the variable is still available to the rest of the script that calls session_unregister( ).

session_unset( )
Unsets the values of all session variables. This function doesn't unregister the actual session variables. A call to session_is_registered( ) still returns true for the session variables that have been unset.

Boolean session_destroy( )
Removes the session from the PHP session management. With PHP's default settings, a call to this function removes the session file from the /tmp directory. Returns true if the session is successfully destroyed and false otherwise.

Session Management Without Cookies

A change that can be made to the default PHP session management is to encode the $PHPSESSID value as an attribute in a GET or POST method request and avoid the need to set a cookie.

A simple experiment that illustrates what happens when users disable cookies is to request the script shown in Example 8-2 from a browser that has cookie support turned off. When repeated requests are made, the counter doesn't increment, and the session duration remains at zero seconds. Because a cookie isn't sent from the browser, the variable $PHPSESSID is never set. The other side effect is that each time the page is requested, a session file is created in the /tmp directory. Many users configure their browsers to not accept cookies, and session-based applications won't work unless they are written to handle the missing cookie.

The session identifier that would have been sent as a cookie in this experiment can be transmitted in a GET or POST method request. While the session_start( ) function can use $PHPSESSID set by either a GET or POST method request, it is more practical to use the GET variable. Using the POST variable leads to the reload problem described in Chapter 6. Continuing the experiment, requests that don't contain the cookie can identify an existing session by setting an attribute in a GET method request with the name PHPSESSID and the value of the session ID. For example, an initial request can be made to Example 8-1 with the URL:

http://localhost/example.8-1.php

This creates a session and an associated file such as:

/tmp/sess_be20081806199800da22e24081964000

Subsequent requests can be made that include the PHPSESSID:

http://localhost/example.8-1.php?PHPSESSID=be20081806199800da22e24081964000

The response shows the counter set to 1 and the correct session duration. Repeated requests to this URL behave as expected: the counter increments, and the calculated duration increases.

If you write session-based applications to use the URL to identify sessions, the application doesn't fail for users who don't allow cookies. Applications can use a test cookie to see if cookies are supported by the browser or just not use cookies at all.

WARNING:   When register_globals is enabled, and both a cookie and GET or POST are used to set the $PHPSESSID, the cookie wins. A GET or POST attribute value is overwritten by the value associated with the cookie because of the default order in which PHP initializes those variables.

The safe way to read cookies and GET and POST attributes that have name conflicts is to use the $HTTP_COOKIE_VARS, $HTTP_GET_VARS, and $HTTP_POST_VARS arrays.

Another advantage of avoiding cookies is that some browsers, such as Netscape and Internet Explorer, share cookies across all instances of the program running for a particular user on the same machine. This behavior prevents a user from having multiple sessions with a web database application.

Encoding the session ID as a GET variable

Scripts that generate embedded links to pages that use session variables need to include a GET attribute named PHPSESSID in the URL. This can be done using the basic PHP string support and calls to session_id( ). For example:

<?php
  // Initialize the session
  session_start(  );
 
  // Generate the embedded URL to link to
  // a page that processes an order
  $orderUrl = "/order.php?PHPSESSID=" . session_id(  );
?>
 
<a href="<?=$orderUrl ?>">Create Order</a>

To aid the creation of URLs that link to session-based scripts, PHP sets the constant SID that contains the session ID in the form suitable to use as a URL query string. If there is no session initialized, PHP sets the value of SID to be a blank string. If a session is initialized, it sets the SID to a string containing the session ID in the form:

PHPSESSID=be20081806199800da22e24081964000

By including the value of SID when URLs are constructed, the hypertext links correctly identify the session. A link that points to a script that expects a session ID can be encoded like this:

<?php
  // Initialize the session
  session_start(  );
?>
 
<a href="/order.php?<?=SID?>">Create Order</a>

As an alternative to writing code to formulate the session ID into the URL, PHP includes a URL rewrite feature that automatically modifies reference URLs to include the session ID as a GET attribute. To activate this feature, PHP needs to be configured with - -enable-trans-id and then recompiled. Once URL rewrite is activated, PHP parses the HTML generated by scripts and automatically alters the embedded URLs to include the PHPSESSID query string. The URL rewrite feature has the disadvantage that extra processing is required to parse every generated page.

Turning off cookies

PHP session management can be instructed not to set the PHPSESSID cookie by changing the session.use_cookies parameter to 0 in the php.ini file. The session configuration parameters in the php.ini file are described in the later section "Configuration of PHP Session Management."

Garbage Collection

While it is good practice to build applications that provide a way to end a session--with a script that makes a call to session_destroy( )--there is no guarantee that a user will log out by requesting the appropriate PHP script. PHP session management has a built-in garbage collection mechanism that ensures unused session files are eventually cleaned up. This is important for two reasons: it prevents the directory from filling up with session files that can cause performance to degrade and, more importantly, it reduces the risk of someone guessing session IDs and hijacking an old unused session.

There are two parameters that control garbage collection: session.gc_maxlifetime and session.gc_probability, both defined in the php.ini file. A garbage collection process is run when a session is initialized, for example, when session_start( ) is called. Each session is examined by the garbage collection process, and any sessions that have not been accessed for a specified period of time are removed. This period is specified as seconds of inactivity in the gc_maxlifetime parameter--the default value being 1,440 seconds. The file-based session management uses the update time of the file to determine the last access. To prevent the garbage collection process from removing active session files, PHP must modify the update time of the file when session variables are read, not just when they are written.

The garbage collection process can become expensive to run, especially in sites with high numbers of users, because the last-modified date of every session file must be examined. The second parameter gc_probability sets the percentage probability that the garbage collection process will be activated. A setting of 100% ensures that sessions are examined for garbage collection with every session initialization. The default value of 1% means that garbage collection occurs with a probability of 1 in 100.[1] Depending on the requirements, some figure between these two extremes balances the needs of the application and performance. Unless a site is receiving less that 1,000 hits per day, the probability should be set quite low. For example, an application that receives 1,000 hits in a 10-hour period with a gc_probability setting of 10% runs the garbage collection function, on average, once every 6 minutes. Setting the gc_probability too high adds unnecessary processing load on the server.

When it is important to prevent users from accessing old sessions, the gc_probability should be increased. For example, the default session configuration sets up a cookie in the browser to be deleted when the browser program is terminated. This prevents a user from accidentally reconnecting to an old session. However, if the session ID is encoded into a URL, a bookmarked page can find an old session if it still exists. If session IDs are passed using the GET method, you should increase the probability of running garbage collection.

Configuration of PHP Session Management

There are several parameters that can be manipulated to change the behavior of the PHP session management. These parameters are set in the php.ini file in the section headed [Session].

session.save_handler
This parameter specifies the method used by PHP to store and retrieve session variables. The default value is files, to indicate the use of session files, as described in the previous sections. The other values that this parameter can have are: mm to store and retrieve variables from shared memory, and user to store and retrieve variables with user-defined handlers. In Appendix D we describe how to create user-defined handlers to store session variables in a MySQL database.

session.save_path
This parameter specifies the directory in which session files are saved when the session.save_handler is set to files. The default value is /tmp. When implementing user-defined save_handler methods, the value of this parameter is passed as an argument to the function that opens a session. User-defined handlers are discussed in Appendix D.

session.use_cookies
This parameter determines if PHP sets a cookie to hold the session ID. Setting this parameter to 0 stops PHP from setting cookies and may be considered for the reasons discussed in the previous section. The default value is 1, meaning that a cookie stores the session ID.

session.name
This parameter controls the name of the cookie, GET attribute, or POST attribute that is used to hold the session ID. The default is PHPSESSID, and there is no reason to change this setting unless there is a name collision with another variable.

session.auto_start
With the default value of 0 for this setting, PHP initializes a session only when a session call such as session_start( ) or session_register( ) is made. If this parameter is set to 1, sessions are automatically initialized if a session ID is found in the request. Allowing sessions to autostart adds unnecessary overhead if session values aren't required for all scripts.

session.cookie_lifetime
This parameter holds the life of a session cookie in seconds and is used by PHP when setting the expiry date and time of a cookie. The default value of 0 sets up a session cookie that lasts only while the browser program is running. Setting this value to a number of seconds other than 0 sets up the cookie with an expiry date and time. The expiry date and time of the cookie is set as an absolute date and time, calculated by adding the cookie_lifetime value to the current date and time on the server machine.[2]

session.cookie_path
This parameter sets the valid path for a cookie. The default value is /, which means that browsers include the session cookie in requests for resources in all paths for the cookie's domain. Setting this value to the path of the session-based scripts can reduce the number of requests that need to include the cookie. For example, setting the parameter to /winestore instructs the browser to include the session cookie only with requests that start with http://www.webdatabasebook.com/winestore/.

session.cookie_domain
This parameter can override the domain for which the cookie is valid. The default is a blank string, meaning that the cookie is set with the domain of the machine running the web server, and the browser includes the cookie only in requests sent to that domain.

session.cookie_secure
This parameter sets the secure flag of a cookie, which prevents a browser from sending the session cookie over nonencrypted connections. When this setting is 1, the browser sends the session cookie over a network connection that is protected using the Secure Sockets Layer, SSL. We discuss SSL in the next chapter and provide installation instructions in Appendix A. The default value of 0 allows a browser to send the session cookie over encrypted and nonencrypted services.

session.serialize_handler
This parameter sets up the method by which variables are serialized, that is, how they are converted into a stream of bytes suitable for the chosen session store. The default value is php, which indicates use of the standard PHP serialization functions. An alternative is wddx, which uses the WDDX libraries that encode variables as XML.

session.gc_probability
This parameter determines the probability that the garbage collection process will be performed when a session is initialized. The default value of 1 sets a 1% chance of garbage collection. See the discussion in the previous section for a full explanation of garbage collection.

session.gc_maxlifetime
This parameter sets the life of a session in number of seconds. The default value is 1440, or 24 minutes. Garbage collection destroys a session that has been inactive for this period. See the discussion in the previous section for a full explanation of garbage collection.

session.referer_check
This parameter can restrict the creation of sessions to requests that have the HTTP Referer: header field set. This is a useful feature if access to an application is allowed only by following a hypertext link from a particular page such as a welcome page. If the HTTP Referer header field doesn't match the value of this parameter, PHP creates a session, but the session is marked as invalid and unusable. The default value of a blank string applies no restriction.

session.entropy_file
PHP generates the session IDs from a random number seeded by the system date and time. Because the algorithm is known--it can be looked up in the PHP source code--it makes guessing session IDs a little easier. If this parameter is set to the name of a file, the first n bytes from that file (where n is specified by the session.entropy_length parameter) make the ID less predictable. The default value is left blank, meaning the default seeding method is used. One alternative is to use /dev/urandom, a special Unix device that produces a pseudorandom number.

session.entropy_length
This parameter is the number of bytes to use when generating a session ID from the file specified by session.entropy_file. The default value is 0, the required value when no entropy file is set.

session.cache_limiter
This parameter controls how responses can be cached by the browser. The default is nocache, meaning that PHP sets up the HTTP response to avoid browser caching. PHP sets the HTTP/1.1-defined header field Cache-Control to no-cache, the HTTP/1.0 header field Pragma to no-cache, and--for good measure--the Expires header field to Thu, 19 Nov 1981 08:52:00 GMT. Applications that use sessions--and even stateless web database applications--can be adversely affected when browsers cache pages. The other values allowed, private and public, allow responses to be cached. The distinction between private and public is apparent when a proxy server caches responses. See Appendix B for more details about HTTP caching.

session.cache_expire
This parameter is used when caching is allowed; it sets the expiry date and time of the response to be the current system time plus the parameter value in minutes. The default value is 180.

Case Study: Adding Sessions to the Winestore

In this section we use sessions to improve the user interaction with the client entry <form> developed in Chapter 6. The improvements focus on the interaction when the <form> is submitted and fields don't validate. We modify the scripts to:

Improving the Client Entry <form>

The client entry <form>, generated by the script shown in Example 6-7, collects client fields to either create a new client or edit the details of an existing client. The script shown in Example 6-8 performs the server-side validation of the client <form> data, and updates or inserts a row in the customer table if there are no errors.

If the validation fails, the script shown in Example 6-8 generates a page to display the errors to the user, and the user then follows a hypertext link back to the client entry <form> to reenter the fields. The solution provided by Examples 6-7 and 6-8 suffers three problems:

In this section we develop the scripts to make use of session variables to solve these problems. Rather than displaying the error messages on a page generated by the validation script, we make the necessary changes to display the errors in red above the appropriate fields on the client entry <form>, as shown in Figure 8-2.

Figure 8-2. Client entry <form> showing error messages placed above the appropriate fields

 

Both the script that generates the client entry <form> and the script that validates the data need to be modified to use sessions and the session variables. Because the validation script processes the fields collected in the client <form> and generates any associated errors, we look at the changes required for that script first.

The Validation Script

We begin the improvements to the validation script with the changes required to support an error message session variable and then discuss how to record the values to pass back to the client entry <form> generation code. We then present the complete structure of the modified validation script.

Improving error messages

We examine the changes required for error messages first. The validation script checks each variable submitted from the client <form>. Each field is checked with more or less rigor, depending on the purpose of the field. The script shown in Example 6-8 builds up a long formatted error message by concatenating error messages together as they are found. In the modified script, an associative array is registered to hold error messages associated with each field. This allows more flexibility when displaying the error messages.

First, we need to initialize a session and register a variable to hold an array of errors. This is achieved by adding the following lines to the start of the script:

// Initialize a session
session_start(  );
 
// Register an error array - just in case!
if (!session_is_registered("errors"))
   session_register("errors");
 
// Clear any errors that might have been 
// found previously
$errors = array(  );

Because this validation script may be called several times in a session, any errors that may have been recorded previously need to be cleared. This is the reason for setting the $errors value to a new, empty array.

The script checks each variable and adds an error message to the associative array $errors if an error is encountered. The error message is indexed by the name of the field being checked. For example, the validation of the surname is coded as:

// Validate the Surname
if (empty($formVars["surname"]))
   // the user's surname cannot be a null string
    $errors["surname"] = 
        "The surname field cannot be blank.";

Once all the fields have been validated, you can test the size of the array $errors to determine if any errors were encountered. If the size of the $errors array is 0, you create or update the row as before. If there are any error messages in the array, you need to display them.

// Now the script has finished the validation, 
// check if there were any errors
if (count($errors))
{
    // There are errors. Relocate back to the 
    // client form
    header("Location: example.8-5.php");
    exit;
}

In Example 6-8, the script itself displays any errors, and because the request contains variables in a POST method request, the resulting page suffers from the reload problem discussed in Chapter 6. In a nonsession-based environment, this problem can't be solved with a Location: header field, as the error messages are lost. In the validation script developed here, we relocate back to the client entry <form>--shown later, in Example 8-5--and let it display the errors held in the session variable $errors. We show the changes that allow the client entry <form> to display error messages in the next section.

Saving last-entered values as a session variable

We now develop the script to pass the field data from the validation script back to the client entry <form> to avoid rekeying when an error occurs. The script is modified by saving the user-entered data in another session variable, the associative array $formVars. The client details <form> already uses an array, $formVars, to populate the entry fields from a customer record when editing an existing client. By setting the $formVars session variable in the validation script, the client entry <form> populates the <input> fields with the values that were last entered.

The following code--inserted just after $errors is registered as a session variable--registers the array $formVars and then loops through each user-entered variable, setting a value in the array, indexed by the name of the variable. Note that the clean( ) function described in Chapter 5 is used to secure the user data.

// Set up a $formVars array with the POST variables
// and register with the session.
if (!session_is_registered("formVars"))
   session_register("formVars");
 
foreach($HTTP_POST_VARS as $varname => $value)
    $formVars[$varname] = trim(clean($value, 50));

When the modified client entry <form> is run, the most recent values entered from the session variable $formVars are shown.

WARNING:   While the $HTTP_POST_VARS associative array can be stored in a session and accessed like any other session variable, there is a catch. The value of $HTTP_POST_VARS is determined by PHP before scripts are run. If a session has registered a variable with the name $HTTP_POST_VARS, the values held in $HTTP_POST_VARS that were set up by PHP--as a result of processing a POST request--are overwritten by the session variable.

If register_globals is enabled in php.ini, the GET or POST variables PHP sets up can also be overwritten by session variables with the same name.

The safe way to read cookies, GET, and POST variables that have name conflicts is to use the $HTTP_COOKIE_VARS, $HTTP_GET_VARS, and $HTTP_POST_VARS associative arrays, as discussed in Chapter 6.

The final change needed in Example 6-8 is to destroy the session when the script successfully saved a row in the customer table:

// Clear the session 
session_destroy(  );

The final validation script

Example 8-4 shows the final validation script derived from Example 6-8.

Example 8-4: The complete validation script derived from Example 6-8

<?php
  include 'db.inc';
  include 'error.inc';
  
  // Initialize a session
  session_start(  );
  
  // Register an error array - just in case!
  if (!session_is_registered("errors"))
     session_register("errors");
  
  // Clear any errors that might have been 
  // found previously
  $errors = array(  );
  
  // Set up a $formVars array with the POST variables
  // and register with the session.
  if (!session_is_registered("formVars"))
     session_register("formVars");
  
  foreach($HTTP_POST_VARS as $varname => $value)
      $formVars[$varname] = trim(clean($value, 50));
  
  // Vaildate the firstName
  if (empty($formVars["firstName"])) 
      // First name cannot be a null string
      $errors["firstName"] = 
          "The first name field cannot be blank.";
    
  // Validate the Surname
  if (empty($formVars["surname"]))
      // the user's surname cannot be a null string
      $errors["surname"] = 
          "The surname field cannot be blank.";
  
  // Validate the Address
  if (empty($formVars["address1"]))
      // all the fields of the address cannot be null
      $errors["address"] = 
          "You must supply at least one address line.";
  
  // Validate the City
  if (empty($formVars["city"]))
      // the user's city cannot be a null string
      $errors["city"] = "You must supply a city.";
  
  // Validate Date of Birth
  if (empty($formVars["dob"]))
      // the user's date of birth cannot be a 
      // null string
      $errors["dob"] = 
        "You must supply a date of birth.";
  
  elseif (!ereg("^([0-9]{2})/([0-9]{2})/([0-9]{4})$",
          $formVars["dob"], 
          $parts))
      // Check the format
      $errors["dob"] = 
        "The date of birth is not a valid date " .
        "in the format DD/MM/YYYY";  
  
  if (empty($formVars["email"])) 
      // the user's email cannot be a null string
      $errors["email"] = 
        "You must supply an email address.";
  
  // Now the script has finished the validation, 
  // check if there were any errors
  if (count($errors))
  {
      // There are errors.  Relocate back to the 
      // client form
      header("Location: example.8-5.php");
      exit;
  }
 
  // If we made it here, then the data is valid
 
  if (!($connection = @ mysql_pconnect($hostName, 
                                       $username, 
                                       $password)))
     showerror(  );
 
  if (!mysql_select_db($databaseName, $connection))
     showerror(  );
     
  // Reassemble the date of birth into database format
  $dob = " \"$parts[3]-$parts[2]-$parts[1]\"";
  
  // Is this an update?
  if (!empty($custID))
  {
    $query = "UPDATE customer SET ". 
      "surname = \"" . $formVars["surname"] . "\", " .
      "firstname = \"" . $formVars["firstName"] . "\", " .
      "addressline1 = \"" . 
                    $formVars["address1"] . "\", " .
      "city = \"" . $formVars["city"] . "\", " .
      "email = \"" . $formVars["email"] . "\", " .
      "birth_date = " . $dob . 
      " WHERE cust_id = $custID";
  }
  else
     // Create a query to insert the customer
     $query = "INSERT INTO customer SET" .
       "cust_id = NULL, " .
       "surname = \"" . $formVars["surname"] . "\", " .
       "firstname = \"" . 
                    $formVars["firstName"] . "\", " .                    
       "addressline1 = \"" . 
                    $formVars["address1"] . "\", " .
       "city = \"" . $formVars["city"] . "\", " .
       "email = \"" . $formVars["email"] . "\", " .
       "birth_date = $dob";
 
  // Run the query on the customer table
  if (!(@ mysql_query ($query, $connection)))
     showerror(  );   
 
  // Is this an insert?
  if (empty($custID))
  // Find out the cust_id of the new customer
  $custID = mysql_insert_id(  );
 
  // Clear the session 
  session_destroy(  );
  
  // Now show the customer receipt
  header("Location: customer_receipt.php?custID=$custID");
?>

The Client Entry <form> Script

Now let's turn to the changes required for the script that generates the client entry <form> shown in Example 6-7. In the last section, we set up two session variables: the associative array $errors used to hold a list of error messages found in the validation script and the associative array $formVars used to hold the POST variables you processed.

Displaying previously entered values

As Example 6-7 already sets the value attribute of the <input> elements from the array $formVars, there are no changes needed to display previously entered values; Example 6-7 uses $formVars when displaying the current values of clients from the customer table. By setting $formVars as a session variable, Example 6-7 displays the values passed back from the validation script with each <input> field.

Displaying error messages

Changes are required to display the errors that are saved in the session variable $errors in the validation script. We have added the function fieldError( ) to help display the error messages above the <input> fields. The function takes two parameters: $errors, which is the associative array of error messages, and $fieldName, which is the index into the array.

function fieldError($fieldName, $errors)
{
  if (isset($errors[$fieldName]))
    echo 
    "<font color=RED>$errors[$fieldName]</font><br>";
}

This function tests if the indexed error message exists and, if so, echoes an appropriately formatted error message. When each <input> element is displayed, a call is made to the fieldError( ) function, as shown for the firstName and surname fields:

<tr>
  <td><font color="red">First name:</font></td>
  <td><? echo fieldError("firstName", $errors); ?>
      <input type="text" name="firstName" 
         value="<? echo $formVars["firstName"]; ?>" 
         size=50></td>
</tr>
<tr>
  <td><font color="red">Surname:</font></td>
  <td><? echo fieldError("surname", $errors); ?>
      <input type="text" name="surname" 
         value="<? echo $formVars["surname"]; ?>" 
         size=50></td>
</tr>

Figure 8-2 shows the final results: a client entry <form> with error messages placed over the corresponding fields.

The final client entry script

Example 8-5 shows the complete client entry script, derived from Example 6-7, that displays the previous <form> values and the error messages held in session variables.

Example 8-5: Client entry form derived from Example 6-7

<?php
  include 'db.inc';
  include 'error.inc';
 
  function fieldError($fieldName, $errors)
  {
     if (isset($errors[$fieldName]))
        echo 
        "<font color=RED>$errors[$fieldName]</font><br>";
  }    
 
  // Connect to a session.
  // Up to three session variables can be registered:
  // (1) $formVars - previously entered data that has 
  //     failed validation
  // (2) $errors - an array of error messages, up to 
  //     one per widget
  // (3) $custID - the customer ID of a customer 
  //     to edit
  session_start(  );
 
  // $custID can also be passed as a GET parameter
  // If it is, override any session variable
  if (!empty($HTTP_GET_VARS["custID"]))
     $custID = clean($HTTP_GET_VARS["custID"], 5);
 
  // Has a custID been provided and are there no errors? 
  // If so, retrieve the customer details for editing.
  if (!empty($custID) && empty($errors))
  {
     // Register the custID as a session variable
     if (!session_is_registered("custID"))
        session_register("custID");
 
     if (!($connection = @ mysql_pconnect($hostName, 
                                         $username, 
                                         $password)))
        die("Could not connect to database");
 
     if (!mysql_select_db($databaseName, $connection))
        showerror(  );
  
     $query = "SELECT * FROM customer 
               WHERE cust_id = " . $custID;
  
     if (!($result = @ mysql_query($query, $connection)))
        showerror(  );
  
     $row = mysql_fetch_array($result);
  
     // Reset $formVars, since we're loading from 
     // the customer table
     $formVars = array(  );
  
     // Load all the form variables with customer data
     $formVars["surname"] = $row["surname"];
     $formVars["firstName"] = $row["firstname"];
     $formVars["address1"] = $row["addressline1"];
     $formVars["city"] = $row["city"];
     $formVars["email"] = $row["email"];
     $formVars["dob"] = $row["birth_date"];
     $formVars["dob"] = 
            substr($formVars["dob"], 8, 2) . "/" .
            substr($formVars["dob"], 5, 2) . "/" .   
            substr($formVars["dob"], 0, 4);
  }
?>
<!DOCTYPE HTML PUBLIC 
   "-//W3C//DTD HTML 4.0 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd" >
<html>
<head><title>Customer Details</title></head>
<body bgcolor="white">  
<form method="post" action="example.8-4.php">
<h1>Customer Details</h2>
<?php
  // Show meaningful instructions for UPDATE or INSERT
  if (!empty($custID))
     echo "<h3>Please amend your details below as 
           required. Fields shown in 
           <font color=\"red\">red</font> are 
           mandatory.</h3>";
  else
     echo "<h3>Please fill in the details below to 
           join. Fields shown in 
           <font color=\"red\">red</font> are 
           mandatory.</h3>";
?>
<table>
<col span="1" align="right">
 
<tr><td><font color="red">First name:</font></td>
    <td><? echo fieldError("firstName", $errors); ?>
        <input type="text" name="firstName" 
           value="<? echo $formVars["firstName"]; ?>" 
           size=50></td>
</tr>
<tr><td><font color="red">Surname:</font></td>
    <td><? echo fieldError("surname", $errors); ?>
        <input type="text" name="surname" 
           value="<? echo $formVars["surname"]; ?>" 
           size=50></td>
</tr>
<tr><td><font color="red">Address:</font></td>
    <td><? echo fieldError("address", $errors); ?>
        <input type="text" name="address1" 
           value="<? echo $formVars["address1"]; ?>" 
           size=50><td>
</tr>
<tr><td><font color="red">City:</font></td>
    <td><? echo fieldError("city", $errors); ?>
        <input type="text" name="city" 
           value="<? echo $formVars["city"]; ?>" 
           size=20><td>
</tr>
<tr><td><font color="red">Email/username:</font></td>
    <td><? echo fieldError("email", $errors); ?>
        <input type="text" name="email" 
            value="<? echo $formVars["email"]; ?>"
            size=30><td>
</tr>
<tr><td>
    <font color="red">Date of birth (dd/mm/yyyy):</font>
    </td>
    <td><? echo fieldError("dob", $errors); ?>
        <input type="text" name="dob" 
           value="<? echo $formVars["dob"]; ?>" 
           size=10><td>
</tr>
</table><br>
<input type="submit" value="SUBMIT">
</form>
</body>
</html>

When to Use Sessions

So far in this chapter we have described how to implement stateful applications using sessions, but we have not discussed when they should or should not be used. Sessions allow some kinds of applications to be developed that otherwise would be difficult to implement on the Web. However, because HTTP is a stateless protocol, building a stateful application can present problems and restrictions. Avoiding the need to maintain state information is often a desirable goal. In this section we list some reasons sessions are used and some reasons to avoid them.

Reasons to Use Sessions

Sessions can be used in web database applications for several reasons. Many traditional database applications use sessions to help control user interaction, while other applications use sessions to reduce server processing.

Performance

In a stateless environment, an application may need to repeat an expensive operation. An example might be a financial calculation that requires many SQL statements and calls to mathematics libraries before displaying the results on several web pages. An application that uses a session variable to remember the result exposes the user, and the server, to the cost of the calculation only once.

Sequence of interaction

Often a database application--or indeed any application--needs to present a series of screens in a controlled order. One style of application--known as a wizard--guides a user through what would otherwise be a complex task with a series of screens. Wizards are sometimes used for complex configurations, such as some software installations, and often alter the flow of screens based on user input. Some applications require that a user enter via a known page. Applications, such as online banking, often force a user to enter via a login page rather than allow access directly to a function such as funds transfer.

Intermediate results

Many database applications validate data before creating or updating a record in the database, preventing erroneous data from being saved. Sessions can keep the intermediate data, so that incomplete data can be edited--rather that rekeyed--when errors are detected. Earlier in this chapter we used sessions to improve the interaction between the client entry <form> and validation scripts of the winestore application. In the case study, the fields entered by the user are held in an array as a session variable until the validation is successful. Another example where intermediate results can be used is when a database application collects and validates data for a single record over a number of fill-in forms. A shopping cart is an example where complete data may not be created until a user requests a purchase. The winestore application doesn't implement the shopping cart this way; rather, a shopping cart is implemented by creating a row in the orders table and adding rows to the items table as items are selected. The winestore application then needs to store only the cust_id and the order_no--the combination is the primary key of the orders table--as session variables while a shopping cart is being used. We develop the shopping cart in Chapter 11.

Personalization

Sessions can personalize a web site. Personalization not only includes background color or layout alternatives, but can include recording a user's interests and modifying searches. The winestore application can record favorite regions or a buyer's price range as session variables; each query could then be modified to reflect these settings. A result screen displays "wines from your favorite regions within your budget" before displaying other wines.

Reasons to Avoid Sessions

The reasons to avoid sessions focus mainly on the stateless nature of HTTP. The features of HTTP that support browsing access to a disparate collection of resources don't support stateful applications. Stateful applications work over the Web often at the expense of HTTP features.

Need for centralized session store

In an application that uses sessions, each HTTP request needs to be processed in the context of the session variables to which that request belongs. The state information recorded as the result of one request needs to be available to subsequent requests. Most applications that implement sessions store session variables in the middle tier. Once a session is created, all subsequent requests must be processed on the web server that holds the session variables. This requirement prevents such applications from using HTTP to distribute requests across multiple servers and therefore can't easily scale horizontally to handle large numbers of requests.[3] One way for a web database application to allow multiple web servers is to store session variables in the database tier. This approach is described in Appendix D, where we provide a PHP and MySQL implementation of a database-tier session store.

Performance

When a server that offers session management processes a request, there is the unavoidable overhead of identifying and accessing session variables. The session overhead results in longer processing times for requests, which affects the performance and capacity of a site. While sessions can improve application performance--for example, a session can keep the result of an expensive operation--the gains may be limited and outweighed by the extra processing required. Servers that manage session variables in memory require more memory. As the amount of memory used by the web server grows, a system may need to move portions of memory to disk--an operation known as swapping. Swapping memory in and out of disk storage is slow and can severely degrade the performance of a server. Servers that use files--such as the default PHP session management--incur the cost of reading and writing a file on disk each time a session is accessed.

Timeouts

Sessions can also cause synchronization problems. Because HTTP is stateless, there is no way of knowing when a user has really finished with an application. Other network applications can catch the fact that a connection has been dropped and clean up the state that was held on behalf of that user, even if the user did not use a logout procedure (such as typing exit or clicking on a logout button). The Telnet application is such an example where a user makes a connection to a system over the Internet. However, unlike HTTP, the TCP/IP connection for Telnet is kept for the length of the session, and if the connection is lost--say, if the client's PC crashes or the power is lost--the user is logged out of the remote system. With a session over the Web, the server doesn't know about these events and has to make a decision as to how long to keep the session information. In the case of PHP session management, a garbage collection scheme is used, as we discussed earlier in this chapter.

Bookmark restrictions

Because HTTP is stateless, browsers allow users to save URLs as a list of bookmarks or favorite sites. The user can return to a web site at a later date by simply selecting a bookmarked URL. Web sites that provide weather forecasts, stock prices, and even search results from a web search engine are examples of the sites a user might want to bookmark. Consider the URL for a fictional site that provides stock prices:

http://www.someexchange.com/stockprice.php?code=SIMCO

The URL encodes a query that identifies a particular stock, and presumably, the script stockprice.php uses the query to display the current stock price of the company. The URL can be bookmarked because it contains all that is needed to generate the stock price page for the given company code. An alternative site may collect the company code using a <form> and, when the form is submitted, use a session variable to hold the company code as a query. The script that generates the stock price page reads the session variable, looks up the current price, and generates the result for the entered company code. If a user bookmarks the session-based stock price page and comes back in a week, the session that stored the company code is unlikely to still exist, and the script fails to display the desired company's stock price.

Sometimes bookmarking a page makes no sense. Consider an online banking application that allows transfer of funds between two accounts. A user would log in to the application, then request the transfer page that collects the source and target account details in a <form>. When that <form> is submitted, a confirmation page is shown without actually performing the transaction. Revisiting this page through a bookmark has no meaning if the transaction was subsequently confirmed or canceled. Generally, the pages generated from applications such as online banking can't be bookmarked because of the reliance on session variables. Session management in such applications is often tied closely to authentication, a topic explored further in Chapter 9.

Security

Sessions can provide a way for a hacker to break into a system. Sessions can be open to hijacking; a hacker can take over after a legitimate user has logged into an application. There is much debate about the security of session-based applications on the Web, and we discuss some issues of session security in the next chapter.


1. Perhaps the gc_maxlifetime parameter should have been called gc_minlifetime, because the value represents the minimum time garbage collection permits an inactive session to exist. Remember that garbage collection is performed only when a request that initializes a session is made, and then only with the probability set by gc_probability.

2. The actual expiry of the cookie is performed by the browser, which compares the expiry date and time of the cookie with the client machine's date and time. If the date and time are incorrectly set on the client, a cookie might expire immediately or persist longer than expected.

3. Scaling up an application--increasing the number of requests an application can respond to in a given period--can be achieved horizontally by providing more machines, and vertically by providing a single bigger, faster, or more efficient machine.

Back to: Web Database Applications with PHP & MySQL


oreilly.com Home | O'Reilly Bookstores | How to Order | O'Reilly Contacts
International | About O'Reilly | Affiliated Companies | Privacy Policy

© 2001, O'Reilly & Associates, Inc.
webmaster@oreilly.com