During development of a new web application that required users to log in, we had problems with users being logged out too soon. The cookies were configured to end when the sessions did, but the max life time given to sessions turned out to be completely ignored.

The application had a standard LAMP environment, the key element as we will see, being the OS: the Debian based distro Ubuntu Hardy.

How PHPs garbage collection handles sessions

The main issue behind our problem turned out to be garbage collection. PHPs garbage collection also handles sessions. This is necessary because sessions are usually stored as flat files at a given location, and since each session has a unique id they will accumulate into quite a large amount over time.

During the start up over every session, there is a chance the session garbage collection will run as well. Session garbage collection deletes all session files if they are older than the set session max life time. The default probability for a new session also running session garbage collection is one in a hundred, this probability is configurable in php.ini, along with the location of the session files.

The problem

The Ubuntu server running our web application was also running an additional application which did not always have the same PHP configuration. Apache is fully capable of this when using virtual hosts – the point is, the max life time changes were not done in any of the php.ini files. Despite of this, that is exactly were there is a clue to what was happening. The PHP version we are using is an Ubuntu/Debian package, which has some changes to the original PHP default setup. In all of the php.ini files, in the SESSION section just above the garbage collection probability setting, we found that the session garbage collection by default was actually turned off. The reason given is Debians strict permissions on the default session save path. Furthermore, the section informs that PHPs garbage collection has been replaced by a cron job.

A closer inspection of the cron job revealed this to be true, every half hour, it will look for a maxlifetime setting in all php.ini files it can find, see if it has found a value larger than its default of 24 minutes, and go on to delete all session files in the default session save path older than this value. In our case our maxlifetime settings were not in either of the ini files, which means the default value of 24 minutes was effective.

The solution

The cron job calls /usr/lib/php5/maxlifetime to determine how old sessions can be before they can be deleted, and in this file it is possible to set a new default max life time corresponding to the highest value set in either your web app or in an Apache virtual host configuration.

If you are uneasy with the OS entering territory on what arguably should be PHPs business, you can of course also remove or comment the cron job and activate PHPs session garbage collector instead.