© Frank M. Kromann 2018
Frank M. KromannBeginning PHP and MySQLhttps://doi.org/10.1007/978-1-4302-6044-8_17

17. Session Handlers

Frank M. Kromann1 
(1)
Aliso Viejo, CA, USA
 
Although 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 the following:
  • Why session handling is necessary, and useful

  • How to configure PHP to most effectively use the feature

  • How to create and destroy sessions, and manage session variables

  • Why you might consider managing session data in a database, and how to do it

What Is Session Handling?

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 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, the number of cookies allowed, and various other inconveniences and security problems 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. The session ID is stored as a cookie in the browser and automatically included in every subsequent request to the server. That way the server can keep track of what the visitor is doing at the site. In the basic configuration, the session ID is the index to a file in the file system that holds all the saved information for the user. With the session ID stored in a cookie, it is a requirement that the visitors have the cookie feature enabled in the browser for the site to work. Many countries require the site owners to display a message that informs the visitors that cookies are used even if it’s only used for session tracking.

The Session-Handling Process

In most cases, the developer does not have to do much to start using the session-handling process. With the standard configuration, all you need to do is to call the session_start() function at the beginning of your script before any output is sent to the client. This function will detect if a session cookie is already defined. If it’s not defined, it will add a cookie header to the response. If a cookie is defined, PHP will look for the associated session file and use that to populate the $_SESSION super global. If you look at the session file, you will see a serialized copy of what was in the $_SESSION variable at the previous request from that user.

There are many configuration options when it comes to how PHP uses sessions. In the coming sections, you’ll learn about the configuration directives and functions responsible for carrying out this process.

Configuration Directives

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. Most beginners do not have to change any of the default settings.

Managing the Session Storage Media

The session.save_handler directive determines how the session information will be stored. Its prototype follows:
session.save_handler = files|mm|redis|sqlite|user

Only the files and the user options can be used without installing extra PHP extensions.

Session data can be stored in at least five ways: within flat files (files), within volatile memory (mm), using a Redis server ( https://redis.io ), 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 websites 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. To use this option, you’ll need to download and install the mm library from https://www.ossp.org/pkg/lib/mm/ . Unless you’re well informed of the various issues that could arise from managing sessions in this fashion, I suggest choosing another option.

The Redis option works like an in-memory solution, but the Redis server supports persistence to disk, and it can be installed on a different server allowing the session data to be shared between multiple web servers in a load balanced environment. The Redis server can be downloaded from http://redis.io . It also requires the Redis extension that can be downloaded from https://github.com/nicolasff/phpredis . Some Linux distributions allow you to install these elements with the package manager.

The sqlite option takes advantage of the SQLite extension to manage session information transparently using this lightweight database. The fifth option, user, 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.

Setting the Session Files Path

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, this directive is not defined, and unless a value is provided, the system will use /tmp as the location for session files. If you’re using the files option, then you’ll need to both enable it within the php.ini file and choose a suitable storage directory. 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.

Automatically Enabling Sessions

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 if you’d like to store objects within a session variable, you’ll need to load their class definitions using the auto_prepend_file directive . Doing so will, of course, cause additional overhead because these classes will load even in instances where they are not used within the application.

Setting the Session Name

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

Choosing Cookies or URL Rewriting

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. You can choose this 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. Using URL rewriting makes it possible to view the session ID as part of the URL. This is a potential security risk that allows a different user with access to the URL to access the site using the same session ID. There are two possible values for the session.ude_cookies directive:
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, there are several other directives that you must consider, and they are introduced next.

For security reasons, it is recommended that you configure a few extra options for cookie handling. This will help prevent cookie hijacking.
session.use_only_cookies = 0 | 1
Setting session.use_only_cookies = 1 will prevent users from passing in the cookie as a parameter in the querystring. The server will only accept the session id when it is passed from the browser as a cookie. In addition, most modern browsers allow defining cookies as “http only.” Doing so will prevent the cookie from being access from JavaScript. It is controlled via the directive session.cookie_httponly:
session.cookie_httponly = 0 | 1
Finally, it’s possible to prevent the cookie from being set on a non-secure connection. Setting session.cookie_secure = 1 will only send the cookie to the browser if a secure SSL connection is used.
session.cookie_secure = 0 | 1

Setting the Session Cookie Lifetime

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, this directive should be set to 3600. If this directive is set to 0 (the default), the cookie will live until the browser is restarted. The cookie lifetime indicates the lifetime of the cookie. Every time a user sends a request, PHP will issue an updated cookie with the same lifetime. If the user waits longer that the lifetime between requests, the browser will no longer include the cookie in the request, and it will look like a new visitor to the site.

Setting the Session Cookie’s Valid URL Path

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 / (the default), then the cookie will be valid for the entire website. Setting it to /books means that the cookie is 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. Neglecting to set this cookie will result in the cookie’s domain being set to the host name of the server that generated it. 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 www.example.com , set this directive like this:
session.cookie_domain = .example.com

Setting Caching Directions

It is common practice to use caching to speed up loading of web pages. Caching can be done by the browser, by a proxy server, or by the web server. If you are serving pages that have user-specific content, you don’t want that to be cached in a proxy server and picked up by a different user that’s requesting the same page. 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: This setting disables the transmission of any cache control headers along with the session-enabled pages.

  • nocache: This is the default setting. This setting ensures that every request is first sent to the originating server for confirmation that the page has not changed before a potentially cached version is offered.

  • private: Designating a cached document as private means that the document will be made available only to the originating user, instructing proxies to not cache the page and therefore not share it with other users.

  • private_no_expire: This variation of the private designation results in no document expiration date being sent to the browser. Otherwise identical to the private setting, this was added as a workaround for various browsers that became confused by the Expire header sent along when caching is set to private.

  • public: This setting deems all documents as cacheable, making it a useful choice for non-sensitive areas of your site, thanks to the improvement in performance.

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 session data is considered valid. When session data is older than the specified lifetime, it will no longer be read into the $_SESSION variable and the content will be “garbage collected” or removed from the system. 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. Also check out the session.gc_divisor and session.gc_probability directives for more information about tweaking the session garbage collection feature.

Working with Sessions

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.

Starting a Session

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 by calling it like this:
session_start([ array $options = array() ]);

One important issue that confounds many newcomers to the session_start() function involves exactly where this function can be called. Neglecting to execute it before any other output has been sent to the browser will result in the generation of an error message (headers already sent).

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, plus it will introduce other side effects such as requiring the loading of class definitions should you wish to store object information within a session variable.

The optional parameter $options was introduced in PHP 7.0 as a way to allow the developer to overwrite any of the directives configured in php.ini by passing an associative array of options. In addition to the standard parameters, it’s also possible to specify a read_and_close option. When that is set to TRUE, the function will read the content of the session file and close it right away, preventing updates to the file. This can be used on high-traffic sites where the session is read by many pages but only updated by a few.

Destroying a Session

Although you can configure PHP’s session-handling directives to automatically destroy a session based on an expiration time or garbage collection 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 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.

Setting and Retrieving the Session ID

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

If you’d like to create a custom session handler, supported characters are limited to alphanumeric characters, the comma, and the minus sign.

Creating and Deleting Session Variables

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 variables 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']);
?>
This returns:
Your username is: Jason
Username now set to:

Caution

You might encounter older learning resources and newsgroup discussions referring to the function’s 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 was removed completely in PHP 5.4.0, you should instead use the variable assignment and deletion methods as described in this section.

Encoding and Decoding Session Data

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 (username and loggedon) are displayed here:
username|s:5:"jason";loggedon|s:20:"Feb 16 2011 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 perform these tasks manually. Two functions are available for doing so: session_encode() and session_decode() .

Encoding Session Data

session_encode() offers a convenient method for manually encoding all session variables into a single string. Its prototype follows:
string session_encode()
This function is particularly useful when you’d like to easily store a user’s session information within a database, as well as for debugging, giving you an easy way to review a session’s contents. 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, like so:
<?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 2011 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.

You can also use the seraialize() function to obtain a similar result, but by default the session_encode() function will use an internal serialization format that is different from that of the serialize() function.

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 2011 22:32:29";
    session_decode($sessionVars);
    echo "User ".$_SESSION['username']." logged on at ".$_SESSION['loggedon'].".";
?>
This returns:
User jason logged on at Feb 16 2011 22:55:22.

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. A demonstration of this appears later in this chapter.

Regenerating Session IDs

An attack known as session-fixation involves an attacker somehow obtaining an unsuspecting user’s SID and then using it to impersonate the user in order to gain access to potentially sensitive information. You can minimize this risk by regenerating the session ID on each request while maintaining the session-specific data. PHP offers a convenient function named session_regenerate_id() that will replace the existing ID with a new one. Its prototype follows:
Boolean session_regenerate_id([boolean delete_old_session])

The optional delete_old_session parameter determines whether the old session file will also be deleted when the session ID is regenerated. If this is set to false or not passed, the old session file will be left on the system and an attacker would still be able to use the data. The best option is to always pass true to make sure the old data is deleted after a new session id is created.

There is some overhead to using this function as a new session file has to be generated and the session cookie updated.

Practical Session-Handling Examples

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 how to create a mechanism that automatically authenticates returning registered 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 from Chapter 22.

Automatically Logging In Returning Users

Once a user has logged in, typically by supplying a unique username and password combination, 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 17-1.
CREATE TABLE users (
   id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
   first_name VARCHAR(255) NOT NULL,
   username VARCHAR(255) NOT NULL,
   password VARCHAR(32) NOT NULL,
   PRIMARY KEY(id)
);
Listing 17-1

The users Table

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']))
      {
        $db = new mysqli("localhost", "webuser", "secret", "corporate");
        $stmt = $db->prepare("SELECT first_name FROM users WHERE username = ? and password = ?");
        $stmt->bind_param('ss', $_POST['username'], $_POST['password]);
        $stmt->execute();
        $stmt->store_result();
        if ($stmt->num_rows == 1)
        {
          $stmt->bind_result($firstName);
          $stmt->fetch();
          $_SESSION['first_name'] = $firstName;
          header("Location: http://www.example.com/");
        }
      } else {
        require_once('login.html');
      }
  } else {
    echo "You are already logged into the site.";
  }
?>

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.

The example above requires a table called users with the column’s username and password. As discussed in Chapter 14, you should not store passwords in clear text. Instead you should use a hash as that will not make the actual password available to attackers should they gain access to the database.

Generating a Recently Viewed Document Index

How many times have you returned to a website, wondering where exactly to find that great PHP tutorial that you forgot to bookmark? Wouldn’t it be nice if the website was 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 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 INTEGER 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
    $db = new mysqli("localhost", "webuser", "secret", "corporate");
    // User wants to view an article, retrieve it from database
    $stmt = $db->prepare("SELECT id, title, content FROM articles WHERE id = ?");
    $stmt->bind_param('i', $_GET['id']);
    $stmt->execute();
    $stmt->store_result();
    if ($stmt->num_rows == 1)
    {
      $stmt->bind_result($id, $title, $content);
      #stmt->fetch();
    }
    // 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;
    // Display the article
    echo "<p>$title</p><p>$content</p>";
    // Output list of requested articles
    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 17-1.
../images/314623_5_En_17_Chapter/314623_5_En_17_Fig1_HTML.jpg
Figure 17-1

Tracking a user’s viewed documents

Creating Custom Session Handlers

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) : This function initializes any elements that may be used throughout the session process. The two input parameters $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() : This function operates much like a typical handler function does, closing any open resources initialized by 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) : This function reads the session data from the storage media. The input parameter $sessionID refers to the SID that will be used to identify the data stored for this particular client.

  • session_write($sessionID, $value) : This function writes the session data to the storage media. The input parameter $sessionID is the variable name, and the input parameter $value is the session data.

  • session_destroy($sessionID) : This function is likely the last function you’ll call in your script. It destroys the session and all relevant session variables. The input parameter $sessionID refers to the SID in the currently open session.

  • session_garbage_collect($lifetime) : This function effectively deletes all sessions that have expired. The input parameter $lifetime refers to the session configuration directive session.gc_maxlifetime , found in the php.ini file .

Tying Custom Session Functions into PHP’s Logic

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");

Using Custom MySQL-Based Session Handlers

You must complete two tasks before you can deploy the MySQL-based handlers:
  1. 1.

    Create a database and table that will be used to store the session data.

     
  2. 2.

    Create the six custom-handler functions.

     
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 VARCHAR(255) NOT NULL,
   value TEXT NOT NULL,
   expiration TIMESTAMP NOT NULL,
  PRIMARY KEY(sid)
);
Listing 17-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. The example uses the function session_set_save_handler() to define the six callback functions needed to implement all the functions. Each of the functions can be identified with a function name as a string or with an array that takes two parameters. The first is a reference to the object, and the second is the name of the method to call for the given action. Because the session handler in this example is defined with a class, each function name is specified with an array.
<?php
class MySQLiSessionHandler {
  private $_dbLink;
  private $_sessionName;
  private $_sessionTable;
  CONST SESS_EXPIRE = 3600;
  public function __construct($host, $user, $pswd, $db, $sessionName, $sessionTable)
  {
    // Create a connection to the database
    $this->_dbLink = new mysqli($host, $user, $pswd, $db);
    $this->_sessionName = $sessionName;
    $this->_sessionTable = $sessionTable;
    // Set the handlers for open, close, read, write, destroy and garbage collection .
    session_set_save_handler(
      array($this, "session_open"),
      array($this, "session_close"),
      array($this, "session_read"),
      array($this, "session_write"),
      array($this, "session_destroy"),
      array($this, "session_gc")
    );
    session_start();
  }
  function session_open($session_path, $session_name) {
    $this->_sessionName = $session_name;
    return true;
  }
  function session_close() {
      return 1;
  }
  function session_write($SID, $value) {
    $stmt = $this->_dbLink->prepare("
      INSERT INTO {$this->_sessionTable}
        (sid, value) VALUES (?, ?) ON DUPLICATE KEY
        UPDATE value = ?, expiration = NULL");
    $stmt->bind_param('sss', $SID, $value, $value);
    $stmt->execute();
    session_write_close();
  }
  function session_read($SID) {
      // create a SQL statement that selects the value for the cussent session ID and validates that it is not expired .
      $stmt = $this->_dbLink->prepare(
        "SELECT value FROM {$this->_sessionTable}
         WHERE sid = ? AND
         UNIX_TIMESTAMP(expiration) + " .
         self::SESS_EXPIRE . " > UNIX_TIMESTAMP(NOW())"
      );
      $stmt->bind_param('s', $SID);
      if ($stmt->execute())
      {
      $stmt->bind_result($value);
        $stmt->fetch();
        if (! empty($value))
        {
          return $value;
        }
      }
  }
  public function session_destroy($SID) {
    // Delete the record for the session id provided
    $stmt = $this->_dbLink->prepare("DELETE FROM {$this->_sessionTable} WHERE SID = ?");
    $stmt->bind_param('s', $SID);
    $stmt->execute();
  }
    public function session_gc($lifetime) {
      // Delete records that are expired.
      $stmt = $this->_dbLink->prepare("DELETE FROM {$this->_sessionTable}
          WHERE UNIX_TIMESTAMP(expiration) < " . UNIX_TIMESTAMP(NOW()) - self::SESS_EXPIRE);
      $stmt->execute();
   }
}
Listing 17-2

The MySQL Session Storage Handler

To use the class, just include it within your scripts, instantiate the object, and assign your session variables :
require "mysqlisession.php";
$sess = new MySQLiSessionHandler("localhost", "root", "jason",
                                                            "chapter17", "default", "sessioninfo");
$_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 can 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.

Summary

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 for incorporating 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: web services. It will also address how to interact with services and APIs using standard web technologies.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.140.186.201