Database Sessions with CakePHP 1.3 in 1 minute

Enabling database sessions with CakePHP 1.3 is super easy. But first I want to cover a few reasons that I know of where you need sessions stored in the database: load-balanced environments and PHP file-locking issues.

In a load-balanced environment you have some options.

  • Use a network file system. By this I mean using a hard disk that is accessible to all application servers. This is slow and not very failure tollerant.
  • Set the load balancers to have affinity. This means that once an ip address starts a session with one server, traffic from that ip address will always go to that same server. This doesn’t work for large organizations who use reverse proxies. Users behind reverse proxies may have a different ip address on each http request. The effect is that they get logged off intermittently.
  • Use database sessions.. Storing session data in a database provides the application with a quick way to read and write to a central location.

The problem I ran into is that sometimes the PHP session file would get locked and never unlocked. This happened on Apache 2.2 with PHP 5.3 on CentOS 5 when the application aborted AJAX requests that hadn’t completed yet. From the user point of view it looked like our application server was unresponsive. And of course the complaint was an unhelpful report that “the server is down.” I don’t know if it is a bug (or “deficiency”) with CentOS, Apache, or PHP, but I could reproduce it with a few tries of aborting AJAX requests.

So I switched to database sessions in CakePHP 1.3. You can do it in less than a minute.

First, create the sessions table:

CREATE TABLE `cake_sessions` (
`id` varchar(255) NOT NULL DEFAULT '',
`data` mediumtext,
`expires` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

If you create the sessions table from the cake command line utility it will cause two problems with the `data` column: cake will use a latin1 charset instead of utf8 and `data` will be text instead of mediumtext. The text column type maxes out at 64kb characters while mediumtext can hold up to 16MB. It is quite reasonable that sometimes you will have more than 64kb in a user’s session!

Second, alter three settings in /app/config/core.php:

Configure::write('Session.save', 'database'); // change from 'php' to 'database'
// ...
Configure::write('Session.model', 'Session'); // you can just uncomment this line
// ...
// If you use $default in /app/config/database.php you can just uncomment the following line
// Otherwise, use whatever connection you use in /app/config/database.php
// This also allows you to put your sessions table in a completely different
// database if you want
Configure::write('Session.database', 'default');
// also, because of the way Configure works, you can optionally put these settings
// in your bootstrap or other file so you don't have to touch /app/config/core.php

Last, test it. The effect will be that users currently on the site will lose their session and log out. So you may want to make the switch off hours.

Happy sessioning!