PHP 5.2 upload progress meter

Yesterday I’ve spent considerable amount of time in order to find out more about the most interesting new PHP 5.2 feature – hook for upload progress meter. Except for this link I haven’t found anything else, no php source code example how to make one.

However, after I looked at internal php mailing list archive, I’ve found this thread, still no php data found, but Rasmus mentioned link with an example at http://progphp.com/progress.php. I immediately tried upload and it looked very cool. Then I looked at html source code and noticed one unusual thing there: APC_UPLOAD_PROGRESS hidden field inside of html source. I knew it must be important so I’ve googled for it, and insteresting enough first result was source code of Rasmus example above 🙂

So, I took complete source (I figured out later it is upload meter example made by Rasmus Lerdorf) and quickly tried to make it working under my fresh new installed PHP 5.2.0. Unfortunately, it didn’t work since it needed apc stuff installed. After I looked at apc documentation, I found that I need to grab it from list of pecl dll’s for windows php 5.2 version. Unfortunately, after I’ve downloaded it from here I’ve noticed apc dll is missing there ?!!

Again, I had to google for php_apc.dll and after a while found needed dll available at http://pecl4win.php.net/ext.php/php_apc.dll. In order to make it working, you have to save dll file under php/ext dir (i.e. c:\php\ext on windows) and put this to php.ini:

extension=php_apc.dll

Unfortunately, it still didn’t work, so I’ve looked at apc docs further. Finally on this page I’ve found apc have new “special feature” which is directly related to our new upload feature.

    apc.rfc1867             RFC1867 File Upload Progress hook handler is only available
                            if you compiled APC against PHP 5.2.0 or later.  When enabled
                            any file uploads which includes a field called 
                            APC_UPLOAD_PROGRESS before the file field in an upload form
                            will cause APC to automatically create an upload_
                            user cache entry where  is the value of the 
                            APC_UPLOAD_PROGRESS form entry.
                            (Default: 0)

After I figured out on my phpinfo page apc.rfc1867 setting is turned off, I’ve added

apc.rfc1867 = on 

in php.ini, and after restart was finally able to enjoy new fancy upload progress meter 🙂

upload progress meter

Btw, upload also depend of json turned on as well, but it was already turned on so I didn’t have any more problems.

About the code Rasmus used in his example, I am tired to analyze it more now, but obviously it use Yahoo! User Interface Library to create progress bar and json/apc to control it from php during file upload.

I hope this will be helpful for someone. Enjoy 😉

55 thoughts to “PHP 5.2 upload progress meter”

  1. Thanks for the

    apc.rfc1867 = on

    hint, that made it allmost work flawlessly.

    Found an annoying bug though.

    If you make a multi file upload_form and do not fill out all of the file fields then the
    cancel_upload parameter get a value of 4 and the the whole upload is reported as:

    Cancelled after 109300234 bytes

    even if the upload actually was a success.

    If anyone comes up with a workaround or fix for that would be great.

    Except for that I would like to see a solution where we did not have to use APC to make it work.

  2. Upload progress meter not working in IE (6.0) either.

    Tested against:
    http://progphp.com/progress.php

    I suspect that is more to do with YUI and/or JSON ..
    will make a custom AJAX like replacement for those and see what happens tomorrow.

    Anyone else with info on this?

  3. Yeah, I noticed after your comment that progress meter doesn’t work in IE6, but didn’t have a time to look at it. When i get a chance will do and let you know what I’ve found 🙂

  4. Filed a feature request to php bugs database asking that they make this new upload variables in 5.2 using session variables instead of APC objects.

    http://bugs.php.net/39447

    Do not see why we should have to use APC to get this thing working in PHP.

    It could be an optional feature though, controlled by a php.ini variable.

    Hope they can do this ASAP.

  5. The reason it did not work in IE was because of caching issues.

    In IE it fetches the first get request from server and then the rest from the cache.

    To avoid it we can use:

    } else if(isset($_GET[‘progress_key’])) {
    header( “Expires: Mon, 26 Jul 1997 05:00:00 GMT” ); // disable IE caching
    header( “Last-Modified: ” . gmdate( “D, d M Y H:i:s” ) . ” GMT” );
    header( “Cache-Control: no-cache, must-revalidate” );
    header( “Pragma: no-cache” );

    $status = apc_fetch(‘upload_’.$_GET[‘progress_key’]);
    echo json_encode($status);
    exit;
    }

    Or eventually put a counter in the URL used to produce a get request in order to make each get request unique and thereby preventing IE from caching.

    Note that there seem to be a bug if you have more than one file fields in the the upload form, and only uses some of the fields (and the empty fields are not disabled before submitting the form)…
    then the cancel_upload parameter will be set to 4 even if the upload went okay.

    Using a javascript to check if some of the fields are empty and disabling those fields before submitting the form will (in most cases) prevent cancel_upload to get the value of 4.

    Regards

  6. Hi !

    On my Wamp Server, there is no problem to make appear the progress bar (i’ve rewrite the code in a Prototype.js way , i prefer !)

    But on my Lamp server, all i have it’s a “false” response from the apc_fetch(‘upload_’.$_GET[“progress_key”])

    I’ve a problem with IE also despite the remarks of Tore Krudtaa about preveting cache…

    Enjoy the codes below :

    uploads.js

    function arrondi(m){return (Math.round(m*100))/100}
    function mega(m){return arrondi(parseFloat(m/(1024*1024)))}
    function uploadTermine(r){
    	if (r['cancel_upload']) txt = "Transfert annulé !";
    	else txt = mega(r['total'])+" Mo transférés !";
    	$('pbar').style.width = "100%";
    	if (txt) txt = " ("+txt+")";
    	$('ppct').update("100%"+txt);
    }
    function progressStatus(o){
    	var r = eval('('+o.responseText+')');
    	if(!r['done']){ 
    		if(r['total']){
    			var pct = arrondi(parseFloat(100*(r['current']/r['total'])));
    			$('pbar').style.width = pct+'%';
    			txt = pct+"% ("+mega(r['current'])+"/"+mega(r['total'])+" Mo)";
    		}
    	}else if (r['cancel_upload']) txt = "Transfert annulé !";
    	else if (r['current']==r['total']) uploadTermine(r);
    	$('ppct').update(txt);
    }
    function updateProgress(){
    	new Ajax.Request('ajax/upload_progress.php',
    		{parameters:'progress_key='+$F('progress_key'),onComplete:progressStatus}
    	);
    }
    function progress(){
    	new Draggable('progress',{revert:true});
    	new PeriodicalExecuter(updateProgress,1); 	$('pbar').style.width = "0%";
    	$('ppct').update("0%");
    	Effect.Appear('progress',2);
    }
    

    style.css

    body,input{
    	font:.85em 'Trebuchet MS';
    }
    #progress{
    	height: .85em; 
    	width: 300px; 
    	border:1px solid #000;
    	margin:3px 0 3px 0;
    	cursor:move;
    }
    #progress #pbar{
    	background: #FFC300; 
    	height: .90em; 
    	width:0%; 
    	float:left;
    }
    #progress #ppct {
    	font:.80em 'Trebuchet MS';
    	margin: -2px auto 0 auto;
    	text-align:center;
    }
    

    upload.php

    <html>
    <head>
    <script type="text/javascript" src="js/prototype.js"></script>
    <script type="text/javascript" src="js/scriptaculous.js?load=effects,dragdrop"></script>
    <script type="text/javascript" src="js/uploads.js?p=1164196800"></script>
    <link rel="stylesheet" type="text/css" href="css/style.css" />
    </head>
    <body>
    <form enctype="multipart/form-data" id="formulaire" action="recu.php" method="POST">
    	<input type="hidden" name="APC_UPLOAD_PROGRESS" id="progress_key" value="45643bc03f565"/>
    <input type="file" id="test_file3" name="test_file3"/>
    <div id="progress" style="display:none"><div id="pbar"></div><div id="ppct">0%</div></div>
    
    <script type="text/javascript">Event.observe("formulaire","submit",progress);</script>
    	<input type="submit" value="Upload!"/>
    </form>
    </body>
    </html>

    upload_progress.php

    <?php
    if(isset($_POST['progress_key'])) {
    	echo json_encode(apc_fetch('upload_'.$_POST['progress_key']));
    	exit;
    }
    >
    
  7. If anyone has any idear about my lamp problem (json + apc activated, same config as wamp…)

    and the IE problem too…

  8. Hey le_zell.

    I had the same problem as you, but have now fixed it. After hours of searching, I think the problem is that APC-3.0.12p2 doesn’t have rfc support built into it. I did some googling and found their CVS and downloaded the files for version 3.0.13-dev. I have made a tarball of these for you. Try installing this one and see if it works.

    http://www.nfsg.net/APC-3.0.13-dev.tar.gz

  9. OOps,

    i must have a problem on my compilled librairy APC…

    a phpinfo() gives me : Fatal error: Call to undefined function apc_cache_info() in /home/intranet/www/phpinfo.php on line 5

    A future release of PAC will have the rfc support no ?
    We have just to wait these support ?

    thanks mike !

  10. It’s explain a lot of things.

    I’ve tried to compiled a new apc.so extension but no sucess, a phpinfo() gives me fatal error on apc functions.

    So i will wait for the future support of RFC in the APC developpements.

    thanks mike !

  11. I’ve installed PHP 5.2.0 as FastCGI server API, but APC return false on every AJAX requests, Is it only working when php compiled as Apache module?

  12. I haven’t seen this posted anywhere but it has been giving me fits. Tests with multiple simultaneous file uploads through multiple iframe pipes or even in multiple browsers results in apc neglecting the first-created upload variable. So tracking one file at a time works fine but if I attempt to track a second file’s progress at the same time I can see by watching apc_cache_info(‘user’) that updates to the first upload_x variable stop occurring after the second file begins to upload.

  13. Hi, i dont have a clue about apache, or anything, maybe i can get into php.ini. i have a linux server, i would like to install that uploader but i get errors

    Warning: uniqid() expects at least 1 parameter, 0 given in /home/funk999/public_html/ajax/demo.php on line 3
    0%

    then once complete
    Array ( [test_file3] => Array ( [name] => http://www.wmv [type] => video/x-ms-wmv [tmp_name] => /tmp/phplv7owV [error] => 0 [size] => 369565 ) ) Array ( [APC_UPLOAD_PROGRESS] => )

    so.. i cant find where it has uploaded to… please help

    abdulwahid999@hotmail.com

  14. the script is only an example, if you want to store the files permanently look into the function move_uploaded_file… at the moment the file only lives in your temp directory and php deletes it after the page is generated.

  15. Thanks man! 🙂 You did the hard work for us.. otherwise i would have had to follow the same path u took 🙂 of searching ans trying.. thanks a lot! 🙂

  16. How to save the file permanently? For sure have i to use the move_uploaded_file function – but where since the action of the form is never being called.
    So please give me an hint how to call a PHP script with $_FILES available after the successful upload.

    Anyway a great Tutorial which saved me lots of time. Many Thanks.

  17. hello~

    i use version 3.0.13-dev,but rfc is not in my phpinfo,could anyone tell me something wrong??

  18. OKAY SO.. let’s see.. The CGI uploaders can show kb per second and estimated time left, etc.. and move very fast..

    why should one use this PHP uploader?

    whats the point if it is not better than existing technology that is 10 years old?

  19. Good reference. Thanks.

    Just a note for Linux users, you will need to download from current CVS and build it yourself. The current pecl module (3.12p2) doesn’t have the apc.rfc1867 property enabled.

  20. Ok, I got APC installed. i just stumbled across this script the same way you did, i did a search in google and just found the progphp.com/progress.php and tried uploading a file and it was exactly what I am looking for. I have a php script that can handle multiple files at one time, but how can I get this to work with that. There doesn’t seem to be any reference to a seperate php code that handles the file. What is it doing with the file? Also, when I try and run a page with the script exactly (copied and pasted pretty much, changed a few things and downloaded all the js files to my own server) all i get is a: {“done”:1} after it has uploaded the file. It doesn’t show the progress bar. I hope someone can help me out with this, this seems to be the answer to my problems.

  21. I am also having problems tracking simultaneous uploads. Has anybody found a solution?

  22. Hi i`ve tried to make this thing working on my local server and i have a problem with saving files.
    What should i write and where to make files save, and how can I check some file parameters 9like size or type) and get form back to user if it is with mistakes.

    I’ve writen in progress.php something like that
    if($_SERVER[‘REQUEST_METHOD’]==’POST’) {
    $status = apc_fetch(‘upload_’.$_POST[‘APC_UPLOAD_PROGRESS’]);
    $status[‘done’]=1;
    echo json_encode($status);

    $file=$_FILES[‘test_file’];
    $name = $file[‘name’];
    $tmp_name = $file[‘tmp_name’];

    $filename=”$root_path/mp3/$name”;

    move_uploaded_file($tmp_name, $filename);

    But it makes progress bar not to display progress but file gets loaded into dir.

  23. hello!
    i added the
    apc.rfc1867 = on
    to my php.ini.
    but after restart it´s not shown in the phpinfo() ?
    i can see the apc – part, but not this rfc1867 stuff…
    what´s my problem? 🙁

    thank you!

  24. Regarding the IE issue – use POST requests. For some unknown reason IE caches GET requests, even when you tell it not to do and expire the cache. I’m not sure, but I think they fixed it in IE7.

  25. apc.rfc1867 = on

    Thanks… I was ready to start screaming.

    That really helped. Will try to post an example using this with dojo.io in a few days here. I have all of the dojo part working which barely has any docs, and the php barely has any docs either, but this was the key for the php part.

  26. Hi,

    I am working on an HTTPS file uploader using APC. I have a linux/apache server. It works very well on Firefox, but not on IE. Have you a solution for this problem.

    I disabled the IE cache (using the header lines), but it does not change any thing.

    Thanks.

  27. Working On IE 6 & 7:

    function update_progress() {
    var currentTime = new Date();
    progress_key = document.getElementById(‘progress_key’).value;
    YAHOO.util.Connect.asyncRequest(‘GET’,’progress.php?progress_key=’+progress_key+’&time=’+currentTime.getTime(), progress_callback);
    }

    but be sure that you don’t post files that apache configuration don’t accept.

  28. le zell – what about recu.php? you dont include that and the link to your zip file no longer works. please repost!

    thanks,

    luke.

  29. Hey, I just wanted to try this upload meter, too, and ran into another problem. apc_fetch() returns false to me most of the time. At the very first upload I tried, it sometimes returned some data, but now it doesn’t anymore. I have a FastCGI setup with PHP 5.2.4 and APC. The problem is this: FastCGI runs multiple PHP processes that handle requests. Every HTTP request runs in under a different PHP process. I could test this with getmypid(), which is different every time, but only from a limited set. apc_cache_info() shows all upload_* entries for a process, but only for this specific process. So if I upload a file to one process, I can only get progress info from the same process again. But since every HTTP request comes to a different process, this works in only a few cases and often just returns false. It seems that every PHP process in FastCGI has its own APC cache, so this feature is nice but useless in these environments.

  30. Hi, we have a IE6 & 7, and Mozilla Firefox, with IE any version all working fine, but with Firefox, the window upload animation don’t progress. any body have a idea.

  31. Hi, I’ve tryed this piece of code on two server and on an ubuntu with PHP Version 5.2.3-1ubuntu6 it works fine.
    On OpenSuse with PHP Version 5.2.4 I’ve the problem that apc_fetch returns always false.

    I’ve compared the phpinfo() for the two servers and in apc section are equal.

    I’ve tried the suggestion of Yves, and looked at pid with the function getmypid().
    The pid are always equal, but the returns of apc_fetch it’s always false.

    Anyone can suggest me what type of debug I can do?

  32. to Tore Krudtaa:

    in IE, ajax can set send uri a different, let IE work. like add a rnd=Math.random()+new Date().getTime().

    In jQuery, it’s needn’t to do this.

  33. I’ve read this discussion but I still can not find how do I save the uploaded file ?
    Let’s say I already had a form in *.php file which contains some fields and the file to upload. Now I want to add the feature to track the file upload progress to the existing form using this example and yui Java scripts.
    Should I include this form in iframe as a part of progress.php ? What is the best approach for this ?
    Thank you to everyone in advance,
    Alex.

  34. Has anyone experienced results from apc_fetch such as the current number of bytes transfered being greater than the total number of bytes transfered? I experienced this on Windows 2003, PHP 5.2.5 with Apache 2. The problem isn’t consistent but does happen randomly. Usually when multiple uploads by different people are taking place.

  35. I have similar problem as Paul had. The one that tests with multiple simultaneous file uploads through multiple iframe pipes or even in multiple browsers results in apc neglecting the first-created upload variable.

    Can someone help me? Please.

  36. Hi there.

    Finally the upload hooks will be available using session variable.

    This is now submitted to head for the PHP 6.
    The guy working on it says he will try submit to 5.3 as well in not to long time.

    So, in a short while (hopefully) we can start using the upload hooks without the need for APC, PECL or whatever….

    Just a plain php installation…

  37. Pingback: Upload | hilpers
  38. Hi All,

    I am using wamp server on my local:
    I followed steps as below:
    1.C:\wamp\bin\php\php5.2.8\ext\php_apc.dll

    In php.ini file
    1.extension=php_apc.dll
    2.apc.rfc1867 = on

    and I restarted wamp server
    I tried to upload file
    but unfortunately I am getting error
    Fatal error: Call to undefined function apc_fetch() in C:\wamp\www\UploadProgress\uploadProgress.php on line 3

    Please help it’s urgent.

    Thanks & Regards

    Yogesh

  39. @Yogesh
    It looks that you don’t have apc installed.

    Old link in my article doesn’t work anymore but you can downlod it from link Tom provided.

  40. Doesn’t work, tried uploading a 500 MB file and it said completed within 3 seconds. I know my upstream isn’t more than 48KB/s, so there is no way it actually uploaded.

    I am also not going to digg this, because its really no brainer, Upload with progress bar has been around for quite some time, which all they did was refresh the popup window. Now it just a AJAX version of the same.

    Firefox 1.5.0.1.

  41. I have been trying to get this to work, and have exactly the same issue as a few people on here. It works great in IE, but not Firefox3…

    I get the progress meter comeup and then it shows me {blah:1 blah:1} – but the file is uploading. It just doesn’t seem to refresh the parent as it doe sin IE.

    Any ideas would be appreciated..

Comments are closed.