Join David Powers for an in-depth discussion in this video Implementing the PHP SessionHandlerInterface, part of Managing PHP Persistent Sessions.
- To store session data in database other than the deprecated version of SQLite you need to define your own session handler. Prior to PHP 5.4 this involved defining at least six custom functions and parsing them as arguments to session_set_save_handler. The functions tell PHP what to do when a session is opened, or closed, how to handle session data when it's read or written, and how to destroy a session or garbage collect. You also could supply a seventh optional argument defining how to create the session id.
Since PHP 5.4 session_set_save_handler also accepts just one or two arguments. They're listed down here. The first argument is required, and it must be a class that implements the SessionHandlerInterface. The second argument is a boolean and it's optional. It specifies whether the session data should be written to the data store on shut down. It defaults to true, which is normally what you want. So, most of the time you need only the first argument. Using a custom class as a single argument to session_set_save_handler is more convienient so that's the approach we'll take.
So, let's take a quick look at SessionHandlerInterface. We get to that by clicking this link here, and then scrolling down. This is a core part of PHP and the interface defines six abstract methods, close, destroy, gc, open, read, and write. They're listed alphabetically here, but they're exactly the same as the six functions required by session_set_save_handler prior to PHP 5.4. So, in effect, the custom class acts as a wrapper that encapsulates all the functionality needed to store session data in a database.
All these methods are called internally by PHP so you don't need to worry about the values that are parsed as arguments to each one. However, you do need to specify the parameters that are shown here when defining the class even when you don't do anything with them inside the method. So, we need to create a custom class that implements SessionHandlerInterface. Let's get to the code. In Chapter 3, 03_01 folder I've created a file called MysqlSessionHandler.php.
This contains the basic structure for a class that implements the SessionHandlerInterface. One of the most common mistakes when storing session data in a database is forgetting to lock records while they're being read or written to. The locking system that we're going to use is based on the approach used by PDOSessionHandler in the Symfony Httpfoundation component. The original Symfony class supports multiple database systems. To make the code easier to understand I've modified it so that it works only with Mysql or MariaDB.
Symfony is distributed under the MIT license which permits modification and redistribution. At the top of the file is this long comment acknowledging that some of the code comes from the Symfony PDOSessionHandler and reproducing the license. This version is covered by the same license so you're free to modify and redistribute it. Right, let's take a look at the code, we'll just collapse this comment and then on line 35 we declare a name space to avoid naming conflicts with other third party code.
The first part of the namespace foundationphp is the name of my own personal domain, foundationphp.com. The class definition itself begins on line 43 and this backslash preceding SessionHandlerInterface indicates that the interface is a core part of PHP. We need that because we're working inside this namespace. The class definition begins by defining several protected properties. They're fully commented so I'll leave you to read the comments yourself.
And, if we scroll down I just want to point out that we've got here table_sess and then col_sid and so on, this is the database table name and the names of the columns. I've declared them as protected properties to make it easy to change the table name and column names in one place if you're using a different set up. And, if we continue scrolling down we find the constructor method that begins on line 103. Let's just expand this pane so we can see the code more clearly.
The constructor method has two parameters, the first one is a PDO database object, and then the second one is useTransactions which is set true. This will determine whether to use transactions in our database. Because, we've got the default value of true this becomes then optional. So, you need to set the second argument only if you don't want to use transactions. Inside the constructor we assign the database object to the db property.
Then the conditional statement on lines 106 to 108 makes sure that the error mode for PDO has been set to exception. I know that we did that in the database connection in the previous chapter, but this is just a fail safe in case you forget in a different project. Then, on line 109 we assign the value of useTransactions to the useTransactions property. Then, on line 110 the expiry property is set to the current time stamp plus the value from session.gc_maxlifetime.
So, the expiry property will be a time stamp by default, for 24 minutes after the session data is either created or updated. The rest of the code defines the signatures for the six required public methods of the SessionHandlerInterface. So, if we scroll down there is open, read, write, close, destroy, and gc for garbage collection. We learnt the code for each method in the rest of the chapter as well as defining some other internal methods.
The convention with namespaced classes is to store them in a directory structure that mirrors the namespace. If you'd like to follow along with me what I suggest you do is, let's just open up here and then in the root of the testing site create a new directory call that Foundationphp. It needs to have a capital F. Then, inside that new directory create another one called Sessions beginning with a capital S.
And then, save MysqlSessionHandler.php from this Chapter Three 03_01 folder into this Sessions folder. So, Save As, and then we're going to go into Foundationphp, Sessions. So, there we are, there's the class definition that I will be working on in the rest of the chapter.
If you just want to read the code there are copies of this file showing the state at the beginning and end of each video in the Exercise files for Chapter Three. So, let's get to work on building the MysqlSessionHandler class.
- Configuring sessions
- Inspecting how session data is stored
- Implementing persistent sessions
- Creating a SQL database to store session data
- Implementing the PHP SessionHandlerInterface
- Writing session data
- Closing and destroying sessions
- Creating an auto-login system with persistent sessions
- Creating persistent logins
- Checking out visitor credentials
- Authenticating users
- Logging out users selectively