Stefan Gabos web developer extraordinaire
Zebra_Session, a wrapper for PHP’s default session handling functions, using MySQL for storage
-
Latest version2.0.3released onJuly 13, 2012
- 1. Overview
- 2. Features
- 3. Requirements
- 4. Installation
- 5. How to use
- 6. Download
- 7. Documentation
- 8. Changelog
- 9. Comments
Session support in PHP consists of a way to preserve information (variables) on subsequent accesses to a website’s pages. Unlike cookies, variables are not stored on the user’s computer. Instead, only a session identifier is stored in a cookie on the visitor’s computer, which is matched up with the actual session data kept on the server, and made available to us through the $_SESSION super-global. Session data is retrieved as soon as we open a session, usually at the beginning of each page.
By default, session data is stored on the server in flat files, separate for each session. The problem with this scenario is that performance degrades proportionally with the number of session files existing in the session directory (depending on the server’s operating system’s ability to handle directories with numerous files). Another issue is that session files are usually stored in a location that is world readable posing a security concern on shared hosting.
This is where Zebra_Session comes in handy – a PHP library that acts as a drop-in replacement for PHP’s default session handler, but instead of storing session data in flat files it stores them in a MySQL database, providing better security and better performance.
The Zebra_Session is also a solution for applications that are scaled across multiple web servers (using a load balancer or a round-robin DNS) where the user’s session data needs to be available. Storing sessions in a database makes them available to all of the servers!
This class is was inspired by John Herren’s code from the Trick out your session handler article and Chris Shiflett’s code from his book Essential PHP Security, chapter 8, Shared Hosting, Pg. 78-80.
Zebra_Session‘s code is heavily commented and generates no warnings/errors/notices when PHP’s error reporting level is set to E_ALL.
Starting with version 2.0, Zebra_Session implements row locks, ensuring that data is correctly handled in a scenario with multiple concurrent AJAX requests.
Citing from Race Conditions with Ajax and PHP Sessions, a great article by Andy Bakun:
When locking is not used, multiple requests (represented in these diagrams as processes P1, P2 and P3) access the session data without any consideration for the other processes and the state of the session data. The running time of the requests are indicated by the height of each process’s colored area (the actual run times are unimportant, only the relative start times and durations).

In the example above, no matter how P2 and P3 change the session data, the only changes that will be reflected in the session are those that P1 made because they were written last. When locking is used, the process can start up, request a lock on the session data before it reads it, and then get a consistent read of the session once it acquires exclusive access to it. In the following diagram, all reads occur after writes:

The process execution is interleaved, but access to the session data is serialized. The process is waiting for the lock to be released during the period between when the process requests the session lock and when the session is read. This means that your session data will remain consistent, but it also means that while processes P2 and P3 are waiting for their turn to acquire the lock, nothing is happening. This may not be that important if all of the requests change or write to the session data, but if P2 just needs to read the session data (perhaps to get a login identifier), it is being held up for no reason.
So, in the end, this is not the best solution but still is better than nothing. The best solution is probably a per-variable locking. You can read a very detailed article about all this in Andy Bakun‘s article Race Conditions with Ajax and PHP Sessions.
Thanks to Michael Kliewe who brought this to my attention!
Features review
- acts as a wrapper for PHP’s default session handling functions, but instead of storing session data in flat files it stores them in a MySQL database, providing better security and better performance
- it is a drop-in and seemingless replacement for PHP’s default session handler: PHP sessions will be used in the same way as prior to using the library; you don’t need to change any existing code!
- implements row locks, ensuring that data is correctly handled in scenarios with multiple concurrent AJAX requests
- because session data is stored in a database, the library represents a solution for applications that are scaled across multiple web servers (using a load balancer or a round-robin DNS)
- has comprehensive documentation
- the code is heavily commented and generates no warnings/errors/notices when PHP’s error reporting level is set to E_ALL
Requirements
PHP 4.4.9+, MySQL 4.1.22+
Installation
Download the latest version, unpack it, and put it in a place accessible to your scripts. After unpacking, you will notice a directory called “install” containing a file named “session_data.sql”. This file contains the SQL code that will create a table that is used by the class to store session data. Import or execute the SQL code using your preferred MySQL manager (like phpMyAdmin or the fantastic Adminer) into a database of your choice.
How to use
Note that this class assumes that there is an active connection to a MySQL database and it does not attempt to create one! If you really need the class to make a database connection, put the code in the “open” method of the class.
<?php
// first, connect to a database containing the sessions table
// include the Zebra_Session class
include 'path/to/Zebra_Session.php';
// instantiate the class
// this also calls session_start()
$session = new Zebra_Session;
// from now on, use sessions as you would normally
// this is why it is called a "drop-in replacement"
$_SESSION['foo'] = 'bar';
// data is in the database!
?>
Download
Zebra_Session is distributed under the LGPL.
In plain English, this means that you have the right to view and to modify the source code of this software, but if you modify and distribute it, you are required to license your copy under a LGPL-compatible license, and to make the entire source code of your derivation available to anybody you distribute the software to.
You also have the right to use this software together with software thas has different licensing terms (including, but not limited to, commercial and closed-source software), and distribute the combined software, as long as state that your software contains portions licensed under the LGPL license, and provide information about where the LGPL licensed software can be downloaded.
If you distribute copies of this software you may not change the copyright or license of this software.
You may also like:
- Zebra_Database, a MySQL database wrapper written in PHP
- Zebra_Form, a jQuery augmented PHP library for creating and validating forms
- Zebra_Image, a lightweight image manipulation library written in PHP
- Zebra_Mptt, a PHP implementation of the modified preorder tree traversal algorithm
- Zebra_Pagination, a generic pagination class written in PHP
- Zebra_Session, a wrapper for PHP's default session handling functions, using MySQL for storage
Documentation
|
Become a ninja. Read the comprehensive documentation. |
Changelog
Click on a version to expand/collapse information.
- version 2.0.3 (July 13, 2012)
-
- fixed a bug where sessions’ life time was twice longer than expected; thanks to Andrei Bodeanschi;
- details on how to preserve session data accross subdomains was added to the documentation;
- the messages related database connection errors are now more meaningful;
- version 2.0.2 (October 24, 2011)
-
- fixed a bug with the get_active_sessions() method which was not working at all;
- fixed a bug where the script was not using the provided MySQL link identifier (if available);
- version 2.0.1 (July 03, 2011)
-
- the constructor method now accepts an optional link argument which must be a MySQL link identifier. By default, the library made use of the last link opened by mysql_connect(). On some environments (particularly on a shared hosting) the “last link opened by mysql_connect” was not available at the time of the instantiation of the Zebra_Session library. For these cases, supplying the MySQL link identifier to the constructor method will fix things. Thanks to Mark for reporting.
- some documentation refinements
- version 2.0 (April 18, 2011)
-
- the class now implements session locking; session locking is a way to ensure that data is correctly handled in a scenario with multiple concurrent AJAX requests; thanks to Michael Kliewe for suggesting this and to Andy Bakun for this excellent article on the subject Race Conditions with Ajax and PHP Sessions.
- version 1.0.8 (December 27, 2010)
-
- fixed a small bug in the destroy method; thanks to Tagir Valeev for reporting;
- the script would trigger a PHP notice if the HTTP_USER_AGENT value was not available in the $_SERVER super-global;
- added a new method “get_settings” that returns the default session-related settings for the environment where the class is used
- version 1.0.7 (October 29, 2008)
-
- the class will now trigger a fatal error if a database connection is not available;
- the class will now report if MySQL table is not available;
- version 1.0.6 (October 01, 2007)
-
- the constructor of the class now accepts a new argument: tableName – with this, the MySQL table used by the class can be changed;
- version 1.0.5 (September 15, 2007)
-
- ‘LIMIT 1′ added to the read method improving the performance of the script; thanks to A. Leeming for suggesting this;
- version 1.0.4 (August 23, 2007)
-
- rewritten the write method which previously had to run two queries each time; it now only runs a single one, using ON DUPLICATE KEY UPDATE; thanks to Inchul Koo for providing this information;
- the type of the http_user_agent column in the MySQL table has been changed from TEXT to VARCHAR(32) as now it is an MD5 hash; this should increase the performance of the script; thanks to Inchul Koo for suggesting this;
- the constructor of the class now accepts a new argument: securityCode, in order to try to prevent HTTP_USER_AGENT spoofing; read the documentation for more information; thanks to Inchul Koo for suggesting this;
- version 1.0.3 (December 13, 2006)
-
- the get_users_online method is now more accurate as it now runs the garbage collector before getting the number of online users; thanks to Gilles for the tip;
- the structure of the MySQL table used by the class was tweaked in so that the http_user_agent column has been changed from VARCHAR(255) to TEXT and the session_data column has been changed from TEXT to BLOB; thanks to Gilles for the tip
- version 1.0.2 (November 22, 2006)
-
- the class was trying to store the session data without mysql_real_escape_string-ing it and therefore, whenever the data to be saved contained quotes, nothing was saved; thanks to Ed Kelly for reporting this;
- version 1.0.1 (September 11, 2006)
-
- the structure of the MySQL table used by the class was tweaked and now the session_id column is now a primary key and its type has changed from VARCHAR(255) to VARCHAR(32) as it now is an MD5 hash; previously a whole table scan was done every time a session was loaded; thanks to Harry for suggesting this;
- added a new stop method which deletes a session along with the stored variables from the database; this was introduced because many people were using the private destroy method which is only for internal purposes;
- the default settings for session.gc_maxlifetime, session.gc_probability and session.gc_divisor can now be overridden through the constructor;
- on popular request, an example file was added;
- version 1.0 (August 01, 2006)
-
- initial release




I am a 32 year old web developer working from Bucharest, Romania. I am coding since I was 14 and I am extremely passionate about it. For the server side of things I use PHP/MySQL while on the front-end I write valid HTML 5, nice CSS and lots of JavaScript code using jQuery.
Am I right in believing that when using Zebra_Session, none of my scripts require session_start(); anymore?
Specific example …
ReplyPHP code starts by including config.php which initiates the Zebra_Session
Previously (and currently I still do), prior to this include I have session_start();
you are right – you don’t have to call session_start when using this library. still, if you call it, you must call it after initializing the library.
if you’d have the error reporting turned on (error_reporting(E_ALL)) you’d see a notice from PHP because, as the manual states, “As of PHP 4.3.3, calling session_start() after the session was previously started will result in an error of level E_NOTICE. Also, the second session start will simply be ignored”
this library works with a pdo connection?
ReplyHello, I really like your Session Handler, but I noticed something weird (for me)
ReplyI was testing it and I just logged in the same account using 2 different browser, the account was “locked” both browsers was unable to loggin into it (until session expire)
There are some way to let “Multi Loggin” or something similar?
It’s weird to get kicked from account and wait 20 minutes to loggin again
you should call
whenever you authenticate an user
Hi Again,
I’ve been using this session handler for a little while now and have a question.
What is the best way to test for an active session?
I’ve experienced some issues with sessions idle sessions that should exceed the lifetime, but act a little quirky… I can provide more detail if necessary..
Thanks again!
Replyplease provide me with some more details about how they “act quirky”. either here or to my email. thanks!
Hi Stefan,
I’m going to do some more testing and try to confirm the bug, it may very well be my logic that is at fault. In that case, I don’t want to leave a negative impression of your awesome class. At this point I’ll presume all is working well, and I have a bug elsewhere. If not, I’ll email you.
Thanks,
there’s no problem in finding bugs – although, I’m hoping you won’t find one
the contribution of lots of people like you made these classes/plugins what they are!
Hi,
ReplyMy question is about write function,when I use $_SESSION superglobal cannot update session_data field.But change session_data field types for text, it is ok。i used mysql 5.5.17
Sory I know it,Blob in the navcate client can’t display~ XD And thanks~
Hi there Stefan,
Thank you for sharing an awesome product. It works like a charm with mysql. However, when i converted to mysqli everything Zebra_Session broke down. The error i get is “NO MySQL connection” (…) Zebra_Session.php on line 218.
I tried to do a replace of mysql to mysqli, as i did in all the other php code.
Any idea on what more i need to do with Zebra_Session to get it to work with mysqli?
Replyit’s not that easy as simply replaceing mysql_* calls to mysqlli_* calls.
but you can use this without any problems even if your whole ecosystem runs on mysqlli…
Hello,
I am liking what I see but am having some trouble running it. I built the database/table. run your example script, and see the results in the database. The problem I see is if I hit refresh on the browser it goes blank. If I place echo statements in the exaple code as follows.
echo("allan1");
$session = new Zebra_Session();
echo("allan2");
I do not see the allan2 output. It seems as if the session will only run thru 1 time. What am I doing wrong?
Thank you,
ReplyAllan
Looking deeper into this, I think the problem is because of the mysql_ping is failing and the Zebra_Session code is being skipped. I have compiled php to use mysqli as well as and mysql (but I prefer the mysqli). Not sure, but I am thinking I have to rewrite to mysqli. Is that something you are planning on? Any suggestions requested. Here is my connection code.
// change the values to match the setting of your MySQL database
$host = ‘xxx’;
$username = ‘xxx’;
$password = ‘xxx’;
// this is the name of the database where you created the table used by this class
$database = ‘sessions’;
// try to connect to the MySQL server
$link = mysql_connect($host, $username, $password) or die(‘Could not connect to database!’);
// select the required database
$db = mysql_select_db($database, $link) or die (‘Could not select database!’);
// include the Zebra_Session class
include(‘zebra_session/Zebra_Session.php’);
// instantiate the class
// note that you don’t need to call the session_start() function
// as it is called automatically when the object is instantiated
$session = new Zebra_Session();
Thanks, Allan
Allan, I am currently not planing on porting this to mysqli…
Hi, thanks a lot for this awesome piece of code, but i just want to know why you keep the deprecated mysql() and not mysqli or pdo. The performance are better or you don’t want to rewrite part of the code ? I want to add your code to my project but i am little afraid with this point (everybody keep telling me not to use mysql anymore)
ReplySorry for my bad english btw, this is not my native language !
i currently do not have the time to rewrite this for mysqli. yes, you should use mysqli or pdo in general, but for this particular class, you are safe to use it as i’ve been using it in production for 6 years now and I can assure you it is safe
Hi,
This class is good idea for session hijacking AND fixation prevention?
Can I use for that?
tnx
Replyactually it has nothing to do with session hijacking. you do that by protecting yourself from XSS and CSRF attacks, and maybe transmitting your data over HTTPS – but none of those are this library’s job.
Hi, I’m trying to use Zebra Sessions (actually a vast majority of your excellent libraries and Jquery’s) – I’ve included the command lines to start the coding but I keep getting the error: Zebra_Session: No database selected I am using using Meekro’s DB Wrapper and wondering if that has anything to do with it as I’m opening the MySQL connection by loading the site settings. Help me please?
Replymake sure you are connecting to the database *before* instantiating Zebra_Session
Hello, thanks for this good class. I have a problem when try to use it with zebra database class you provided it gives error
ReplyFatal error:
No MySQL connection!
Error in E:\xampplite\htdocs
this is the code i use
require_once('config.php');
require_once('inc/Zebra_Database.php');
require_once('inc/Zebra_Session.php');
//Classları başlat
$db = new Zebra_Database();
$db->connect($dbhost, $dbuser, $dbsifre, $dbadi);
$session = new Zebra_Session;
$db->debug = true;
i am connected to mysql
solved it with
$session = new Zebra_Session($db->_connected());
I think may be contain the database connect in class will better
Reply