Script Perfect

         Random snips of code and bugs

PHP File Upload Progress (APC Fetch PECL)

Posted by Tim On September - 4 - 2009

You would think that tracking file upload progress would be a given now, from your browser you can create websites, edit pictures and communicate with millions of people. Only a few sites will actually show you your upload progress and they are few and far between. If anything they will show you a nice animated gif that gives you the illusion your file is being transferred.

It is very possible to track upload progress but I have some bad news for some of you. If you are hosted on a shared server like Hostmonster, BlueHost, etc… then odds are you will not have the right privileges to install the required modules. For those of you that have access to your own server or the capability to get it installed then read on.


You can download the full source for this by clicking here. But I strongly recommend you read this!

Installing APC

First we need to install APC created by PECL. Unfortunately there is no longer support for this on windows based machines but you can still find the dll floating around the internet if you look hard enough. If you do get the dll and you want to use it with WAMP or any other type of local setup simply place it in your php folder with the rest of the dll’s under the “ext” folder. If you are installing remotely like on a server you can use the “wget” function to grab the files and the “gzip” command to extract. There are plenty of resources which can show you how to install, I will show you how to set it up and use it.

Windows Users: If the dll you find does not work try a different version, I had to try 3 different ones to get it to work on my local box.

Once you have the package or dll installed in your machine you will need to edit your php.ini file to configure some settings on apc. Search your php.ini file for “extensions” and you should be presented with a list of them, you need to add the following line:

//WINDOWS USERS:
extension=php_apc.dll
//CentOS or similar
extension = “apc.so”

This will activate the file in windows or on your server. Next you will need to instruct APC to monitor file uploads by adding the following line to the php.ini:

apc.rfc1867 = On

RFC 1867 is a document that describes how HTTP file uploads work for those of you that are curious. The final step in setting up APC is simply restarting your server.

Monitoring File Uploads With APC…The Code

So here is the thing, we actually need to use a combination of things to make this work correctly. First we need to set up our form and a unique key that can be used to track the file progress. We also need a few JavaScript / Ajax functions which will allow us to track the upload without refreshing the page. Finally we need a php function which will report the progress back to us so we can display it on the page. Below is an overview of how it will all work.
I will explain this step by step:

Step 1: We post our form with the file we are uploading, the data is collected by our JavaScript functions and we remain on the same page.

Step 2: The JavaScript will post all of the data to the php upload file and start our php progress indication.

Step 3: We use a JavaScript function to pull the upload progress from our php progress file, the progress is being tracked based on the file being uploaded in our php upload file.

Step 4: We update the files status in our progress area on the webpage.

Creating Our Form and  a Key to Track Progress:

At the top of the page where our form resides we will need to generate a random string of characters which will be used by the APC function to track the files progress. We will need to include that value in our form, your form should look like the following:

<?php $uniqueID = md5(uniqid(rand())); ?>
<form name="upload" onsubmit="javascript:uploadFile();" action="upload.php" target="upload_target" method="post" id="ajax_upload" enctype="multipart/form-data">
        <input type="file" name="myfile" id="myfile"/><br />
        <input type="hidden" name="APC_UPLOAD_PROGRESS" id="progress_key" value="<?php echo $uniqueID; ?>" />
<input type="submit" value="Upload" />
</form>
<div id="progress"></div>

<iframe id="upload_target" name="upload_target" style="width:0;height:0;border:0px solid #fff;"></iframe>

There is our basic form, it is very important to leave the name of the apc input the way it is. Notice there is a DIV with the id of “progress”, this is the area we will display the upload progress. We are also including a hidden iframe so that the form will post there and not refresh the page. Also take note of the function call in the form tag, the onsubmit calls our JavaScript function to track the upload, we will write this later.

Now lets set up some of the JavaScript and Ajax. In order for us to tell if something is being posted back to us from any of our scripts we must listen for them. We have two different types of listeners here, one for IE and another for most other browsers.

Listener

var HttpListener = false;
if(window.XMLHttpRequest) {
        HttpListener = new XMLHttpRequest();
}
else if(window.ActiveXObject) {
        HttpListener = new ActiveXObject("Microsoft.XMLHTTP");
}

We will use the above listener in our progress function.

Progress Function

function Progress(uniqueID) {
   if(HttpListener) {
      HttpListener.open(‘GET’, ‘get_progress.php?uniqueID=’ + uniqueID, true);
      HttpListener.onreadystatechange = function() {
         if(HttpListener.readyState == 4 && HttpListener.status == 200) {
            var response = HttpListener.responseText;
                        if (isNaN(response)){response=1; }
            document.getElementById(‘progress’).innerHTML = Math.round(response) + "%";
            if(response < 100) {
               setTimeout(‘getProgress(’+"’"+uniqueID+"’"+‘)’, 100);
            }
            else {
                       document.getElementById(‘progress’).innerHTML = "100% – Upload Complete!";
            }
         }
      }
      HttpListener.send(null);
   }
}

What the above function does is send the uniqueID that we generated in the form to a file called get_progress.php(which we will write in a sec.) and listens for a response. When we receive a response from that file we update the results in our DIV progress back on our main page. You also see the “setTimeout” function, this calls the function over and over again which essentially posts to get_progress again and again thus updating our progress.

In order for this all to work we need one last piece of JavaScript, the actual function that sets the ball in motion:

function uploadFile(){
        var uniqueID = document.getElementById(‘progress_key’).value;
        setTimeout(‘Progress("’ + uniqueID + ‘")’, 500);
}

This function grabs the uniqueID from the hidden input on the page and passes the value to our Progress function after half a second.

Progress:
The get_progress.php file mentioned above is very simple, here it is:

header(‘Expires: Mon, 26 Jul 1997 05:00:00 GMT’);
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header(‘Cache-Control: no-store, no-cache, must-revalidate’);
header(‘Cache-Control: post-check=0, pre-check=0′, FALSE);
header(‘Pragma: no-cache’);
if(isset($_GET[‘uniqueID’])){
   $progress = apc_fetch(‘upload_’ . $_GET[‘uniqueID’]);
   echo round($progress[‘current’]/$progress[‘total’]*100);
}

The get_progress.php file simply takes the uniqueID and calls the apc_fetch function which reports back an array of data about the file it is tracking. We are using “current” and “total” to come up with our percentage. The first four lines of this is to prevent some browsers from caching the original request, we force those to update each time this is called, otherwise the bar would appear frozen.

Last but not least, you need an upload.php script which will actually handle the file transfer, three lines and you are done:

$filepath = "uploads/";
$filepath = $filepath . basename( $_FILES[‘myfile’][‘name’]);
move_uploaded_file($_FILES[‘myfile’][‘tmp_name’], $filepath);

And that is it. When you break this code into sections and actually read how it all works, life becomes easy and this project becomes simple.

A note for those of you looking for a progress bar, the response sent from our get_progress.php is simply a number from 1 to 100. So you could take that number to create a very simple upload bar by creating a container DIV set to a width of 100px and place another container inside of that one set to an initial width of 0. You will need the internal div color to be set to whatever color you would like your bar and use JavaScript to update the inner div width based on the response.

For a progress bar on another site I used an animated gif as the background of my outer DIV and overlaid it with a transparent gif of the same dimensions for a really nice effect.

You can download the full source for this by clicking here. But I strongly recommend you read this entire article!
Good luck and have fun with this one.

One Response to “PHP File Upload Progress (APC Fetch PECL)”

  1. karthika says:

    You are saying your an independent web developer so can you support me in php coding. If possible.

Leave a Reply

Spam protection by WP Captcha-Free

About Me

I am an independent web developer and webmaster of many sites. The main goal of Script Perfect is to provide answers to some of the hard to find questions when it comes to website design and coding.

Twitter