Jun 25, 2008

HOWTO: PHP and jQuery upload progress bar

Author: gaweee | Filed under: development, howto

With the controllable jQuery Progress Bar, writing a form upload progress bar seems like a piece of cake now. Hypothetically, all we need is to create the bar, poll for the progress of the file upload, derive the new progress bar value (in percentage) and set it.

To do that you need to prepare the php script to do it. By default PHP cant report the progress of upload progress. However people smarter than me have already solved that problem. In 5 mins i’ve found 2 solutions: the Alternative PHP Cache (APC) method as well as the UploadProgress method. Both of them are PECL packages. Because i couldnt get APC to work on my server properly, i’ll document the UploadProgress more in detail here…

Step 1: Install the uploadprogress package. Really simple just run the following command  

pecl install uploadprogress

Once that is done, register the extension to your PHP with the following line in your php.ini

extension=uploadprogress.so

then restart your apache/httpd

Step 2: Create the form and your progress bar  

<form id="uploadform" enctype="multipart/form-data" method="post">
<input id="progress_key" name="UPLOAD_IDENTIFIER" type="hidden" value="&lt;?= $uuid ?&gt;" />
<input id="ulfile" name="ulfile" type="file" />
<input type="submit" value="Upload" />
	<span id="uploadprogressbar" class="progressbar">0%</span>
</form>

this creates the form with a file field as well as a unique UPLOAD_IDENTIFIER hidden field that allows our script to check the progress of the form submission.

Step 3: Next the script itself to check the respond with the progress of the form submission. Lets call this file uploadprogress.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($_GET['id']));
	exit();
}

The header no-cache declarations circumvents IE’s cache of the response. Basically this form does nothing but respond with a json encoded string of the uploadprogress_get_info function. The id argument is the same one we used in the form. Think of it as a form-upload-process-id. A typical response looks like this:

{"time_start":"1214384364","time_last":"1214384366","speed_average":"25889","speed_last":"40952","bytes_uploaded" :"51778","bytes_total":"8125518","files_uploaded":"0","est_sec":"311"}

the response encodes a good deal of data about the form submission. most importantly for us: bytes_uploaded and bytes_total

Step 3: use jQuery and a timer to keep polling the page and update the progress bar value  

var progress_key = '';
 
// this sets up the progress bar
$(document).ready(function() {
	$("#uploadprogressbar").progressBar();
});
 
// fades in the progress bar and starts polling the upload progress after 1.5seconds
function beginUpload() {
	$("#uploadprogressbar").fadeIn();
	setTimeout("showUpload()", 1500);
}
 
// uses ajax to poll the uploadprogress.php page with the id
// deserializes the json string, and computes the percentage (integer)
// update the jQuery progress bar
// sets a timer for the next poll in 750ms
function showUpload() {
	$.get("uploadprogress.php?id=" + progress_key, function(data) {
		if (!data)
			return;
 
		var response;
		eval ("response = " + data);
 
		if (!response)
			return;
 
		var percentage = Math.floor(100 * parseInt(response['bytes_uploaded']) / parseInt(response['bytes_total']));
		$("#uploadprogressbar").progressBar(percentage);
 
	});
	setTimeout("showUpload()", 750);
}

viola! read the comments if you dont understand the code. it is _THAT_ straightforward. Of course there can be many improvements such as stopping the script when the upload reaches 100% but thats probably not really needed since the whole page is refreshed. But this approach allows the flexibility of ajax submissions and what nots.

Again, download the jQuery progressbar here: jQuery progressbar
or view the demo here

Note: for the APC solution seekers out there, assuming you can get APC to work, the solution is not so different. A few changes will get your there:  

  • Change the HTML hidden form field name from UPLOAD_IDENTIFIER to APC_UPLOAD_PROGRESS
  • Change the PHP uploadprogress_get_info($_GET['id']) to apc_fetch(‘upload_’.$_GET['id']));
  • Change the Javascript percentage calculation from:
    Math.floor(100 * parseInt(response['bytes_uploaded']) / parseInt(response['bytes_total']));
    to:
    Math.floor(100 * parseInt(response['current']) / parseInt(response['total']));

48 Responses to “HOWTO: PHP and jQuery upload progress bar”

  1. Jeremy Roberts Says:

    I tried and it works like a charm

  2. gaweee Says:

    Hi guys,
    the jquery progress bar is MIT license of course
    No need to credit the author or donation or anything like that.
    Just use and abuse!

  3. Jakob Says:

    II am unable to leave a comment at http://t.wits.sg/jquery-progress-bar/, however the plugin is used here. I am wondering what the copyright notice in the progressbar plugin covers. Who can use it, may it become part of a commerical product, must companies purchase a license for using it? – In other words can you more precisely define the copyrights you hold over your plugin?

  4. Joshua Says:

    Thanks in advanced for this great plugin!

    I have the script installed… Progressing is working great.. But I am baffled on how you handle the uploaded script..

    I know that I, and probably several others are running into this query… I noticed a gentleman above posted he was using uploadscript.php as a script to handle the uploaded file… The problem is, WHERE lol… Where is he referencing this file? The action attribute on the form? Some where in the JavaScript? Where?

    Also, if the file is being referenced in the action, how can we debug that page… Because it’s not being called via jQuery how can we ever see what that file has received?

    This is a great plugin, and I know it’s certainly helpful for those like me who refuse to use a FlashUploader.. but some further directions in the tutorial on where we can access the uploaded files would be spectacular…

    Thanks!

  5. jurma Says:

    Ok, nevermind, I’ve found it. Needed “return;” in onSubmit call;

  6. jurma Says:

    Hello!
    Noticed that on Firefox this example sends POST with whole file after the data was sent once by multiple GETs. Does anyone know how to disable this file send in POST?
    In IE this thing seems not occure.

  7. james Says:

    hey i got this working on my server; progress bar is moving and everything. The only problem it never uploaded the file to the directory? Anyone get this working correctly to let us all know? thanks

  8. alex Says:

    sorry…your first reply wasn;t for me :P

  9. alex Says:

    gaweee, my problem is that it’s not uploading the file at all and nope…i don;t have an shell account(i guess it should be there in the cPanel interface but it isn;t)…what else could i do?

  10. hi Says:

    hey gaweee thanks for reply.

    Okay i actually noticed that action=”myrealuploadscript.php” and onsubmit=”calls ajax”

    i have pecl uploadprogress showing in my phpinfo so i know it is installed correctly.
    the ajax calls a checkprogress.php which has
    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();

    in action=”myscript.php” i have

    move_uploaded_file($_FILES['Filedata']['tmp_name']);
    exit();

    but nothing happens?

    thanks!

  11. gaweee Says:

    it seems it is trying to install the package peclinstallUploadProgress instead of uploadprogess
    If you have a shell account, you can try running the command instead
    pecl install uploadprogress

  12. gaweee Says:

    It calls the script multiple times to only detect the status of the upload. This is done by asking the script to fetch the upload status via the UPLOAD_IDENTIFIER variable. It wont upload your file multiple times. Dont worry =)

  13. alex Says:

    so…things are gettin’ complicated just from the beginning, i tried to install UploadProgress on a payed server… with “pecl install uploadprogress”(i am using cPanel) but it gives me this error:

    No releases available for package “pear.php.net/peclinstalluploadprogress”
    Cannot initialize ‘channel://pear.php.net/peclinstallUploadProgress’, invalid or missing package file
    Package “channel://pear.php.net/peclinstallUploadProgress” is not valid
    install failed
    /usr/local/jdk/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/lib/courier-imap/sbin:/usr/lib/courier-imap/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/X11R6/bin:/root/bin:/opt/bin

    what am i doing wrong?(it works with pear packages)

  14. hi Says:

    Hi im trying to understand this. uploadprogress.php is this my document where i specify all stuff i want to do ? Bc if it calls this url all time to check on the upload progress will it upload the file multile times? can anyone help ?

  15. ZJA Says:

    Humm… Can I have an example of the uploadprogress.php? Basically i want to know how to get the file total size and bytes uploaded

  16. fadi Says:

    great plugin, however i need some help getting this to work on opera and safari??
    thx

  17. Paulo Says:

    Any ideas?? I did:
    $(‘progressbar’).progressBar(1)
    $(‘progressbar’).progressBar(2)
    $(‘progressbar’).progressBar(3)…
    $(‘progressbar’).progressBar(100)

    This apparently create 100 objects progressBar, isnt it?
    Why not create only one object and update them?
    I got 100% CPU, I believe this is the reason.

  18. okan Says:

    Very thanks for the article. great work.

  19. Paulo Says:

    Nice plugin! But I am having a big problem, when I make a progress bar for long time, like hours, I get 100% of my CPU bacause the call x.progressbar(percentage). I believe this method create a prototype, doesn’t it?
    There is a way to get a reference of that object and use it only?
    Thanks in advance!

  20. 克兰印象 » 20款PHP+JQuery应用 Says:

    [...] 10. 如何用PHP and jQuery创建上传进度条 [...]

  21. 20 Useful PHP + jQuery Components & Tuts for Everyday Project | Noupe Says:

    [...] 10. HOWTO: PHP and jQuery upload progress bar [...]

  22. Jake Says:

    Okay, so it saves the file to the uuid, right? Wouldn’t this be written to a temp file somewhere? Or am I missing the boat?

  23. Br1an Says:

    I have the same problem

  24. Mark Says:

    @J reply number 22:
    Can you post your working code? I can’t make this example work. I have successfully installed php_uploadprogress.dll in my wamp. Thanks

  25. J Says:

    I just want to point out how to check if you have gotten uploadprogress installed correctly or not.

    Create a phpinfo page, and you should see a table of entries dedicated to uploadprogress bar. Its position is should be somewhere above Zend Optimizer table. Otherwise just search for the keyword “uploadprogress” and your browser will point it out at you. If you DO NOT have this table, chances are you did not have it installed correctly.

    There could be a few reasons to this. In my particular case however, I had a problem with my extension_dir pointing at the wrong directory. After doing some lookup at the position of uploadprogress.so, I changed the settings, uploadprogress works perfectly.

    Now the author might not have been very obvious about this, but the structure of your upload script should look like this.

    uploadform.php
    uploadscript.php
    uploadprogress.php

    Uploadform.php will obviously contain the javascript, html form elements etc.

    Uploadprogress.php will contain the codes listed on step 3 in the article.

    Uploadscript.php, is the script you will have to code yourself to save the uploaded files into a desired directory and perform other actions.

    On upload, uploadform.php will submit the information to uploadscript.php, while the javascript will “ping” uploadprogress.php every X milliseconds to get a progress and build a upload progress bar.

    Hopefully my comment will help others to understand this article better. Eitherway, this article is great. Helped me out a ton! Thanks!

  26. Marcelo Says:

    Thanks for this script.
    I had any problems to be work this script on my server.
    You would share the code of demo.php, with this example code i have find where i´m wrong.

  27. wa7eed Says:

    hi
    thank you for this great jop
    I wander If I can use it with :

    http://www.fyneworks.com/jquery/multiple-file-upload/

    thank you .

  28. ata Says:

    Thanks for the article.
    In order to run this script we should trigger beginUpload() function with adding onSubmit=”beginUpload()” attribute to form.

  29. Wazza Says:

    Hi there, great work – very nice.
    Just wondering if you could incorporate a Get Image Witdh and Height on upload into the current versions… Also set Maximagewitdh and echo back error if too big.
    Cheers

  30. jc Says:

    nevermind, everything works, i love it !!!!!!!!!!!!!

  31. jc Says:

    finally it works…
    but where is uploaded the file ?

  32. jc Says:

    Could someone help me…

    I’ve tried the demo on my server (APC extension is installed) but the progress bar still at 0… :(
    When I do some tests; I can see that the variabe data is on false… i guess it’s supposed to be an array…
    where does it come from ??? any clue ?

    thx for ur help !

    JC

  33. Corey Says:

    Thx for this. Nice and neat solution except… In addition to Safari, it doesn’t work in Opera. *sigh* I’ll keep digging around.

  34. Rob Hawkes Says:

    Thanks for the script. Is there any chance you could upload all the files from the example?

  35. keith Says:

    have all of the above but the progress bar stays at zero. Need help.

  36. A Says:

    The “view the demo” linked at the end of the article http://t.wits.sg/misc/jQueryProgressBar/demo.php has multiple file input fields, but the demo code is not setup right in order for uploadprogress.so to monitor all the files.

    In order for the hooks to monitor ALL files, the file input fields need to be setup so they are named all the same name with array brackets, like

    input type=file name=ufile[]
    input type=file name=ufile[]
    input type=file name=ufile[]

    and NOT

    input type=file name=ufile1
    input type=file name=ufile2
    input type=file name=ufile3

    as shown in the demo.

    If you do the former (ufile[]), then the one UPLOAD_IDENTIFIER will track all 3 files in succession, and the json response will contain another field called

    files_uploaded

    which will tell you how many of the array of inoput files have arrived on the server so far.

    After all files arrive on the server, then your form page will reload and your php script that was the ACTION of the form will have access to the $_FILES variables as usual.

  37. JWard Says:

    That’s a problem with Safari. Here’s someone else who did something similar with an Apache module. I haven’t taken the time to convert it over to this progress bar yet through:

    http://drogomir.com/blog/2008/6/30/upload-progress-script-with-safari-support

  38. Obegowag Says:

    Thanks for the post

  39. Mike Says:

    Has anybody managed to get this to work in Safari?

  40. james Says:

    Hi Cesar,

    By having a quick read on this code I think he actually means guid (global unique identifier), essentially, a unique random value to identify which upload we want data for incase we have multiple.

    $guid = md5(time()); will do it.

  41. Greg Says:

    Hi,

    Your plugin seems to be great but i cannot make it works. Same as César I don’t understand this: ”.

    Thanks in advance for your work and help.

  42. nuwinda Says:

    ok progress bar is working(nice one) how can we configure other details such as where to upload on the…

  43. Chris Says:

    Great Post! I’ve been using APC progress for a while but wanted to try this out. I am so close, but it just isn’t working… the temp files are generated and the progress status is returned… BUT… my upload page gets a UPLOAD_ERR_EXTENSION error. I go back to APC and all is well. Odd?

  44. mike Says:

    Thanks for this article. I was going to tackle this myself as I’m currently using an APC/yui solution, but YUI is awfully bloated.

    and @Cesar:
    $uuid is set in the first line under step 2:

    it’s just a unique code.. could be anything you want, md5 etc… It’s unique to make sure that simultaneous uploads don’t trip over each other and report the wrong progress.

  45. Cesar Says:

    Hello, I’m very interested in your code but I can’t get it to work… I can’t figured out where do you get the $uuid variable, could you publish your demo.php to see what are you doing! thanks

Leave a Reply