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.

6 Responses 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.

  2. Luke says:

    Hi,

    Thanks for the detailed explanation, it was very helpful. None the less I have a problem I hope the can help me with. When uploading a file my percentage is not being updated and sits on 0%. I am using a debian webserver which i have setup locally and have checked the following:

    php.ini contains apc.rfc1867 = On and extension = “apc.so”

    apc.so – is in the correct location set in the php.ini

    increased apc.max_file_size and upload_max_filesize to 10m

    tested with IE and FireFox

    phpinfo.php – list apc and is enabled

    Two things I have noticed:

    1. The apc build date looks odd. I am running version 3.0.19 with a build date of Nov 27 2009 17:37:19. I checked this against http://pecl.php.net/package/APC where the release date for 3.0.19 is 2008-05-15, odd?

    2. When uploading a file in IE I notice an “error on page” on the status bar.

    Webpage error details

    User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2)
    Timestamp: Sat, 28 Nov 2009 12:08:53 UTC

    Message: Object expected
    Line: 1
    Char: 1
    Code: 0
    URI: http://192.168.1.152/luke/

    Any help with this would be greatly appreciated.

    Thanks,

    Luke

  3. Upcoming Generation Clickjacking…

    To perform the attack, a malicious website will load a page from the website inside an iframe, using CSS to hide all except the targeted region of the page….

  4. Anti Aging Skin Care Products – Can They Make You Look Younger …

    proviso you are comparable a assortment of women greater than 30, you are perhaps preliminary headed for unease concerning the dreaded w-word….

  5. Lawn care tips with great solutions | Best tips lawn care programs …

    Whether a residential area or commercial area, a striking lawn can be the difference in terms of aesthetic play. This is a great thing that you can now make ……

  6. free hair growth tips…

    my blog is about free hair growth tips…

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