ChipmunkNinja
Ninjas are deadly. Chipmunk Ninjas are just weird.
About this blog
Marc Travels
Marc on Twitter
JustLooking on Twitter

Marc Wandschneider is a professional software developer with well over fifteen years of industry experience (yes, he really is that old). He travels the globe working on interesting projects and gives talks at conferences and trade shows whenever possible.

My Publications:

My book, "Core Web Application Programming with PHP and MySQL" is now available everywhere, including Amazon.com

My "PHP and MySQL LiveLessons" DVD Series has just been published by Prentice-Hall, and can be purchased on Amazon, through Informit, or Safari


ABCHKMPRaRoSTVW
xxxxx-xxxxxxxxx
Feb 04, 2006 | 10:59:23
PHP5 and Database Sessions: Busted
By marcwan

One of my favourite things about PHP 5 is how nifty the object-oriented features are. I have been able to put together surprisingly robust web applications using simple class hierarchies and abstract classes, features that only took off in PHP with the version 5.0 release. One of the other things I have loved is using the the various built-in object-oriented classes provided by the runtime, most notably the mysqli and related functionality.

One extremely common task I complete is to use database storage for session data. When you are running multiple web servers and individual HTTP requests might go to different machines, trying to come up with a scheme to synchronise session data files between the individual servers becomes prohibitive. Far better a solution is to simply put these data in the database server along with everything else (see Figure 1) – your application servers hold only the code needed to generate the pages from the database.

In the past, I have written code as follows to store the session data after the script has finished executing:



$s_conn = NULL;     // this is set to be a mysqli object in the session_open function.

function session_open($save_path, $session_name)
{
    global $s_conn;
    $s_conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DB);
    return TRUE;
}

// there are a bunch of other read, close, clean up functions etc.

function session_write_data($id, $session_data)
{
    global $s_conn;

    $x = $s_conn->real_escape_string($id);
    $d = $s_conn->real_escape_string($session_data);

    $s_conn->query('SET AUTOCOMMIT=0');

    $q = "DELETE FROM SessionData WHERE session_id='$x'";
    $s_conn->query($q);

    $q = "INSERT INTO SessionData VALUES('$x', NOW(), '$d')";

    $s_conn->query($q);
    $s_conn->commit();

    return TRUE;
}

Unfortunately, the combination of all of these nifty features has taken a turn for the worse in PHP 5.0.5 and greater (including PHP 5.1). When you execute the above code in these versions of PHP, you will now get the rather odd error:


Error:  couldn't fetch mysqli.

What happened? Where did mysqli go, seeing as it was working earlier in the script, and in all previous versions of PHP 5?

The short answer is that the PHP team changed how objects are cleaned up and destroyed when PHP shuts down. All objects are now cleaned up before the session is closed on exit. Thus, if you use any objects in your session shutdown code, you are in trouble.

Are you simply out of luck then? Can you absolutely not use mysql in session_write_data as shown above? Fortunately, the situation is not so dire. There is a rather unpleasant hack that you can add to your code to make things continue to work. In our session handling code, we create a subclass of the mysqli class that, when instructed to destroy itself, insures that the session is shut down early and the data are written to the database.

We then instantiate this subclass of mysqli instead of using the regular old class.


class php505bugMysqli extends mysqli
{
    public function __destruct(){
        @session_write_close();
    }
}

function session_open($save_path, $session_name)
{
    global $s_conn;
    $s_conn = new php505bugMysqli(DB_HOST, DB_USER, DB_PASS, DB_DB);
    return TRUE;
}

If you are looking at this code and thinking “yeeeech”, you should be. It is hacky and unpleasant. It is, unfortunately, also the only way to make this work in current versions of PHP 5. Much noise has been appearing in various PHP bug reports on bugs.php.net, but the Zend folks have, thus far, been resolutely insisting this is not a serious breakage and arguing it is a documentation bug.

Here’s to hoping that they come to their senses sometime soon, or at least come up with a less awful solution to this problem. It flies directly in the face of all the advances PHP has made in the last year.

Got any other solutions or workarounds for this problem? Add a comment.

What I'm more upset about
Posted By: marcwan May 30, 2006 06:23:53
While I will grant that you can make a perfect argument for either side of this design problem, I am a little disturbed that the change was just made in a minor point release, and no communication was made to this effect.

We were working on a major web application, and suddently, after upgrading to a new version of PHP, everything went to hell.

Changing APIs or functionality is inevitable and probably a good thing. Doing so without informing poeple is, however, bad practice in my book.
Not Really an Error in the Book ....
Posted By: marcwan Aug 24, 2006 02:17:01

Hey Justin!

This isn't really an error in the book, but you're correct - it would be worth mentioning to readers of the book, as it IS quite annoying. I will create an updated errata article for the book and put it on this blog site.

Thanks.
Zend Custom Session Handling in PHP5
Posted By: Igor Berger Oct 19, 2007 09:17:42
Marc, I read your suggestion but I am confussed how to implement it for
Custom Session Handling in PHP5 script and my hosting people will be migrating to php5 from php4 very soon.

Can you please give me a hand in implementing it in the
Zend Custom Session Handling script thatt I am using now?

http://www.zend.com/zend/spotlight/code-gallery-wade8.php?article=code-gallery-wade8&kind=sl&id=4791&open=1&anc=0&view=1

I am not sure what needs to be added where and what needs to be changed!

Thank you
Add a Comment

Title:

Name:

URL:

Comment:

Copyright © 2005-2008 Marc Wandschneider All Rights Reserved.