View Full Version : upload progress

05-15-2010, 04:09 AM
I may add to this post later as issues arise, but is there a way to use PHP or a simple bit of javascript to maybe refresh the page every 5 seconds to display how much of a file has been uploaded or what percentage of the file has been uploaded?

I am looking to modify an existing script as opposed to installing one that has already been created like uber_uploader.

Another question. Let's say I have a basic upload program and have not placed any limits on it. Are there defaults to how much large of a file I can upload? For example, if I use fireftp I am reasonably sure I can upload a 100MB file, but would I be able to do the same with php or are there default limits built in that would need to be altered with php.ini to modify the upload limits? It appears that there are size limits even though I have not set any.

05-15-2010, 04:48 AM
The answer to the upload file size limit has been found. There are some default values in the php5.ini or php.ini depending on what you use.

upload_max_filesize=50M default is 2M
post_max_size=50M default is 8M

If these values are not stated then the default values are implied.

05-15-2010, 05:35 AM
I believe that the limits are just the defaults and you can change them if you like. There is no inherent limit on how large a file you can upload, but from experience working with video files (I've uploaded 1GB files fairly often), you absolutely do not want to have it over an http connection. The main reason is that you cannot restart the upload if it dies, and over that much time even on a strong connection it's likely that something will go wrong enough of the time (1/3? at best...) that you'd want to avoid it.

Note that also PHP does not reject a file until it's completely sent: if the user waits for a 50mb file to upload then finds out there's a 2mb limit, they'll be upset.

There are ways around this: use java, flash or other programs that can actually handle this kind of thing and work around it.

But for most uses (that is-- not video, huge audio files or really big uncompressed images, and no archives/programs), you'll be fine and rarely go over 5mb.

As for tracking an upload in progress, that's extremely difficult.
Even without the limits of Ajax/JS/PHP it is hard. And that's why computer time is never real time in the progress bar: 2 hours to go, 30 seconds to go, 4 days to go, and then at some point it actually finishes, unrelated to the computer's guess.

The basic method is to constantly call back to the server to find out how much of the file is there. It's possible and not that hard, but hard to keep stable.
But that's for a real programming language on a real connection.

Using Ajax to track PHP from a current upload is all but impossible: you need to find where the temporary file is being stored, SOMEHOW identify which one is actually your file (it seems like the newest one should be, but what about many users at the same time), and then also compare this to the full filesize-- how do you get that? Maybe in JS?

Using ActiveX, Flash, Java applets, etc., you may be able to get more info. With basic Ajax and PHP, you're going to have lots of trouble.

If you can just use an existing script and not use your own code, it's a much simpler process.

05-15-2010, 05:43 AM
The basic method is to constantly call back to the server to find out how much of the file is there.
This is really all I want to do.

But that's for a real programming language on a real connection.
Are you talking about C++?

05-15-2010, 05:58 AM
I'm talking about anything that actually has access to both the user's computer and the server at the same time, not a fake system of Ajax and calls to PHP.

For example, I never finished the project (no need, just testing), but I created something like this in PHP. The difference is that the uploads weren't through HTTP, but through the FTP functions within PHP (php sending to another server) AND the php was executing as an .exe on my computer, not as a hidden process on the server.

The issue isn't the language, but it's security/access limitations.

In theory you could program a space ship in Javascript, but good luck actually getting that to work from a webpage. And here it's practically that hard-- you don't really have access to what's going on for the server.

You *CAN* try to get the temporary filename by pinging the server after the upload starts and you can try to compare that to expected progress, etc., but it's really very complex.

To put it in perspective, it would take a very serious programmer who knows a lot about server configurations and how PHP works at a fundamental level to be able to really do this well.

It's probably possible to throw something together that will approximate it, but it'll be very hard.

I wouldn't bother attempting this myself-- I don't think I'd be able to do something very accurate.

It's a tempting idea, of course, and an interesting puzzle, but that's as far as I've ever gotten with it.

The main place where this all gets messy is that when you start uploading a file NOTHING happens except that it's dumped temporarily somewhere on the server. You can find that place (it's based on how the server/php are configured), but to figure out which file it is and what it's doing is incredibly hard. Then to loop through Ajax and get the server to tell you what's going on with the file will only get you a rough idea of the progress, etc.

You might want to look into uploading the file through Javascript. I have no idea if that's actually possible (that's why even gmail implements flash in this case), but if you could do an ajax upload that might give you permission to see the progress.

In theory this is very easy to do-- the number must exist somewhere. But in practice the format of JS vs. PHP (among other things) makes it nearly impossible.

05-15-2010, 07:25 AM
certainly more involved than I was initially thinking.

You mentioned that there were a few alternatives. What would you recommend as far as a simple or minimalistic upload program for a website; flash, java or whatnot. My initial requirements are certainly not fixed. In fact I notice that the Opera browser already does this with its built in "speed" and "total" meters.

This is all for my own personal use and not for the general public.

05-15-2010, 07:44 AM
Then I'd say use Opera :)

I don't have any good suggestions.

If you're doing this as a fun experiment to see what you can figure out, good luck.

If you're doing this for a practical application, you're probably just better off finding an existing script.

A java applet will have the most access (and also be the most awkward in a few ways, like crashing some computers-- they are definitely not 'smooth').

Apparently flash can do it as well, though I don't know the details.

The choice I guess depends on your ability/interest to learn those two options. Flash is probably easier but Java would be more powerful.... tradeoff.

For just "simple" if you're willing to skip all of this, then you can easily do it with PHP alone (and some JS if you want).

If you must have a progress bar, it's going to be very difficult.

The easiest way is to look at an existing script and see how that works, or just use the script.

Here's a case where re-inventing the wheel probably won't help you.

05-15-2010, 04:43 PM
Now, I don't have any real code to back my theory up but I see it as this.
Have this progress bar:http://www.dynamicdrive.com/dynamicindex11/dhtmlprogress3.htm in an iframe on the page that your uploading and set a meta tag to auto refresh every 5 seconds or so. Have the PHP get the file size of the temporary file size and divide by the total file size, then multiply the answer by 100:

$amount_uploaded = filesize($uploadedfile['name']);
$decimal_uploaded = $amount_uploaded/$uploadedfile['size'];
$percent = $decimal_uploaded*100;

something like that (please fix my code if necessary).
That's the percent done, then just send the percent done to the progress bar:

setCount(<?php echo $percent; ?>);

... that refeshes every 5 seconds or whatever.

05-15-2010, 06:36 PM
Have the PHP get the file size of the temporary file sizeEverything about what you've said is fine. BUT-- how would you accomplish that one "simple" bit? You can figure out where the temporary files are stored, but if multiple uploads are occurring around the same time, then how would you figure out which one is yours? If you can manage that then it is possible. But I've casually looked into it and from what I can tell it gets a random name and there's no way to associate it with anything aside from *maybe* the file creation time and the submission of the script, but even that is just a guess.

I'd actually be more than willing to try to help figure this out, but I'm hesitant because I really don't see a way to make it work well just in having to find which temporary file is correct.

05-15-2010, 07:52 PM
Use Flash and PHP. Since this is for only personal use you can use the tutorial with explanation found here (http://markshu.ca/imm/flash/tutorial/fileReference.html)

05-15-2010, 09:23 PM
djr33, I am pretty sure you can just use $_FILES['file']['tmp_name']; or somthing like that, pass it trhough a get statement or set a session variable and its done. As for the flash, im not sure the OP is up to it but...

05-15-2010, 09:31 PM
I don't believe that's possible: the page is still loading so you can't use PHP yet. The problem here is that you are uploading blind and don't know where the file is going until it's done uploading.

If you can find a way around this, let me know.

I may look into this myself... it would be nice.

Flash is certainly complex/hard, but it's the right way to go to have full control, I think.

05-15-2010, 10:24 PM
I dont think you understand the whole idea, or maybe I just wasnt clear.... The submit/uplouad form would appear on page upload.php with an action of upload_submit.php. On that page the php will actually upload the file. It will also set $_FILES['file']['tmp_name'] to say $_SESSION['tmp_name']. In an iframe on that page is upload_progress.php with a query string set by php like
<iframe ... src="upload_progress.php?file=<?php echo $_SESSION['tmp_name']; ?>"> and then on upload_progress.php, it will recive the filename and then just filesize(); that name, then do all the computations on my previous post....

05-15-2010, 10:33 PM
I understand, but the timing still seems uncertain:
upload_submit.php would not load until the browser has finished sending the upload.

I wasn't aware you could specify the temporary file's name like that. It could get you around the naming issue, though, perhaps.

But even if this all works, how do you know the file's size? You could show a display of the progress counting up, but you wouldn't know the percent without knowing the file's whole size.

05-15-2010, 10:59 PM
I set up a test page and used the minimal form for an upload.

On the receiving page I had at the top just print_r($_FILES); die();

The result was this:
Array ( [userfile] => Array ( [name] => test.mp3 [type] => audio/mpeg [tmp_name] => /tmp/phpqEJth3 [error] => 0 [size] => 301369 ) )

And it only worked AFTER the upload was completed by the browser.

I'm almost positive that the browser's request is only sent after the upload is completed, or rather that it's probably part of the request so the PHP script doesn't do anything at all until the data is uploaded.

I can't find specific info on php.net for this though.

05-16-2010, 12:35 AM
This is getting more complex then I thought. If the action of the upload form is GET, (idk if you can with file uploads) there could be a page inbetween that iframes the processing page that through javascript would change another iframe the main window to a query of the tmp_name and ughhhhh this is getting too complecated. maybe you can just find a script online that does this. Or go with flash

05-16-2010, 01:08 AM
PHP only supports POST.

Your logic isn't wrong-- we just don't have access to those crucial bits of information.

One other thing to theoretically look into is that PHP also supports the "PUT" method of file uploads. I have no idea what that means (it looks like a command line thing), but php.net has documentation if that helps...

I'm not sure it's any more useful, but it could be...

05-16-2010, 01:21 AM
After some googling: http://progphp.com/progress.php and the php source:

$status = apc_fetch('upload_'.$_POST['APC_UPLOAD_PROGRESS']);
echo json_encode($status);
} else if(isset($_GET['progress_key'])) {
$status = apc_fetch('upload_'.$_GET['progress_key']);
echo json_encode($status);
<script type="text/javascript" src="/yui/yahoo.js"></script>
<script type="text/javascript" src="/yui/event.js"></script>
<script type="text/javascript" src="/yui/dom.js"></script>
<script type="text/javascript" src="/yui/animation.js"></script>
<script type="text/javascript" src="/yui/dragdrop.js"></script>
<script type="text/javascript" src="/yui/connection.js"></script>
<script type="text/javascript" src="/yui/container.js"></script>
<link rel="stylesheet" type="text/css" href="/yui/build/container/assets/container.css" />
<script type="text/javascript">
var fN = function callBack(o) {
var resp = eval('(' + o.responseText + ')');
var rate = parseInt(resp['rate']/1024);
if(resp['cancel_upload']) {
txt="Cancelled after "+resp['current']+" bytes!";
} else {
txt=resp['total']+" bytes uploaded!";
txt += "<br>Upload rate was "+rate+" kbps.";
document.getElementById('pbar').style.width = '100%';
document.getElementById('ppct').innerHTML = "100%";
document.getElementById('ptxt').innerHTML = txt;
setTimeout("progress_win.hide(); window.location.reload(true);",2000);
var callback = { upload:fN }

var fP = function callBack(o) {
var resp = eval('(' + o.responseText + ')');
if(!resp['done']) {
if(resp['total']) {
var pct = parseInt(100*(resp['current']/resp['total']));
document.getElementById('pbar').style.width = ''+pct+'%';
document.getElementById('ppct').innerHTML = " "+pct+"%";
document.getElementById('ptxt').innerHTML = resp['current']+" of "+resp['total']+" bytes";
} else if(resp['cancel_upload']) {
txt="Cancelled after "+resp['current']+" bytes!";
document.getElementById('ptxt').innerHTML = txt;
setTimeout("progress_win.hide(); window.location.reload(true);",2000);
var progress_callback = { success:fP }

function update_progress() {
progress_key = document.getElementById('progress_key').value;
YAHOO.util.Connect.asyncRequest('GET','progress.php?progress_key='+progress_key, progress_callback);

var progress_win;

function postForm(target,formName) {
/* Is there some event that triggers on an aborted file upload? */
/* YAHOO.util.Event.addListener(window, "abort", function () { alert('abort') } ); */
progress_win = new YAHOO.widget.Panel("progress_win", { width:"420px", fixedcenter:false, underlay:"shadow", close:false, draggable:true, modal:true, effect:{effect:YAHOO.widget.ContainerEffect.FADE, duration:0.3} } );
progress_win.setHeader("Uploading "+document.getElementById('test_file').value+" ...");
progress_win.setBody('<div style="height: 1em; width: 400px; border:1px solid #000;"> <div id="pbar" style="background: #99e; height: 98%; width:0%; float:left;">&nbsp;</div> <div id="ppct" style="height: 90%; position: absolute; margin: 1 0 0 185;">0%</div></div><div id="ptxt" style="margin: 3 0 0 5">0 of 0 bytes</div>');
<form enctype="multipart/form-data" id="upload_form" action="" onsubmit="postForm('progress.php','upload_form'); return false;" method="POST">
<input type="hidden" name="APC_UPLOAD_PROGRESS" id="progress_key" value="<?php echo uniqid()?>"/>
<input type="file" id="test_file" name="test_file"/><br/>
<input type="submit" value="Upload!"/>
<div id="progress_win">
<div class="hd" style="color: #222; background: #bbb"></div>
<div class="bd"></div>
<div class="ft"></div>

It looks like it uses somthing called APC: http://us.php.net/apc

05-16-2010, 02:12 AM
APC (http://www.php.net/manual/en/extensions.alphabetical.php) is one of those extensions for PHP, which on my shared account is not available. Another extension for PHP is called uploadprogress http://pecl.php.net/package/uploadprogress, but I do not have access to that one either. Perhaps if I upgrade to a premium account I could install PHP extensions on my site.

Either way it looks like if I want to pursue this I will need to upgrade my GoDaddy account.

05-17-2010, 08:48 AM
This might be another option: http://devpro.it/upload_progress/
(There's a zip demo to download, with instruction file - dont forget to set the tmp folder value in "whileuploading.php" )

Here's an online demo of it: http://jemthingsandstuff.co.uk/testing/upload_progress/index.php
(8MB max file size)

05-17-2010, 02:49 PM
Unfortunately, that script does not show a percentage done, just how much of the file has been uploaded, But I guess that's the best you can do without php extensions. Is there anyway to know the file size of a file BEFORE it's done uploading? Because I'm pretty sure there is; I have seen sites that say before you upload it that it is not the right file size or such, (Maybe even uploading to the forums here, I forget). The key is to access $_FILES while it's uploading...
Here's a W3 page that uses file restrictions, and it uses $_FILES, but Only after it's uploaded: http://www.w3schools.com/PHP/php_file_upload.asp
What if the action of a forum was to a page with an iframe in which had php code that read $_FILES. Or maybe because it wasn't the action, $_FILES would be null.... Hmmmm

05-17-2010, 03:41 PM
The request is not sent until the file is up. I still see no way.