session_set_save_handlerin order to consolidate all web state in the site's mysql database.
One of the first things I do in nearly any software development project is to set up a convenient debug logging facility. PHP has
error_log, but a) it seems like it's full of magic behaviour, b) it needs a string, so you have to flatten any structured data yourself, first, and c) I didn't know about it when I wrote
debug(). What better thing to log than one's ad-hoc session handlers?
It's a good habit to check Apache's error log once in a while. That's where
debug()originally wrote to, but because I don't necessarily have access to Apache's logs, I taught
debug()to log to a file nearby the
DocumentRoot. But today I checked Apache's error log, and lo and behold, it was full of errors:
[Fri Nov 04 22:45:47 2011] [error] [client ::1] PHP Warning: fopen(../logs/mph.log): failed to open stream: No such file or directory in /home/berndj/public_html/mph-adhoc/lib/debug.php on line 7, referer: http://localhost/~berndj/mph-adhoc/web/index.php
After much head-scratching and source-diving, and poring over
strace's log of what Apache does when I hit the page, I figured it out: PHP resets the working directory back to where it was before it executes a script, and only then runs destructors and other shutdown functions - one of which I assume to call
session_write_close.That left some of my session handlers running in a directory where I didn't expect them to. (The root directory, to be precise.) And that was why the attempts to
fopena relative path were failing - there is no "
.." in the root directory, let alone a
I guess I have to choose a place to call
session_write_close- somewhere that guarantees it always gets called, yet before PHP starts cleaning up (is this possible?). Perhaps my compromise will be to add the call to my boilerplate file - the one I paste into every new file when I start writing it. There's an extra benefit to doing this, because it allows me to get rid of one
# XXX Don't call mysql_close() as session handling depends on having a DB connection.
 To confirm my understanding of what was happening, I wrote a demonstration of what happens to the working directory in PHP's session handling. Install this simple file into a PHP-enabled web directory, and watch its output change as you toggle the call to
 For a flight of counterfactual fancy, imagine if my log file were "
../log/messages" and the website were set up to run from
/var/www! The error description would then not be "No such file or directory" (
ENOENT) but "Permission denied" (
EACCESS). I'm not sure whether that would have helped or hindered my search for an explanation. It may well have prompted me to reach for