My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Thursday, October 25, 2007

Upload progress bar with PHP5, APC and jQuery

Yesterday I wrote a little tutorial (Italian language, sorry) that explain how to create an info panel while a file is uploaded.

Here You can view final result:


While this is the entire archive with everything You need to test by Yourself my code:
APCQuery

To test them You need PHP 5.2 or greater and APC enabled.
Please verify that rfc is enabled too:
extension=php_apc.dll
apc.rfc1867 = On


If You test them locally please remember to try form using big files (from 40Mb to 200M for fast PCs) changing php.ini upload_max_filesize and post_max_size directives (I suppose 200M is enough).

If someone is interested about an English version of tutorial I'll try to find time to translate them.

36 comments:

marc.lang said...

Great work dude, just a small question: In my case, index.html is a php-file with some custom content which should be forwarded to upload.php. There are some routines which I have to keep. This wont work if the page stays at index.php.

Is it possible to "really" go to upload.php with all the data from index (instead of let the index-page open and load upload.php in the background)?

Andrea Giammarchi said...

marc if You try to upload one file without Ajax You can see that the page, in your case upload.php, will be visible only when upload has been finished (I didn't try forcing flush and manageing upload after first one, the page) so You could change JavaScript function and redirect user at upload finished using a different redirect page on action url for JS disabled browsers too.

marc.lang said...

well thats what I've tried, altering the Javascript but I didn't find the correct lines so far. Could you tell me what I have to alter, which lines I have to change so the upload bar is still visible and workin?

Andrea Giammarchi said...

uhm ... it seems You need n English version of my tutorial? I hope I'll find time to write them soon :-)

marc.lang said...

Well, I've been workin on this for quite some time now and I'm really tryin to get this finished soon. I've already read your tutorial (translated by google) but I didnt find the part which would solve my problem but I have to admit that I'm not that experienced with Java yet. What I've done so far is to change this one:
"form name="fileupload" enctype="multipart/form-data" action="APCQuery.class.php?redirect=upload.php" method="POST"
Now the redirect is set but you won't get redirected if Java is enabled right? What I would like is to redirect in any case, even if java is enabled :/

Andrea Giammarchi said...

Marc ... anyone talked about Java, We're talking about JavaScript so I suppose You're not so skilled with this language ...

However this was a tutorial, not a perfect/portable library and You need to change both client and server code to adapt them correctly.

For example:
APCQuery.class.php?redirect=upload.php
should be changed into
APCQuery.class.php?redirect=upload.php&nojavascript=page2.php
and at this point You could manage form action to change behaviour (both client and server code) with compatible/not compatible browsers.

marc.lang said...

Idd, thats what I've said before, I'm not that familiar with JS. However I think you got me on the wrong foot. What I was tryin to explain was the following:

- Javascript enabled = stay on index.html, upload bar shown

- Javascript disabled = redirect to the page I want, no upload bar shown

What would be the best:
-JS enabled/disabled = upload bar shown AND redirect

Andrea Giammarchi said...

marc ... again, if You don't have JavaScript You'll never see next page before You haven't send entire file.

So, without JavaScript You'll wait the end of uploaded file and only after them You'll see next page.

Do You need this is different? Change header("Location: "); redirect for disabled browsers.

Do You need to view them before upload is not completed or instantly when user click on upload button? No way man! ... and this is PHP ... not my tutorial problem ...

marc.lang said...

Hm, I fully understand and know that but this was never my point.

EVERYONE who visits my upload-page has javascript ENABLED. Your progress bar works fine, status and so on is just perfect.

All I wanted to do is to redirect the user AFTER the upload is complete (with js enabled).

So my question was, how do I redirect the user after he has uploaded a file when Javascript is ON? Because I only get redirected when I turn JS off.

Andrea Giammarchi said...

Ok marc, I didn't probably understand You.

To redirect JS enabled browsers Yous hould add them inside onload function, exactely after this line

apcquery.css("visibility", "hidden");

You should put your redirect:
location.href = "pageAfterUpload.html";

marc.lang said...

Perfect dude, thats exactly what I was looking for. Thanks, that one made my day. Now I'll have a look how to send the var's from index.php to upload.php but I think I will get that sooner or later. Thanks again mate. Great!

עידו said...

Hi
you have an syntax error.
its working fine with your example of the demo but whene im using it in drupla its does not fined the file input in the form.
filter("[type=file]") when you need to do filter("[@type=file")

i hope i helped someone...

Andrea Giammarchi said...

Oops, thank You :-)

Labanux said...

I've download APCQuery, and installed it on my local server.

But it didn't work as it should..

I browse the file, then click the upload button. Then the upload progress showed up. But the upload progress information never updated.

It just show Total, sent, and rate : 0 bytes. Meanwhile the progress bar never showed up.

And afther clicked the upload button, the upload button itself disabled forever..

Any suggestion?

NB: I've installed APC, and it works. Cause i've tried using other uploader script, and it works well.

Andrea Giammarchi said...

labanux You should tell me wich version of PHP You have in your server.

My example simply works for everyone but not for You so I think the problem should be the PHP version or your specific configuration, isn't it?

Labanux said...

As I said before, i've tried other Ajax Uploader with APC - script. And it works well..

These are software version that I use : Apache/2.2.4 (Unix) DAV/2 mod_ssl/2.2.4 OpenSSL/0.9.8d PHP/5.2.1 mod_apreq2-20051231/2.5.7 mod_perl/2.0.2 Perl/v5.8.7

The APC version is 3.0.15

*I'm using Debian Linux, btw..

Should I made any changes to your script before I can use it?

NB: The script that I use is located here http://progphp.com/progress.php (if i'm not wrong it was made by Rasmus itself).

Any clue?

thuyetti said...

Hello and thank you very much for this tutorial, it works perfectly for me. But for now i'd like to pass the value of an input field (text input) from the upload form page to the upload.php. Àny idea ?

Anonymous said...

Italian language, sorry...

SORRY?!?!?! What do u mean... Sorry...

:-(

Davide

Anonymous said...

I've been searching for around an hour looking for a nice PHP/JavaScript solution that shows your upload progress, then I stumbled upon your site... Very well done! I think if you commented your code a little more, it may help people who need to alter the standard mechanism of the code.

I may need some more help when I implement this into a site I'm working on, but again - you've done a good job!

Anonymous said...

I've found a particularly problematic line of code in the APCQuery.class.php file. I was getting the same problem as labanux, where nothing was showing up in the Upload section, and the upload didn't do anything.

On line 45 of APCQuery.class.php, you have:

if($_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF'] === str_replace('\\', '/', __FILE__)){

I found that my Windows server's DOCUMENT_ROOT variable was different - it had '\' characters instead of '/', which was making the 'if' statement fail, and therefore do nothing! I replaced mine to this:

if(str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF']) === str_replace('\\', '/', __FILE__)){

I think this might even be safe to remove (or replaced with another check).

This took me literally hours to find, so I hope this helps!

Andrea Giammarchi said...

Cheers! To be honest, I did not think about that kind of different configuration ... and I cannot understand the reason but anyway, your solution is really welcome ;)

Kind Regards

Spyer said...

Hey,, i've got to say, you wrote one hell of a script.. very nice..

but i'm having this problem.. i'm not so good in Java.. so your help is highly appreciated :)

//-------------->
Webpage Script Errors

User Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0;)
Timestamp: Sat, 22 Mar 2008 18:46:17 UTC

0.
Message: 'length' is null or not an object
Line: 85
Char: 3
Code: 0
URI: http://localhost/upss/

Apache/2.2.6 (Win32) DAV/2 mod_ssl/2.2.6 OpenSSL/0.9.8g mod_autoindex_color PHP/5.2.5
//<----------

Help please

Lorenzo said...

Your code looks nice, without testing anything yet. However, I'm not familiar with APC but as far as I can see you are only using it to once? apc_fetch() from the class file. Now I was wondering, to avoid the hassle of installing APC, wouldn't it work fine by saving the id in session $_SESSION?

Thanks.

Anonymous said...

I've been using this script for several months now, with great success. THANKS SO MUCH FOR IT! Now I'm trying to move my scripts over to a new machine, and I'm having the same problem Labenux is having. When the upload button is pressed, the upload button grays out, the progress bar box is displayed, but everything remains 0, no file is uploaded, and the page stops loading ("done").

It still works great on my old machine:
- Ubuntu 7.10 box, Apache/2.2.3 (Ubuntu) mod_python/3.2.10 Python/2.5.1 PHP/5.2.1 mod_ruby/1.2.6 Ruby/1.8.5(2006-08-25) mod_perl/2.0.2 Perl/v5.8.8

My new machine is running:
- Ubuntu 8.04, Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.1 with Suhosin-Patch mod_ruby/1.2.6 Ruby/1.8.6(2007-09-24) mod_ssl/2.2.8 OpenSSL/0.9.8g

I've been working on this for more than a day now, and I can't readily find the difference, besides the newer versions. I have exhaustively compared the php.ini and apache2.conf files. Between the two servers, they are practically identical (a few comments differ. :/)

Any thoughts?
- Thanks!

laschmoove said...

Hi Andrea, thank your for your excellent script. I hope I may ask you for another advice: I need to write some data to a database after uploading the file, but since the upload.php is called internally it does not allow me to echo a message in case of success or failure. How would you handle that problem? Thanks, B.

huglester said...

Hello. and thanks for such nice tools.
But in my environment it doesn't work, I see get requests like:
GET http://aaa.com/APCQuery/APCQuery.class.php?APC_PK[]=1.7955122241208508 (31ms)jquery-1.2.1.js (line 2387)
GET http://aaa.com/APCQuery/APCQuery.class.php?APC_PK[]=1.7955122241208508 (16ms)jquery-1.2.1.js (line 2387)
GET http://aaa.com/APCQuery/APCQuery.class.php?APC_PK[]=1.7955122241208508 (31ms)jquery-1.2.1.js (line 2387)
GET

it seems like file is beeing uploaded, but lastly I get:

data has no properties
[Break on this error] while(i < data.length){

(those debuggin messages i got from Firebug)

apc.php shows that APC is running, and apc.rfc1867 is On .
I think the system can't handle tha ppaths. Because even while uploading , I can't find temporary files in php temp directory... strange

thanks in advance

huglester@gmail.com said...

heya.
anonymous with Ubuntu 8.04 , have you found the sollution?

I tried to recompile php without SUHOSINS patch - same problem as without removing it.

I see GET queries like:
http://192.168.1.107/apc/APCQuery.class.php?APC_PK[]=1.7168347417735283

seems the file is being uploaded.
I tried to find where it places temp files, even while uplaoding I can't see temporary file.
Could anyone try to help me, finding it ?

and later, after file is uplaoded, i see this error:

data has no properties
[Break on this error] while(i < data.length){

anyone could be of any help?

huglester said...

After my tests, it seems:

this progress bar cannot work with:
suhosin's patch.

and if php works as fastcgi - it cannot work too.

So if you are under (ubuntu 8.04) where php comes with suhosin already - you must rebuild witout suhosin.

I can help you with that. just email me at
huglester@gmail.com

good luck!

Joao Pedro said...

the progress bar is not working fine for me ...
i have apc extension installed and correct discribed on phpinfo.
can someone help me ?
thanks.

mariuz said...

I have tested and indeed it doesn't work
with jaunty and that patch suhosin

Be a Javascript RockStar said...

awesome!

Arnold Roa said...

There is some error with the code in windows.

$_SERVER['DOCUMENT_ROOT'] = c:/test/
$_SERVER['PHP_SELF'] = /admin/bla.php

you concatenates the 2 vars:
c:/test//admin/bla.php
and compares to ___file___:
c:/test/admin/bla.php

you see the double //?

the correction is:

if(str_replace('//', '/', $_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF']) === str_replace('\\', '/', __FILE__)){

Guenter said...

The var DOCUMENT_ROOT is not usable since the files can reside in an aliased directory. If you only want to check if PHP_SELF points to same file as __FILE__ then its probably enough to lookup the string PHP_SELF in the string __FILE__, f.e. something like that:
if(strpos(str_replace('\\', '/', __FILE__), $_SERVER['PHP_SELF']) !== FALSE){

Pandora said...

getcwd() . DIRECTORY_SEPARATOR

Rakesh said...

In my server apc_fetch() return data once file fully uploaded in the server.
It returns false when file is getting uploaded so I am unable to show progress bar.
Please help.

Andrea Giammarchi said...

This post is from: Thursday, October 25, 2007

No, sorry, I won't help ... find something that works out of the box or suggest changes to update this post and I will.

Sometimes contributing is better than demanding ;-)

Thanks for understanding (I also happily stopped using PHP a while ago)