I’ve just spent most of a day debugging an intermittent problem with session persistence in a cake php powered application. This was further complicated in that it only arose in Internet Explorer – unusual for server side code.
I should point out at this point that the application is using Cake’s database based session handling.
After much debugging (including some by email!), it turned out to be due to the way Cake handles images.
Cake comes by default with the following .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>
For anyone not familiar with mod_rewrite, or too lazy to think, this rule means that any request that isn’t for a file or directory that exists gets passed back to the index.php in Cake’s webroot folder.
This means that any images (or other files) that are referenced and do not exist are handled by php, which displays a nice "awaiting image" type logo in this application. This is a nice touch, it avoids those nasty X/torn images you normally get.
However, it also has a side effect. The application is configured to auto start the session on load – which it does even when dealing with a missing image. This causes a race condition – if an image processing thread loads the session before the main thread has finished and then finishes and saves its session after the main thread, it overwrites any session variables written by the main thread. End result of this is the intermittent apparent failure to save session data.
For now, I’ve fixed this by modifying the rewrite rule to exclude images and a few other file types so that they generate a normal 404 instead of falling back to CakePHP:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^.*\.png$ [NC]
RewriteCond %{REQUEST_URI} !^.*\.gif$ [NC]
RewriteCond %{REQUEST_URI} !^.*\.jpg$ [NC]
RewriteCond %{REQUEST_URI} !^.*\.htc$ [NC]
RewriteCond %{REQUEST_URI} !^.*\.css$ [NC]
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>
However, I’m not too happy with this – I lose the automatic handling of missing images, and it just seems a bit messy. So long term I’m after a better solution – or maybe the next cake release will resolve this.
I’ve thought of switching the sessions table to innodb and using row level locking (or even switching back to file based sessions, which by default handle locking automatically – cake may over ride this?), or else disabling the auto start for sessions and explicitly starting it where required (I’ve not tried this as I’d want to test thoroughly before deploying this, which I don’t have time for at the moment).
So, for now, its the .htaccess hack.
As to why it only affects internet explorer – I presume it’s due to way the browsers request images – firefox must time it differently, preventing the issue from arising.
Leave a reply