These days, using HTTP sessions to track persistent information such as user preferences within even the simplest of applications is more the rule than the exception. Therefore, no matter whether you are completely new to Web development or are a grizzled veteran hailing from another language, you should take time to carefully read this chapter.
Available since the version 4.0 release, PHP's session-handling capabilities remain one of the coolest and most discussed features. In this chapter you'll learn all about the feature, including:
The Hypertext Transfer Protocol (HTTP) defines the rules used to transfer text, graphics, video, and all other data via the World Wide Web. It is a stateless protocol, meaning that each request is processed without any knowledge of any prior or future requests. Although HTTP's simplicity is a significant contributor to its ubiquity, its stateless nature has long been a problem for developers who wish to create complex Web-based applications that must be able to adjust to user-specific behavior and preferences. To remedy this problem, the practice of storing bits of information on the client's machine, in what are commonly called cookies, quickly gained acceptance, offering some relief to this conundrum. However, limitations on cookie size and the number of cookies allowed, and various inconveniences surrounding their implementation, prompted developers to devise another solution: session handling.
Session handling is essentially a clever workaround to this problem of statelessness. This is accomplished by assigning to each site visitor a unique identifying attribute, known as the session ID (SID), and then correlating that SID with any number of other pieces of data, be it number of monthly visits, favorite background color, or middle name—you name it. In relational database terms, you can think of the SID as the primary key that ties all the other user attributes together. But how is the SID continually correlated with the user, given the stateless behavior of HTTP? It can be done in two different ways:
Because PHP can be configured to autonomously control the entire session-handling process with little programmer interaction, you may consider the gory details somewhat irrelevant. However, there are so many potential variations to the default procedure that taking a few moments to better understand this process would be well worth your time.
The very first task executed by a session-enabled page is to determine whether a valid session already exists or a new one should be initiated. If a valid session doesn't exist, one is generated and correlated with that user, using one of the SID propagation methods described earlier. PHP determines whether a session already exists by finding the SID either within the requested URL or within a cookie. However, you're also capable of doing so programmatically. For instance, if the session name is sid
and it's appended to the URL, you could retrieve the value with the following variable:
$_GET['sid']
If it's stored within a cookie, you can retrieve it like this:
$_COOKIE['sid']
Once retrieved, you can either begin correlating information with that SID or retrieve previously correlated SID data. For example, suppose that the user is browsing various news articles on the site. Article identifiers could be mapped to the user's SID, allowing you to compile a list of articles that the user has read, and display that list as the user continues to navigate. In the coming sections, you'll learn how to store and retrieve this session information.
Tip You can also retrieve cookie information via the $_REQUEST
superglobal. For instance, if the session name is sid, $_REQUEST['sid'] will retrieve the SID, just as $_COOKIE['sid'] would. However, for purposes of clarity, consider using the superglobal that best matches the variable's place of origin.
This process continues until the user either closes the browser or navigates to an external site. If you use cookies, and the cookie's expiration date has been set to some date in the future, should the user return to the site before that expiration date, the session could be continued as if the user never left. If you use URL rewriting, the session is definitively over, and a new one must begin the next time the user visits the site.
In the coming sections, you'll learn about the configuration directives and functions responsible for carrying out this process.
Almost 30 configuration directives are responsible for tweaking PHP's session-handling behavior. Because many of these directives play such an important role in determining this behavior, you should take some time to become familiar with the directives and their possible settings. The most relevant are introduced in this section.
The session.save_handler
directive determines how the session information will be stored. Its prototype looks like this:
session.save_handler = files|mm|sqlite|user
Session data can be stored in four ways: within flat files (files
), within volatile memory (mm
), using the SQLite database (sqlite
), or through user-defined functions (user
). Although the default setting, files
, will suffice for many sites, keep in mind for active Web sites that the number of session-storage files could potentially run into the thousands, and even the hundreds of thousands over a given period of time.
The volatile memory option is the fastest for managing session data, but also the most volatile because the data is stored in RAM. The sqlite
option takes advantage of the new SQLite extension to manage session information transparently using this lightweight database (see Chapter 22 for more information about SQLite). The fourth option, although the most complicated to configure, is also the most flexible and powerful, because custom handlers can be created to store the information in any media the developer desires. Later in this chapter you'll learn how to use this option to store session data within a MySQL database.
If session.save_handler
is set to the files
storage option, then the session.save_path
directive must be set in order to identify the storage directory. Its prototype looks like this:
session.save_path = string
By default session.save_path
is set to /tmp
. Keep in mind that this should not be set to a directory located within the server document root, because the information could easily be compromised via the browser. In addition, this directory must be writable by the server daemon.
For reasons of efficiency, you can define session.save_path using the syntax N;/path, where N is an integer representing the number of subdirectories N-levels deep in which session data can be stored. This is useful if session.save_handler
is set to files
and your Web site processes a large number of sessions, because it makes storage more efficient since the session files will be divided into various directories rather than stored in a single, monolithic directory. If you do decide to take advantage of this feature, PHP will not automatically create these directories for you. However, Linux users can automate the process by executing a script named mod_files.sh
, located in the ext/session
directory. If you're using Windows, this shell script isn't supported, although writing a compatible script using VBScript should be fairly trivial.
By default a page will be session-enabled only by calling the function session_start()
(introduced later in the chapter). However, if you plan on using sessions throughout the site, you can forgo using this function by setting session.auto_start
to 1
. Its prototype follows:
session.auto_start = 0|1
One drawback to enabling this directive is that it prohibits you from storing objects within sessions, because the class definition would need to be loaded prior to starting the session in order for the objects to be re-created. Because session.auto_start would preclude that from happening, you need to leave this disabled if you want to manage objects within sessions.
By default PHP will use a session name of PHPSESSID
. However, you're free to change this to whatever name you desire using the session.name directive. Its prototype follows:
session.name = string
If you'd like to maintain a user's session over multiple visits to the site, you should use a cookie so the SID can be later retrieved. If user data is to be used only over the course of a single site visit, then URL rewriting will suffice (although you should keep in mind the URL rewriting security issues mentioned earlier in this chapter). You can choose the method using session.use_cookies
. Setting this directive to 1
(the default) results in the use of cookies for SID propagation; setting it to 0
causes URL rewriting to be used. Its prototype follows:
session.use_cookies = 0|1
Keep in mind that when session.use_cookies
is enabled, there is no need to explicitly call a cookie-setting function (via PHP's set_cookie()
, for example), because this will be automatically handled by the session library. If you choose cookies as the method for tracking the user's SID, then there are several other directives that you must consider, each of which is introduced in the following entries.
If session.use_cookies
is disabled, the user's unique SID must be attached to the URL in order to ensure ID propagation. This can be handled either explicitly, by manually appending the variable $SID
to the end of each URL, or automatically, by enabling the directive session.use_trans_sid
. Its prototype follows:
session.use_trans_sid = 0|1
Not surprisingly, if you commit to using URL rewrites, you should enable this directive to eliminate the possibility of human error during the rewrite process.
The session.cookie_lifetime
directive determines the session cookie's period of validity. Its prototype follows:
session.cookie_lifetime = integer
The lifetime is specified in seconds, so if the cookie should live 1 hour, then this directive should be set to 3600
. If this directive is set to 0
(the default), then the cookie will live until the browser is restarted.
The directive session.cookie_path
determines the path in which the cookie is considered valid. The cookie is also valid for all child directories falling under this path. Its prototype follows:
session.cookie_path = string
For example, if it is set to /
, then the cookie will be valid for the entire Web site. Setting it to /books
causes the cookie to be valid only when called from within the http://www.example.com/books/ path.
Setting the Session Cookie's Valid Domain
The directive session.cookie_domain
determines the domain for which the cookie is valid. This directive is necessary because it prevents other domains from reading your cookies. Its prototype follows:
session.cookie_domain = string
The following example illustrates its use:
session.cookie_domain = www.example.com
If you'd like a session to be made available for site subdomains, say customers. example.com
, intranet.example.com
, and www2.example.com
, set this directive like this:
session.cookie_domain = .example.com
Validating Sessions Using a Referer
Using URL rewriting as the means for propagating session IDs opens up the possibility that a particular session state could be viewed by numerous individuals simply by copying and disseminating a URL. The session.referer_check
directive lessens this possibility by specifying a substring that each referrer is validated against. If the referrer does not contain this substring, the SID will be invalidated. Its prototype follows:
session.referer_check = string
When working with sessions, you may want to exert greater control over how session-enabled pages are cached by the user's browser and by any proxies residing between the server and user. The session.cache_limiter
directive modifies these pages' cache-related headers, providing instructions regarding caching preference. Its prototype follows:
session.cache_limiter = string
Five values are available:
none:
nocache:
private:
private_no_expire:
private
designation, resulting in no document expiration date being sent to the browser. This was added as a workaround for various browsers that became confused by the Expire
header sent along when this directive is set to private
.public:
Setting Cache Expiration Time for Session-Enabled Pages
The session.cache_expire directive determines the number of seconds (180 by default) that cached session pages are made available before new pages are created. Its prototype follows:
session.cache_expire = integer
If session.cache_limiter
is set to nocache
, this directive is ignored.
Setting the Session Lifetime
The session.gc_maxlifetime
directive determines the duration, in seconds (by default 1440
), for which a session is considered valid. Its prototype follows:
session.gc_maxlifetime = integer
Once this limit is reached, the session information will be destroyed, allowing for the recuperation of system resources.
This section introduces many of the key session-handling tasks, presenting the relevant session functions along the way. Some of these tasks include the creation and destruction of a session, designation and retrieval of the SID, and storage and retrieval of session variables. This introduction sets the stage for the next section, in which several practical session-handling examples are provided.
Remember that HTTP is oblivious to both the user's past and future conditions. Therefore, you need to explicitly initiate and subsequently resume the session with each request. Both tasks are done using the session_start()
function. Its prototype looks like this:
boolean session_start()
Executing session_start()
will create a new session if no SID is found, or continue a current session if an SID exists. You use the function simply by calling it like this:
session_start();
Note that the session_start()
function reports a successful outcome regardless of the result. Therefore, using any sort of exception handling in this case will prove fruitless.
You can eliminate execution of this function altogether by enabling the configuration directive session.auto_start. Keep in mind, however, that this will start or resume a session for every PHP-enabled page.
Although you can configure PHP's session-handling directives to automatically destroy a session based on an expiration time or probability, sometimes it's useful to manually cancel out the session yourself. For example, you might want to enable the user to manually log out of your site. When the user clicks the appropriate link, you can erase the session variables from memory, and even completely wipe the session from storage, done through the session_unset() and session_destroy() functions, respectively.
The session_unset() function erases all session variables stored in the current session, effectively resetting the session to the state in which it was found upon creation (no session variables registered). Its prototype looks like this:
void session_unset()
While executing session_unset()
will indeed delete all session variables stored in the current session, it will not completely remove the session from the storage mechanism. If you want to completely destroy the session, you need to use the function session_destroy()
, which invalidates the current session by completely removing the session from the storage mechanism. Keep in mind that this will not destroy any cookies on the user's browser. Its prototype looks like this:
boolean session_destroy()
If you are not interested in using the cookie beyond the end of the session, just set session.cookie_lifetime
to 0
(its default value) in the php.ini
file.
Remember that the SID ties all session data to a particular user. Although PHP will both create and propagate the SID autonomously, there are times when you may wish to manually set or retrieve it. The function session_id()
is capable of carrying out both tasks. Its prototype looks like this:
string session_id([string sid])
The function session_id() can both set and get the SID. If it is passed no parameter, the function session_id()
returns the current SID. If the optional sid
parameter is included, the current SID will be replaced with that value. An example follows:
<?php
session_start();
echo "Your session identification number is ".session_id();
?>
This results in output similar to the following:
Your session identification number is 967d992a949114ee9832f1c11c
Session variables are used to manage the data intended to travel with the user from one page to the next. These days, however, the preferred method involves simply setting and deleting these variable just like any other, except that you need to refer to it in the context of the $_SESSION
superglobal. For example, suppose you wanted to set a session variable named username
:
<?php
session_start();
$_SESSION['username'] = "jason";
printf("Your username is %s.", $_SESSION['username']);
?>
This returns the following:
Your username is jason.
To delete the variable, you can use the unset()
function:
<?php
session_start();
$_SESSION['username'] = "jason";
printf("Your username is: %s <br />", $_SESSION['username']);
unset($_SESSION['username']);
printf("Username now set to: %s", $_SESSION['username']);
?>
Your username is: jason
Username now set to:
Caution You might encounter older learning resources and newsgroup discussions referring to the functions session_register()
and session_unregister()
, which were once the recommended way to create and destroy session variables, respectively. However, because these functions rely on a configuration directive called register_globals
, which was disabled by default as of PHP 4.2.0, and removed entirely as of PHP 6.0, you should instead use the variable assignment and deletion methods as described in this section.
Regardless of the storage media, PHP stores session data in a standardized format consisting of a single string. For example, the contents of a session consisting of two variables, namely username
and loggedon
, is displayed here:
username|s:5:"jason";loggedon|s:20:"Feb 16 2008 22:32:29";
Each session variable reference is separated by a semicolon and consists of three components: the name, length, and value. The general syntax follows:
name|s:length:"value";
Thankfully, PHP handles the session encoding and decoding autonomously. However, sometimes you might wish to execute these tasks manually. Two functions are available for doing so: session_encode()
and session_decode()
, respectively.
Encoding Session Data
session_encode()
offers a particularly convenient method for manually encoding all session variables into a single string. Its prototype follows:
string session_encode()
You might then insert this string into a database and later retrieve it, decoding it with session_decode()
, for example.
As an example, assume that a cookie containing that user's SID is stored on his computer. When the user requests the page containing the following listing, the user ID is retrieved from the cookie. This value is then assigned to be the SID. Certain session variables are created and assigned values, and then all of this information is encoded using session_encode()
, readying it for insertion into a database.
<?php
// Initiate session and create a few session variables
session_start();
// Set a few session variables.
$_SESSION['username'] = "jason";
$_SESSION['loggedon'] = date("M d Y H:i:s");
// Encode all session data into a single string and return the result
$sessionVars = session_encode();
echo $sessionVars;
?>
This returns:
username|s:5:"jason";loggedon|s:20:"Feb 16 2008 22:32:29";
Keep in mind that session_encode()
will encode all session variables available to that user, not just those that were registered within the particular script in which session_encode()
executes.
Decoding Session Data
Encoded session data can be decoded with session_decode(). Its prototype looks like this:
boolean session_decode(string session_data)
The input parameter session_data
represents the encoded string of session variables. The function will decode the variables, returning them to their original format, and subsequently return TRUE on success and FALSE otherwise. Continuing the previous example, suppose that some session data was encoded and stored in a database, namely the SID and the variables $_SESSION['username']
and $_SESSION['loggedon']
. In the following script, that data is retrieved from the table and decoded:
<?php
session_start();
$sid = session_id();
// Encoded data retrieved from database looks like this:
// $sessionVars = username|s:5:"jason";loggedon|s:20:"Feb 16 2008 22:32:29";
session_decode($sessionVars);
echo "User ".$_SESSION['username']." logged on at ".$_SESSION['loggedon'].".";
?>
This returns:
User jason logged on at Feb 16 2008 22:55:22.
This hypothetical example is intended solely to demonstrate PHP's session encoding and decoding function. If you would like to store session data in a database, there's a much more efficient method that involves defining custom session handlers, and tying those handlers directly into PHP's API. How this is accomplished is demonstrated later in this chapter.
Now that you're familiar with the basic functions that make session handling work, you are ready to consider a few real-world examples. The first example shows you how to create a mechanism that automatically authenticates returning registered site users. The second example demonstrates how session variables can be used to provide the user with an index of recently viewed documents. Both examples are fairly commonplace, which should not come as a surprise given their obvious utility. What may come as a surprise is the ease with which you can create them.
Note If you're unfamiliar with the MySQL database and are confused by the syntax found in the following examples, consider reviewing the material found in Chapter 30.
Once a user has logged in, typically by supplying a username and password combination that uniquely identifies that user, it's often convenient to allow the user to later return to the site without having to repeat the process. You can do this easily using sessions, a few session variables, and a MySQL table. Although there are many ways to implement this feature, checking for an existing session variable (namely $username) is sufficient. If that variable exists, the user can automatically log in to the site. If not, a login form is presented.
Note By default, the session.cookie_lifetime
configuration directive is set to 0
, which means that the cookie will not persist if the browser is restarted. Therefore, you should change this value to an appropriate number of seconds in order to make the session persist over a period of time.
The MySQL table, users
, is presented in Listing 18-1.
Listing 18-1. The users Table
CREATE TABLE users (
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
username VARCHAR(10) NOT NULL,
pswd VARCHAR(10) NOT NULL,
PRIMARY KEY(id)
);
A snippet (login.html
) used to display the login form to the user if a valid session is not found is presented next:
<p>
<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
Username:<br /><input type="text" name="username" size="10" /><br />
Password:<br /><input type="password" name="pswd" SIZE="10" /><br />
<input type="submit" value="Login" />
</form>
</p>
Finally, the logic used to manage the auto-login process follows:
<?php
session_start();
// Has a session been initiated previously?
if (! isset($_SESSION['username'])) {
// If no previous session, has the user submitted the form?
if (isset($_POST['username']))
{
$username = mysqli_real_escape_string($_POST['username']);
$pswd = mysqli_real_escape_string($_POST['pswd']);
// Connect to the MySQL server and select the database
mysql_connect("localhost","webuser","secret");
mysql_select_db("chapter18");
// Look for the user in the users table.
$query = "SELECT username FROM users
WHERE username='$username' AND pswd='$pswd'";
$result = mysql_query($query);
// Has the user been located?
if (mysql_numrows($result) == 1)
{
$_SESSION['username'] = mysql_result($result,0,"username");
echo "You've successfully logged in. ";
}
// If the user has not previously logged in, show the login form
} else {
include "login.html";
}
// The user has returned. Offer a welcoming note.
} else {
printf("Welcome back, %s!", $_SESSION['username']);
}
?>
At a time when users are inundated with the need to remember usernames and passwords for every imaginable type of online service, from checking e-mail to library book renewal to reviewing a bank account, providing an automatic login feature when the circumstances permit will surely be welcomed by your users.
How many times have you returned to a Web site, wondering where exactly to find that great PHP tutorial that you nevertheless forgot to bookmark? Wouldn't it be nice if the Web site were able to remember which articles you read, and present you with a list whenever requested? This example demonstrates such a feature.
The solution is surprisingly easy, yet effective. To remember which documents have been read by a given user, you can require that both the user and each document be identified by a unique identifier. For the user, the SID satisfies this requirement. The documents can be identified really in any way you wish, but this example uses the article's title and URL, and assumes that this information is derived from data stored in a database table named articles
, displayed here:
CREATE TABLE articles (
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
title VARCHAR(50),
content MEDIUMTEXT NOT NULL,
PRIMARY KEY(id)
);
The only required task is to store the article identifiers in session variables, which is implemented next:
<?php
// Start session
session_start();
// Connect to server and select database
mysql_connect("localhost","webuser","secret");
mysql_select_db("chapter18");
// Retrieve requested article id
$articleid = mysqli_real_escape_string($_GET['id']);
// User wants to view an article, retrieve it from database
$query = "SELECT title, content FROM articles WHERE id='$id'";
$result = mysql_query($query);
// Retrieve query results
list($title, $content) = mysql_fetch_row($result);
// Add article title and link to list
$articlelink = "<a href='article.php?id=$id'>$title</a>";
if (! in_array($articlelink, $_SESSION['articles']))
$_SESSION['articles'][] = $articlelink;
// Output list of requested articles
echo "<p>$title</p><p>$content</p>";
echo "<p>Recently Viewed Articles</p>";
echo "<ul>";
foreach($_SESSION['articles'] as $doc) echo "<li>$doc</li>";
echo "</ul>";
?>
The sample output is shown in Figure 18-1.
Figure 18-1. Tracking a user's viewed documents
User-defined session handlers offer the greatest degree of flexibility of the four storage methods. Implementing custom session handlers is surprisingly easy, done by following just a few steps. To begin, you'll need to tailor six tasks (defined below) for use with your custom storage location. Additionally, parameter definitions for each function must be followed, again regardless of whether your particular implementation uses the parameter. This section outlines the purpose and structure of these six functions. In addition, it introduces session_set_save_handler()
, the function used to magically transform PHP's session-handler behavior into that defined by your custom handler functions. Finally, this section concludes with a demonstration of this great feature, offering a MySQL-based implementation. You can immediately incorporate this library into your own applications, using a MySQL table as the primary storage location for your session information.
session_open(
$session_save_path, $session_name):
$session_save_path
and $session_name
refer to the namesake configuration directives found in the php.ini
file. PHP's get_cfg_var()
function is used to retrieve these configuration values in later examples.session_close():
session_open()
. As you can see, there are no input parameters for this function. Keep in mind that this does not destroy the session. That is the job of session_destroy()
, introduced at the end of this list.session_read(
$sessionID):
$sessionID
refers to the SID that will be used to identify the data stored for this particular client.session_write(
$sessionID, $value):
$sessionID
is the variable name, and the input parameter $value
is the session data.session_destroy(
$sessionID):
$sessionID
refers to the SID in the currently open session.session_garbage_collect(
$lifetime):
$lifetime
refers to the session configuration directive session.gc_maxlifetime
, found in the php.ini
file.After you define the six custom handler functions, you must tie them into PHP's session-handling logic. This is accomplished by passing their names into the function session_set_save_handler()
. Keep in mind that these names could be anything you choose, but they must accept the proper number and type of parameters, as specified in the previous section, and must be passed into the session_set_save_ handler()
function in this order: open, close, read, write, destroy, and garbage collect. An example depicting how this function is called follows:
session_set_save_handler("session_open", "session_close", "session_read",
"session_write", "session_destroy",
"session_garbage_collect");
The next section shows you how to create handlers that manage session information within a MySQL database.
You must complete two tasks before you can deploy the MySQL-based handlers:
The following MySQL table, sessioninfo
, will be used to store the session data. For the purposes of this example, assume that this table is found in the database sessions
, although you could place this table where you wish.
CREATE TABLE sessioninfo (
SID CHAR(32) NOT NULL,
expiration INT NOT NULL,
value TEXT NOT NULL,
PRIMARY KEY(SID)
);
Listing 18-2 provides the custom MySQL session functions. Note that it defines each of the requisite handlers, making sure that the appropriate number of parameters is passed into each, regardless of whether those parameters are actually used in the function.
Listing 18-2. The MySQL Session Storage Handler
<?php
/*
* mysql_session_open()
* Opens a persistent server connection and selects the database.
*/
function mysql_session_open($session_path, $session_name) {
mysql_pconnect("localhost", "sessionmanager", "secret")
or die("Can't connect to MySQL server! ");
mysql_select_db("sessions")
or die("Can't select MySQL sessions database");
} // end mysql_session_open()
/*
* mysql_session_close()
* Doesn't actually do anything since the server connection is
* persistent. Keep in mind that although this function
* doesn't do anything in my particular implementation, it
* must nonetheless be defined.
*/
function mysql_session_close() {
return 1;
} // end mysql_session_close()
/*
* mysql_session_select()
* Reads the session data from the database
*/
function mysql_session_select($SID) {
$query = "SELECT value FROM sessioninfo
WHERE SID = '$SID' AND
expiration > ". time();
$result = mysql_query($query);
if (mysql_num_rows($result)) {
$row=mysql_fetch_assoc($result);
$value = $row['value'];
return $value;
} else {
return "";
}
} // end mysql_session_select()
/*
* mysql_session_write()
* This function writes the session data to the database.
* If that SID already exists, then the existing data will be updated.
*/
function mysql_session_write($SID, $value) {
// Retrieve the maximum session lifetime
$lifetime = get_cfg_var("session.gc_maxlifetime");
// Set the session expiration date
$expiration = time() + $lifetime;
// Insert the session data into the database
$query = "INSERT INTO sessioninfo
VALUES('$SID', '$expiration', '$value')";
$result = mysql_query($query);
// If the query fails, the session already exists.
// Therefore, update the session instead.
if (! $result) {
$query = "UPDATE sessioninfo SET
expiration = '$expiration',
value = '$value' WHERE
SID = '$SID' AND expiration >". time();
$result = mysql_query($query);
}
} // end mysql_session_write()
/*
* mysql_session_destroy()
* Deletes all session information having input SID (only one row)
*/
function mysql_session_destroy($SID) {
// Delete all session information having a particular SID
$query = "DELETE FROM sessioninfo
WHERE SID = '$SID'";
$result = mysql_query($query);
} // end mysql_session_destroy()
/*
* mysql_session_garbage_collect()
* Deletes all sessions that have expired.
*/
function mysql_session_garbage_collect($lifetime) {
// Delete all sessions older than a specific age
$query = "DELETE FROM sessioninfo
WHERE sess_expiration < ".time() - $lifetime;
$result = mysql_query($query);
return mysql_affected_rows($result);
} // end mysql_session_garbage_collect()
?>
Once these functions are defined, they can be tied to PHP's handler logic with a call to session_set_save_handler()
. The following should be appended to the end of the library defined in Listing 18-2:
session_set_save_handler("mysql_session_open", "mysql_session_close",
"mysql_session_select",
"mysql_session_write",
"mysql_session_destroy",
"mysql_session_garbage_collect");
To test the custom handler implementation, start a session and register a session variable using the following script:
<?php
INCLUDE "mysqlsessionhandlers.php";
session_start();
$_SESSION['name'] = "Jason";
?>
After executing this script, take a look at the sessioninfo
table's contents using the mysql
client:
mysql> select * from sessioninfo;
+---------------------------------------+-------------------+-------------------
+
| SID | expiration | value |
+---------------------------------------+-------------------+-------------------
+
| f3c57873f2f0654fe7d09e15a0554f08 | 1068488659 | name|s:5:"Jason"; |
+---------------------------------------+-------------------+-------------------
+
1 row in set (0.00 sec)
As expected, a row has been inserted, mapping the SID to the session variable "Jason"
. This information is set to expire 1,440 seconds after it was created; this value is calculated by determining the current number of seconds after the Unix epoch, and adding 1,440 to it. Note that although 1,440 is the default expiration setting as defined in the php.ini
file, you are free to change this value to whatever you deem appropriate.
Note that this is not the only way to implement these procedures as they apply to MySQL. You are free to modify this library as you see fit.
This chapter covered the gamut of PHP's session-handling capabilities. You learned about many of the configuration directives used to define this behavior, in addition to the most commonly used functions that are used to incorporate this functionality into your applications. The chapter concluded with a real-world example of PHP's user-defined session handlers, showing you how to turn a MySQL table into the session-storage media.
The next chapter addresses another advanced but highly useful topic: templating. Separating logic from presentation is a topic of constant discussion, as it should be; intermingling the two practically guarantees you a lifetime of application maintenance anguish. Yet actually achieving such separation seems to be a rare feat when it comes to Web applications. It doesn't have to be this way!
18.118.12.50