PHP session garbage collection

Bug #316441 reported by Phil Bayfield
26
This bug affects 3 people
Affects Status Importance Assigned to Milestone
php5 (Ubuntu)
Confirmed
Low
Unassigned

Bug Description

Binary package hint: php5

Use of the Debian cron job for PHP session garbage collection removes the default ability of PHP to clean up old sessions in non-standard paths and custom modifications to the session handler such as database driven session storage.

Although the defaults can be restored by modifying the php.ini it would be nice to see this funcionality restored in Ubuntu.

Revision history for this message
Chuck Short (zulcss) wrote :

Which version are you using?

Thanks
chuck

Changed in php5:
status: New → Incomplete
Revision history for this message
Phil Bayfield (philio) wrote :

This is with latest Intrepid version.

Revision history for this message
Andreas Olsson (andol) wrote :

@Phil: Since you obviously looked closer at the matter, would you mind easing up the bug confirmation process by giving some examples of what works and what doesn't, which changes to php.ini you are refering to, etc?

Revision history for this message
Phil Bayfield (philio) wrote :

In the [Session] section of php.ini there is the following:

; Define the probability that the 'garbage collection' process is started
; on every session initialization.
; The probability is calculated by using gc_probability/gc_divisor,
; e.g. 1/100 means there is a 1% chance that the GC process starts
; on each request.

; This is disabled in the Debian packages, due to the strict permissions
; on /var/lib/php5. Instead of setting this here, see the cronjob at
; /etc/cron.d/php5, which uses the session.gc_maxlifetime setting below
session.gc_probability = 1
session.gc_divisor = 100

The default for session.gc_probability in Ubuntu is 0.

What does work:

Using standard PHP stuff, keeping sessions stored in default path of /var/lib/php5

What doesn't work:

Changing session path to another folder either in php.ini or using an ini_set etc (although the cron job can be modified). (For example we use an NFS share for standard PHP sessions so sessions are valid accross multiple web servers.)
Using session_set_save_handler to modify default session storage functions of php.

Granted for most users the default functionality provided currently with php5 packages will be absolutely fine, but for larger, more complex and distributed PHP applications it breaks the functionality without modification back to php defaults.

Revision history for this message
Ondřej Surý (ondrej) wrote :

So you basically complain that you have to modify gc settings when you are already modifying some other settings in non-standard way? Debian way is properly documented, and you cannot expect everything to be magickally working out of the box. Default install is ok, non-default install has to be modified anyway.

Looks like candidate for invalid bug report to me.

Revision history for this message
Phil Bayfield (philio) wrote :

Well for starters I am not complaining, I'm making a suggestion.
So use of PHP functions and the default PHP distribution settings are 'non-standard'?

Revision history for this message
Navetz (navetz) wrote :

I think this needs to be looked into.

You cannot change the session.gc_maxlifetime in your php scripts using ini_set("session.gc_maxlifetime", SOMEVALUE);

Everything says it was read correctly but the garbage collector reads the session.gc_maxlifetime directly from the php.ini file and disregards the rest. You also cannot change the session path.

I have not done to much debugging but this is a very annoying issue when you want to change the session lifetime.

Revision history for this message
Phil Bayfield (philio) wrote :

You're probably better off removing the Debian cron job and modifying the php.ini yourself to your prefered settings (even if you revert them back to the original PHP settings).

Unfortunately, it doesn't seam like anyone at Ubuntu is interested in changing this away from the Debian modifications, despite the fact it is non-standard behaviour for PHP.

There is an interesting thread on this somewhere on the PHP internals mailing list, it seams the PHP developers feel the pain of users having problems with distro modified versions of PHP and get quite a few complaints from users because of non-standard mods to the source by the linux distros (obviously not their fault)! Unfortunately couldn't find it now but it's on there somewhere.

Revision history for this message
Navetz (navetz) wrote :

Will just modifying the php.ini file work or do I have to remove this special cron job?

Revision history for this message
Phil Bayfield (philio) wrote :

If you edit /etc/cron.d/php5 you will have something like this:

# /etc/cron.d/php5: crontab fragment for php5
# This purges session files older than X, where X is defined in seconds
# as the largest value of session.gc_maxlifetime from all your php.ini
# files, or 24 minutes if not defined. See /usr/lib/php5/maxlifetime

# Look for and purge old sessions every 30 minutes
09,39 * * * * root [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -type f -cmin +$(/usr/lib/php5/maxlifetime) -print0 | xargs -n 200 -r -0 rm

Just comment the last line to disable the cron job.

Then in /etc/php5/apache2/php.ini search for the [Session] section and modify any of the following to your requirements:

session.save_handler = files

How php stores session data, leave this alone unless you want to change the save handler, e.g. to memcache

;session.save_path = /var/lib/php5

Change the location of where php saves session files. Either a local path for 'files' or a url in the form of "tcp://1.2.3.4:11211/" for memcache etc.

;session.gc_probability = 0
session.gc_divisor = 100

You will need to uncomment session.gc_probability and set it to 1 to enable the default garbage collection behaviour of PHP. This means that approx every 100 requests PHP will perform garbage collection, you could decrease session.gc_divisor or increase session.gc_probability to increase this but default should be fine.

session.gc_maxlifetime = 1440

This is how long sessions remain active, 1440 seconds is not long, only about 20 mins (24 to be exact) so it is often worth increasing this value, depending on your needs.

There are other variables in the [Session] section but you shouldn't need to change them.

Revision history for this message
SEWilco (scot-wilcoxon) wrote :

I'm adding to this report that the Ubuntu php.ini file has instructions which are impossible to follow. The php.ini section on Debian session handling refers to ext/session/mod_files.sh (a different program is for Windows) which is not included in the Ubuntu PHP5 package. So Ubuntu does not provide PHP session cleaning.

; NOTE 1: PHP will not create this directory structure automatically.
; You can use the script in the ext/session dir for that purpose.

If we're going to use Debian PHP, we need to include the session directory creation tool. And the session directories need to be created, so the cron job will work.

Whether you interpret this as Ubuntu PHP not being functional due to uninitialized session directories, or as containing a bug which fills the disk with session files, or as having a cron job which cleans the wrong directory, there is something wrong with PHP sessions.

Revision history for this message
SEWilco (scot-wilcoxon) wrote :

Related is a patch to mod_files.sh: http://bugs.php.net/bug.php?id=49175

Chuck Short (zulcss)
Changed in php5 (Ubuntu):
importance: Undecided → Low
status: Incomplete → Confirmed
Revision history for this message
Phil Bayfield (philio) wrote :

I found another issue with this cron job today.

One of our web servers was experiencing very high load, I assumed we had high traffic and went to take a look at where the traffic was coming from.

It wasn't website traffic at all.

We had so many PHP session files in the folder that the cron had failed to delete all the files within 30 minutes, in fact we had 6 cron jobs running at the same time. This almost brought the server to it's knees.

Yet another reason to loose this cron job.

Revision history for this message
Ondřej Surý (ondrej) wrote :

> Yet another reason to loose this cron job.

The reason why the Debian way of gc was introduced was security issue.

Phil, do you expect that standard installation of Debian PHP will work out-of-the-box even on high load servers without any tweaks and settings?

You are free to set the php in any way you want it. However suggesting we drop the security on the floor because your server was experiencing high load isn't really reasonable. I am sorry, but with PHP no size can fit all, and the cron-job approach is most conservative security wise.

I don't mind changing the README or default comments in the php.ini, but the default PHP installation should be most secure (even though it may not be the fastest or most efficient).

Revision history for this message
Jim Rorie (jfrorie) wrote :

I don't think anyone cares about the fastest or most efficient. But it needs to be correct. That means that it should match the PHP documentation at php.net. Currently, gc_maxlifetime is listed as PHP_IN_ALL which means that a PHP file can modify the setting. This is not true, above 1440.

I've spent about 3 weeks on this problem because the cron job supercedes the documentation.

Revision history for this message
Phil Bayfield (philio) wrote :

The irony of the situation is that the latest Ubuntu PHP packages, in Maverick and also Lucid I believe (but don't have a running version to hand to verify) actually do contain the "original" php.net defaults for garbage collection. So in fact BOTH the default PHP garbage collector and the Debian cron job are running.

So now not only does this supposed security flaw (according to Ondřej) now exist in the package, but also the half-assed Debian cron job that doesn't even prevent multiple versions of itself running and causes extremely high IO. Replacing one flawed system with another flawed system is not a solution.

The reality is that Debian are the real package maintainers and Ubuntu just make a few small modifications and run the auto build scripts, hence we're probably wasting our breath raising the issue here.

Revision history for this message
Chris Fryer (c-j-fryer) wrote :

I had a similar issue to Phil. A web server was generating PHP sessions faster than they were being deleted by the cron job. This caused the disk on which /var/lib/php5 was located to run out of inodes, and thence to a loss of service.

It is caused by this upstream workaround, which is poor:

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=461755#20

The latest version of the cron job that does PHP session garbage collection is here:

http://anonscm.debian.org/gitweb/?p=pkg-php/php.git;a=blob;f=debian/php5-common.php5.cron.d;hb=HEAD

It would probably be a good idea to backport to this LTS release, because it fixes Phil's issue, among other security concerns.

Revision history for this message
Bryce Nesbitt (bryce2) wrote :

Using cron is hacky here. It can be too slow (thus the disk fills up), or usless (such as on a laptop with no sessions getting generated).
How about something more dynamic with php counting dirty sessions, and cleaning them up synchronously at the end of a session? Let php handle this, when php needs to.

Revision history for this message
pwaring (launchpad-pwaring) wrote :

Just to add as a comment to people suggesting editing php.ini, what you should actually do is edit /etc/php5/conf.d/local.ini, as that will override any php.ini settings without causing configuration conflicts when you next upgrade PHP (apt will warn you that the file you are using differs from that provided by the maintainer).

You can also override PHP values on a per-virtual host basis in Apache.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.