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
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
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
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
Choosing Cookies or URL Rewriting
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.
Setting the Session Cookie Lifetime
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
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
Setting Caching Directions
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
If session.cache_limiter is set to nocache, this directive is ignored.
Setting the Session Lifetime
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
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.
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
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
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
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
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
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
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 users Table
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.
Creating Custom Session Handlers
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
Using Custom MySQL-Based Session Handlers
- 1.
Create a database and table that will be used to store the session data.
- 2.
Create the six custom-handler functions.
The MySQL Session Storage Handler
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.