Okay so a little bit on how this was built…
First of all, I am so not good at this sort of programming that I am almost 99% positive following my instructions will cause your server to implode. But maybe those of you better at this than I am can make something real out of it?
Second of all, the internet is awesome and if it wasn’t for other people posting their solutions to problems I never would have gotten anything done.
Third of all, I’m sorry in advance that this is so long, I didn’t really edit it and I don’t want to post it on the Wiki or a blog because I’m still not sure of the general stability and security of what is going on.
So, the issue is file uploads — it’s a real drag uploading large files via EE (not picking on it, it just happens to be the CMS we’re all using), partly because there’s the issue of PHP memory, partly because the browsers are wacky, mostly because there’s no way to see how the upload is going, which is a Bad Experience for the client. Using FTP is an even bigger drag because we went through all these lengths to sell a magic CMS to the client and now we’re making them bust out Transmit when in their mind “YouTube and YouSendIt can do it, why can’t my site?”
So here’s a basic list of what needed to be addressed and how I did it. By the way, I lease a server that I host most of my clients on, just for occasions like this, so addressing the PHP issues is easier for me. Your mileage may vary.
1. get PHP happy with dealing with large files
2. get Safari happy with dealing with large files
3. set up the server so it can report on file progress
4. get that file progress injected into the control panel somehow
PHP’s issue is mostly memory, so I bumped up these figures in my php.ini file (if you’re a reseller using WHM you can also do this through the control panel):
memory_limit = 500M
post_max_size = 300M
upload_max_filesize = 100M
post_max_size needs to be bigger than upload_max_filesize, and memory_limit needs to be pretty large if you’re gonna handle anything larger than a few MBs.
Next up, Safari sometimes hangs when trying to upload anything larger than a few hundred kB, and after a little bit of digging I found that adding
header("connection: close");
…to the very top of system/index.php seemed to solve that issue. I guess the deal is Safari might have issues closing the HTTP connection and adding this header to the page that processes the form helps. I’m sure there is a more elegant way of solving this but so far it doesn’t seem to bother tech support very much.
The biggest part of the upload equation is how to poll the server to get upload progress. I used a PHP extension called uploadprogress (I got the idea from this article). There are a bunch of different options out there depending on your server set up (different PHP extensions, Apache modules, Linux patches, etc.); this was the easiest for me to set up on my server. This guy does a great job of explaining how it works.
Finally we get the progress meter installed. I don’t know how to code extensions and all that so I piggybacked some jQuery on my install of nGen File Field. Theoretically you could add this code wherever you wanted and ideally as its own extension but for me it made sense to incorporate it into the file field.
The way the script works is like so:
1. insert the HTML of the progress meter
2. insert the UPLOAD_IDENTIFIER variable uploadprogress needs
3. call up a PHP page via ajax which will grab the current upload info
4. report that info back to the progress meter
Initially I rolled this code myself but I couldn’t get it to work in Safari — turns out Safari will not run ajax code after a form has been submitted (after the browser leaves a page). Eventually I found a solution online as well as a script that did most of the work; the key is to run the code from an iframe which reports back to the parent page.
To install all this I added some new files and images to the /system/extensions/fieldtypes/ngen_file_field directory and did a little editing.
First, I called the extra scripts I needed (ft.ngen_file_field.php):
$this->include_css('styles/ngen_file_field.css');
$this->include_js('scripts/jquery.livequery.js');
$this->include_js('scripts/jquery.uuid.js');
$this->include_js('scripts/jquery.uploadProgress.js');
$this->include_js('scripts/jquery.ngen_file_field.js');
uuid.js is a simple plugin to create a uuid, uploadProgress.js is the script I linked to above.
Next up, I added the PHP page that would gather the upload info (uploadprogress.php):
<?php
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
if (@$_GET['id']) {
echo json_encode(uploadprogress_get_info($_REQUEST['id']));
exit();
}
if (@$_POST['UPLOAD_IDENTIFIER'])
exit();
?>
…where “id” is the uuid value of the UPLOAD_IDENTIFIER key.
To be continued…