All in the <head> – Ponderings and code by Drew McLellan –

The Curse of max_file_uploads

Today marks a year since we shipped the first version of Perch, and we celebrated by putting out another big release. We’ve been following a strategy of shipping medium-sized updates regularly throughout the year (July, October, December, February), each time fixing any issues that users have reported and always adding some new functionality to make it worth the trouble of updating.

This latest release has been a big one. We’ve reflected that in the version number, jumping from 1.2.6 to 1.5. As well as the usual fixes and features, we’ve added an entire developer API enabling the extension of Perch through apps. The first app we’ve launched with is for the creation of new pages.

One bug that cropped up late in the development cycle had to do with a change to PHP that caught us by surprise. PHP 5.2.12 had added a new INI directive called max_file_uploads, designed to prevent DOS attacks. The supposed attack would work by uploading a huge number of files to a server, filling up the available space in its temp folder. The default setting for max_file_uploads is 20 files, and of course we’re at the point now where PHP 5.2.12 and greater are becoming reasonably common in the wild.

So how is this an issue for Perch? Well, Perch enables users to upload images and files as content to their site. A template for an item of content might have a couple of image upload fields. If you allow your content region to hold multiple items, these all appear on one long edit form in Perch. So a region with 10 items, each with 2 upload fields, and you suddenly have the possibility to upload 20 files.

Initially, I didn’t think this was going to be a problem, because that’s not typically how users add content. They don’t add 10 empty items and then go through and fill them in with content. They add one at a time, and so typically will only be uploading one or two files at a time – nowhere near the default limit of 20. But here’s the catch:

max_file_uploads counts empty upload fields as if they were being used. This means that the limit is not on how many files are uploaded, but on how many upload fields you have in your HTML form. If you have 21 file fields, you can’t even upload one single file unless it’s in one of the first 20 fields.

This issue was logged as PHP Bug #50749, but marked as “bogus” due to what sounds like a design flaw in how PHP handles uploads. The idiocy continues, however, as unlike most other PHP INI directives, this one can’t be overridden in a local .htaccess file. It gets set once, for the entire server and the individual site owner has no control over the setting.

This is pretty bad news for Perch, as the way our interface works means that it’s easy for users to end up with more than 20 fields on a form, and so it looks like we’re going to need to redesign how the UI works to get around a fairly dubious security setting.

A JavaScript workaround

Obviously, until we can restructure to work around the issue, we need something in place to fix the issue for existing customers. We make a point of not building with a dependancy on JavaScript, but in this case the only solution I could find without rebuilding the UI (which wasn’t an option this late in the cycle) was to paper over the cracks with some help from jQuery.

$('form').submit(function(){
    $('input:file[value=""]').attr('disabled', true);
});

That should be fairly self-evident, but on submit of the form, it finds any empty file input fields and toggles them as disabled. In every browser I tested, this prevents the value being submitted with the form, and so the server never knows the field existed. Any field with a value submits as normal.

If my tone sounds a little hacked off, it’s because this has annoyed me a bit. I do appreciate the need to improve security all the time, absolutely. I think mostly it’s that Bug #50749 was marked as “bogus” that annoys me so much.

The bug reporter had the same concerns as me. This security setting was not backward compatible. It was not something that had been deprecated and then gradually removed. There’s nothing at all wrong with having forms with lots of file upload fields. This change broke existing functionality, without warning.

For me as a developer of commercial PHP-based software, to have that concern marked as bogus feels like a direct insult. For my customers, software that was valid and worked well, suddenly broke due to a change in PHP. Their concerns are not bogus either – they’re very real. PHP can screw me about as much as it wants – I’m a developer and I’ll cope. But please keep things stable for my customers.