There and Back Again

PHP AJAX File Upload Progress Meter Updates

Over the weekend my file upload progress meter code got lots of traffic. It seems it made it made it on the del.icio.us popular list as well as getting over a thousands diggs. To celebrate this i’ve updated the code.

The main new feature is giving you feedback without having to patch PHP. Now the patched version gives you more information such as upload speed and estimated time to completion. But we still provide some nice user feedback even without it now.

I also created some wiki pages to start the documentation process.

So here are the demo’s

With the patch and extension
Without the patch

To get upload speed you will need to download and install the PHP Upload Progress Patch and extension.

If you want to use the code you need to:
Install HTML_AJAX (pear install HTML_AJAX-alpha)
Download PAFUPMU and install it somewhere accessible.
Add the code to your page using demo.php as an example.

The basic way the code works is we take a form containing a file upload and submit it using a hidden iframe as a target. Doing this lets the upload happen in the background. Then we poll the server on a regular basis (say a 2 second interval) asking it for update status. If you have the patch+extension installed this gives you file upload speed etc. If you don’t have the extesion we stop making AJAX calls and just animate the status bar until the upload finishes in the iframe and tells us were done.

In demo.php we handle generating the current page and handling the upload in the same page. So we start by handling the update.

include 'UploadProgressMeter.class.php';

$fileWidget = new UploadProgressMeter();

if ($fileWidget->uploadComplete()) {
        // output javascript to the iframe to send a final status to the main window
        // this will catch error conditions
        echo $fileWidget->finalStatus();

        // move the file(s) where they need to go

        exit;
}
?>

This code only runs when your uploading so you’ll never see the output of it. This can make debugging problematic. One way around this is too hack the UploadProgressMeter to make the iframe non hidden.

Next you setup the JavaScript needed, first HTML_AJAX and then the uploaders JS.

        
        
        < ?php echo $fileWidget->renderIncludeJs(); ?>

demoserver.php is included in the source, you might want to name it something else if you actually use this code. Its just a page using HTML_AJAX_Server to register the UploadProgressMeterStatus class

You also need some CSS to style the progress bar. The only important thing is that .progressBar and .progressBar .bar are relatively positioned.

.progressBar {
                position: relative;
                padding: 2px;
                width: 300px;
                height: 40px;
                font-size: 14px;
        }
        .progressBar .background {
                border: solid 1px black;
                width: 270px;
                height: 20px;
        }
        .progressBar .bar {
                position: relative;
                background-color: blue;
                width: 0px;
                height: 20px;
        }

Finally you finish things up by building a form. Note that you can include other elements in the form, but if they need to produce output you’ll have to manage calling back into the parent page from the iframes output.

renderFormExtra(); ?>> < ?php echo $fileWidget->renderHidden(); ?>
< ?php echo $fileWidget->render(); ?> < ?php echo $fileWidget->renderProgressBar(); ?>

131 thoughts on “PHP AJAX File Upload Progress Meter Updates

  1. Joshua Eichorn Post author

    Greg: You don’t have HTML_AJAX installed properly did you install it using pear.

    Load up the url from the JavaScript include to see what the error is

  2. Tore Krudtaa

    Joshua:
    I have looked at the comment 38 and read the link.

    What I would like to be able to do in addition to
    presenting an upload meter to the client on how the upload goes is this:

    After the upload of the files has been done….
    then the files are in the whatever temp dir used by php.

    When the upload to tempdir is done then my server script can start
    taking care of the uploaded files.
    This could take some time, depending on the filesize and what one wants to do with it/them.

    I would like to be able to fetch status messages from the server after the upload to temp dir has been done, but before the script has finished.

    I would even like to be able to zero the progress meter and make it start all over again, but now my server script should take care of writing the proper status messages to whatever hooks that are used to update the client of the progress.

    Example… at first the client could see:
    Uploading file(s) to server…
    + the progress meter.
    When the files has been uploaded (they are in temp dir on server), but script not finished…
    Then I would like to present:
    Copying files on server…
    + the progress meter (with status on the copying etc)
    Uploading file(s) to server… Done

    I have tested the Rasmus Lerdorf script which you can find here:
    http://talks.php.net/show/torkey06/23
    On the next page of that talk one can find an example source as well as an example upload page.

    Have been fiddling around with it and it is cool but do not like that I must use APC to make it work.
    But the way this worked made it easy for me to adjust it to my needs by keeping writing to the APC object created by the new upload stuff in PHP 5.2 after the files has been uploaded to the temp dir.

    Here I could keep reading the values from the APC object while I was handling the files and updating the object as I finished each of the files to be uploaded (moving to another dir, updating DB etc).

    That possibility is really nice to have.
    But I would like to do that without using APC.

  3. Joshua Eichorn Post author

    Tore: well you need something to do the storage, you could either extend something like that simple progress extension or use the extension + another communication mechanism.

    You could use anything you want from files to memcached to a database. Its just a matter of making your status ajax call smart enough to check the second method after the file is complete.

  4. Greg

    Hi Joshua,

    How would I go about installing HTML_AJAX on a windows environment?

    Thanks,

    Greg

  5. Pankaj Arora

    Hi ,

    We are not able to find out the path where the file is uploading, we would like to change the of the uploading directory. Please do help to us, we would be grateful to you.

    Thanks,
    Pankaj Arora

  6. Pankaj Arora

    Hi ,

    Thanks for your response Joshua, here could we specify our directory, to upload the files.

    Thanks,
    Pankaj Arora

  7. TCurtis

    I’d like to use this on my podcast page to wathc the uploads instead of an HTTP post just sitting there. But I need to be able to do mySQL functions. Is this possible (if so please a little more than ‘yes’)
    Thanks and happy hunting.

  8. Acheron

    Hmm, i get this everytime

    array(1) { [“upload”]=> array(5) { [“name”]=> string(35) “UploadProgressMeterStatus.class.php” [“type”]=> string(24) “application/octet-stream” [“tmp_name”]=> string(14) “/tmp/phpjGIH2I” [“error”]=> int(0) [“size”]=> int(3174) } }

  9. FileSpin.net Upload Host

    It took me about 5 hours straight coding, figuring out and whatnot to get this working perfectly and the exact way I wanted integrated into my site. You can have a look at http://www.filespin.net – I actually took the progress meter out as it did not fit in with the theme and left the percentage as the main feature. Thanks for this.

  10. Iain Argent

    I get the following error in the apache error log when I try to load the extension:

    /usr/sbin/apache2: relocation error: /usr/lib/php5/20060613/upload_progress_meter.so: undefined symbol: upload_progress_register_callback

    I am running PHP 5.2 under Debian Linux. I have not installed the patch.

  11. Oren

    Hey,
    great script.
    Question – Is there a way to stop the ajax polling after file upload completed? When tracking HTTP requests with FireBug in FireFox I can see the AJAX requests still being sent after upload finished, and it’s a waste of bandwidth.

  12. Uway

    Joshua,
    Thanks for the script.
    But, I would like to know, can I customize the folder for uploading file?
    If yes, what file do I have to customize?
    thanks.

  13. Joshua Eichorn Post author

    Uway:
    The temporary upload location is handled by a setting in your PHP ini. You can use move_uploaded_file to put the uploaded file anywhere.

  14. Oren

    Regarding my timer question (comments 65-66), How exactly do I do that? I can’t seem to find examples on the HTML_AJAX homepage.
    Or maybe I need to handle something through an onLoad event to stop polling?

  15. robert wagner

    this upload progress affair is one of the lamest things ever happend to the php people. since php is the benchmark web language it’s a shame how this feature is ignored by the devs. even in 5.2 the dependence on APC is ridigulous.

  16. Joshua Eichorn Post author

    Robert:
    I agree that its taken too long to get this feature into the language, but the code in 5.2 doesn’t depend on APC. The code in 5.2 is a set of hooks to get information from the file upload process. Any extension can use this to give you upload progress information. APC happens to support this but you can also use http://pecl.php.net/package/uploadprogress.

  17. Ameno

    I have all the necessary things installed, I believe, but am getting the error:
    PHP Fatal error: main() [function.require]: Failed opening required ‘HTML/AJAX/Server.php’ (include_path=’.:’) in /demoserver.php on line 3 .

    I have HTML_AJAX installed via PEAR. Any thoughts of how to fix this?

  18. Joshua Eichorn Post author

    Ameno:
    Pear isn’t in your include path, either update it in your php.ini or by using set_include_path at the top of your script.

  19. Tomas Larsson

    I am using a commersial host, so obviously I have no controll over what’s installed or not.
    Can I use the script, if not, any other suggestions what to do.

  20. Joshua Eichorn Post author

    Tomas: You can use the script, it will do an animation during the upload process. But you won’t get a speed estimate without support from your hosting company.

    There is some new file upload stuff in flash that I don’t think needs a server and should be a good solution for you.

  21. Tomas Larsson

    tnx, it actually works.

    How would I know that they support speed estimate

  22. Tomas Larsson

    Got some problems, the bar does not update, until the upload is finished.

    I got a file to large error as well, despite the file was much smaller than max_post, max_file and max_mem

  23. Tomas Larsson

    Last one is sorted, found the variable in the scripts, still dont have any updates on the progress-bar, and is says “connecting” all the time.

  24. js

    Hi, great tool! I’ve got the demo working on my server, however, now I’d like to be able to access the contents of the iframe to display the uploaded file (image) back into the form. Essentially I’m trying to allow a user to upload an image into a form. How would I go about updating the original form to display the recently uploaded image?

  25. Pingback: Cabeza de Ratón » Progreso de UpLoad de un archivo con AJAX

  26. Adrian

    hi, i’m having some problems, I’ve spent ours doing this and now seem to be going round in circles. I’ve got Php5.2.1 on my system, installed the Liip extension and done a pear install HTML_AJAX-beta (version 0.5.0). testing a the demo source provided earlier located in a trunk directory in my webroot, i just can’t get it to work. the file progress jumps from 0-100%, firebug on my windows machine displays some errors “missing ; before statement demoserver.php line 2” and “HTML_AJAX is not defined UploadProgressMeter.js line 207”. Am i missing something? i’ve looked and HTML_AJAX seems to be installed ../php/lib/php/html . I’m sorry if this obvious but i jsut can’t see what i’m doing wrong. this looks like a great solution to my problem hence i’m spending so long on this.cheers in advance

  27. Joshua Eichorn Post author

    Adrian: If your working on php 5.2.1 make sure to get the newest version from SVN.

    Also if your getting an error message it could be because of include path problems. A good way to check is too load demoserver.php?client=all by hand and see what error messages your getting.

  28. confuser

    Does the newest version of php 5.2 support the extension, I can not install the ext and patch…

  29. Constatin

    What’s the http server ? I have a similar code, for large file the whole file seems to go to the server and there is no status. I goes from 0 to 100% when the server get the whole file… I have the feeling is an apache2 setting but I can’t figure it out yet.

  30. Joshua Eichorn Post author

    I’ve only used the upload progress code with php as a module, i doubt fastcgi would work, but i would think that a normal cgi script would.

    I’ve used apache 2.0.x and 2.2.x

  31. Nick

    Does someone have an example html where 3 files are being uploaded from the same form, with 1 submit button?

  32. ANil

    Hello,

    I have tried hard using the demo for multiple file upload, but no luck .

    Can anyone help me please.

    Thanks in advance.

  33. Rumen

    Hello,
    My problems is as followed:
    1.Under last version of FireFox, sometimes the progress bar goes imediately to 100%, sometimes it says only connecting and sometimes it works fine. In all cases the file upload works but the demoserver.php returns :100% or []

  34. Ric Web

    Hi,

    I am getting the folloowing error even though the upload works. Can anyone please tell me why?

    object(Error) (3) { [“name”]=> string(5) “Error” [“description”]=> string(39) “Request Timed Out: time out was 20000ms” [“message”]=> string(39) “Request Timed Out: time out was 20000ms” }

    Thanks
    Rick

  35. Joshua Eichorn Post author

    Rumen: I’m not sure whats going on, how big of files are you uploading.

    Ric:
    The ajax status request calls are timing out for some reason

  36. Ric Web

    Hi Joshua,

    Do you have any idea why this would be as it only happens with big files.

    Thanks for any help you can offer

    Rick

  37. Joshua Eichorn Post author

    Ric: the ajax status call happens outside of the upload so I don’t see why that would affect things. Maybe your server is low on memory or has a slow network connection?

  38. Ric Web

    Hi Joshua,

    The server is a test server just running this script at the moment with dual processors, 2gb memory and on the Rackspace hosting environment. I have asked them to check it and the server is responding as it should. Is there anyway I can at least increase the timeout so that the message does not appear?

    Thanks for your help
    Rick

  39. Joshua Eichorn Post author

    Ric doesn’t sound like you should be having any problems at all.

    You might start by setting a longer interval so your not polling quite as often you do that by setting: UploadProgressMeter_interval to something higher then its default 2000 (UploadProgressMeter.js)

    You can change the 20 second timeout to something longer by editing line 193 of that same file and inserting:
    UploadProgressMeter_remote.dispatcher.timeout = 40000;