Tracking Upload Progress with PHP and JavaScript

Tweet

A problem that has plagued web developers for years is how to add real-time information to their applications, such as a progress bar for file uploads. Users are impatient; they don’t want to sit and wait while the browser is doing something and wonder whether it has frozen or if they have a slow connection. Providing a progress indicator gives users useful information and lets them know exactly what’s going on.

At first thought, you might think accomplishing this can be done easily by first obtaining the file’s size from the user’s computer and then performing some simple calculations against the directory on the server where the file is being uploaded to. On second thought, you’d find things aren’t quite that simple.

JavaScript can access a file’s name, type, and even the width and height of a local image, but it wasn’t until HTML5 that it could access a file’s size. Unfortunately, HTML5 still isn’t a completed standard yet and isn’t uniformly supported across all browsers. An alternate solution is to rely on a Flash, Java, or ActiveX plugin; no thanks, I’ll pass. Yet another solution is to install the Alternative PHP Cache extension, but that may not be available depending on your hosting environment and it seems like overkill for such a small task such as this.

It would seem as though all the options are fraught with nuisances and the task has quickly become a headache. But in the words of Yoda, “No… There is another.”

One of the many reasons I love PHP is that it makes seemingly difficult tasks easy. As of PHP 5.4, they’ve done it again with a new set of configuration directives, session.upload_progress.

In this article I’ll show you how this feature can be used to create a simple upload progress bar without any external libraries or browser dependencies. I’ll first discuss how it works, and then I’ll walk you through creating the four files needed to accomplish the task (an upload form, some JavaScript, a little CSS, and a file to return the status of the upload).

Session Upload Progress

Besides the usual requirements to allow file uploads, there are two more to track the progress. The session.upload_progress.enabled directive must be enabled and there must be a hidden field in your web form with the name specified by the session.upload_progress.name directive. When session.upload_progress.enabled is true (as it is by default in PHP 5.4 and presumably beyond) and $_POST[session.upload_progress.name] is sent during an upload, information about the file transfer is made available in the $_SESSION superglobal array.

The print_r() output of the $_SESSION array will look similar to the following during a file transfer:

Array
(
    [upload_progress_myForm] => Array
        (
            [start_time] => 1323733740
            [content_length] => 721127769
            [bytes_processed] => 263178326
            [done] => 
            [files] => Array
                (
                    [0] => Array
                        (
                            [field_name] => userfile
                            [name] => ubuntu-10.04.3-desktop-i386.iso
                            [tmp_name] => 
                            [error] => 0
                            [done] => 
                            [start_time] => 1323733740
                            [bytes_processed] => 263178026
                        )
                )
        )
)

When you are developing either locally or on a fast network and upload small files, you won’t be able to visually observe the progress because the transfer happens so fast. In this case, you might want to try transferring a large file. Make sure the settings in your php.ini file allow large uploads, specifically the post_max_size and upload_max_filesize directives, and then verify they are sane values when you go to production.

Create the Form

The first file I’ll present is the upload form. Just to keep things as simple as possible, the example will post to itself and only handle one file upload at a time. Additionally, I won’t bother saving the file after it has been uploaded.

Here’s the code for form.php:

<?php
if ($_SERVER["REQUEST_METHOD"] == "POST" && !empty($_FILES["userfile"])) {
    // move_uploaded_file()
}
?>
<html>
 <head>
  <title>File Upload Progress Bar</title>
  <link rel="stylesheet" type="text/css" href="style.css">
 </head>
 <body>
  <div id="bar_blank">
   <div id="bar_color"></div>
  </div>
  <div id="status"></div>
  <form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="POST" 
   id="myForm" enctype="multipart/form-data" target="hidden_iframe">
   <input type="hidden" value="myForm"
    name="<?php echo ini_get("session.upload_progress.name"); ?>">
   <input type="file" name="userfile"><br>
   <input type="submit" value="Start Upload">
  </form>
  <iframe id="hidden_iframe" name="hidden_iframe" src="about:blank"></iframe>
  <script type="text/javascript" src="script.js"></script>
 </body>
</html>

In the example the code to actually process the file has been omitted to keep things simple. If you’re interested in what such code should look like, check out the article File Uploads with PHP by Timothy Boronczyk.

After the head section which provides the page’s title and includes the stylesheet, you’ll notice a small collection of div elements. The div with the ID “bar_blank” is the container for the progress bar. The div with the ID “bar_color” will be dynamically updated as the file upload progresses. The “status” div will display the numeric value of the percent uploaded.

The form is set to submit to the same URL and its target attribute points to a hidden iframe element. Submitting a form to a hidden frame allows you to keep the visitor on the same page while the work is being done in the background. In fact, this is a common practice when doing “Ajax file uploads” since it isn’t possible to send the contents of a file directly using JavaScript’s XmlHttpRequest object.

Within the form, the special hidden field needed to populate the $_SESSION array appears, followed by a file upload input and submit button. Submitting the form will trigger a JavaScript function named startUpload() which will be defined by the included JavaScript file.

At the bottom of the page is the hidden frame to which the form will post and the import of the script.js file.

Add Some Style

The next file, style.css, is pretty straight-forward. I’ve defined the size of the progress bar container and given it a 1px black border, the color of the progress bar as it’s loading, and both the iframe and the progress bar are hidden.

#bar_blank {
  border: solid 1px #000;
  height: 20px;
  width: 300px;
}

#bar_color {
  background-color: #006666;
  height: 20px;
  width: 0px;
}

#bar_blank, #hidden_iframe {
  display: none;
}

Client-Side Functionality

The script.js file is the largest of the group of files. It contains six functions which I will discuss below. Many people like to use jQuery to provide some of the functionality here, and you are certainly free to do so if you wish, but I personally prefer the old-school approach. Similar to how the Japanese place a higher value on hand crafted goods, I just feel more passionate about the code if it is my own.

function toggleBarVisibility() {
    var e = document.getElementById("bar_blank");
    e.style.display = (e.style.display == "block") ? "none" : "block";
}

function createRequestObject() {
    var http;
    if (navigator.appName == "Microsoft Internet Explorer") {
        http = new ActiveXObject("Microsoft.XMLHTTP");
    }
    else {
        http = new XMLHttpRequest();
    }
    return http;
}

function sendRequest() {
    var http = createRequestObject();
    http.open("GET", "progress.php");
    http.onreadystatechange = function () { handleResponse(http); };
    http.send(null);
}

function handleResponse(http) {
    var response;
    if (http.readyState == 4) {
        response = http.responseText;
        document.getElementById("bar_color").style.width = response + "%";
        document.getElementById("status").innerHTML = response + "%";

        if (response < 100) {
            setTimeout("sendRequest()", 1000);
        }
        else {
            toggleBarVisibility();
            document.getElementById("status").innerHTML = "Done.";
        }
    }
}

function startUpload() {
    toggleBarVisibility();
    setTimeout("sendRequest()", 1000);
}

(function () {
    document.getElementById("myForm").onsubmit = startUpload;
})();

The toggleBarVisibility() function sets an appropriate style on the “bar_blank” div to show or hide the progress bar as needed. Initially it starts out hidden, but will be displayed once an upload starts and hidden again when an upload finishes.

The createRequestObject() function creates an XMLHttpRequest or ActiveXObject object based on the user’s browser. This is probably the function most people would look to jQuery or some other JavaScript framework to provide.

The sendRequest() function requests the progress.php file with a GET request, and then invokes the handleResponse() function to handle the returned data.

The handleResponse() function handles the response from progress.php which will be a number between 1-100 depending on the file upload progress. I also update the “status” div with the appropriate value. If the current percent is below 100 then I call JavaScript’s native setTimeout() function to send another request for an update after 1 second (you may want to adjust this value as appropriate), otherwise I hide the progress bar again and set the status to “Done.”

The startUpload() function makes the upload bar visible and sends a request for an update after a delay of 1 second. This small delay is needed in order to give the upload time to start.

The final function is a self-executing anonymous function which registers startUpload() with the form’s submit event.

Real-Time Progress

The last file that brings everything together is the progress.php file:

<?php
session_start();

$key = ini_get("session.upload_progress.prefix") . "myForm";
if (!empty($_SESSION[$key])) {
    $current = $_SESSION[$key]["bytes_processed"];
    $total = $_SESSION[$key]["content_length"];
    echo $current < $total ? ceil($current / $total * 100) : 100;
}
else {
    echo 100;
}

The script performs some simple math on the current number of bytes transferred divided by the total file size, multiplied by 100 and rounded off to give a percent.

Information about the transfer is keyed with a concatenation of the session.upload_progress.prefix directive’s value and the hidden session.upload_progress.name field’s value. Because my form passed “myForm”, the session’s key is determined with ini_get("session.upload_progress.prefix") . "myForm".

Here’s a screenshot of the progress bar in action:

upload progress bar

Fine-Tuning the Behavior

PHP provides some additional directives to help fine-tune the behavior of session uploads you should be aware of. For example, session.upload_progress.cleanup, which is set to 1 by default, cleans up the extra session data immediately after the upload has finished. You need to be careful to avoid a potential race condition.

Take a look again at the code in progress.php and you’ll notice that I check to see if $_SESSION[$key] is empty or not before proceeding. My JavaScript functions fire off every second as long as the result returned from progress.php is less than 100. If session.upload_progress.cleanup is enabled and my script fetches 99% of the upload and a 1/2-second later the upload finishes, $_SESSION[$key] would not exist for the next check. If I didn’t take that into consideration then my JavaScript function might keep firing, even after the upload finished.

Another two directives are session.upload_progress.freq and session.upload_progress.min_freq which both determine how often the session should be updated. The value of freq can be given in either bytes (i.e., 100) or the percentage of total bytes (i.e., 2%). The value of min_freq is given in seconds and indicates the minimum number of seconds between updates. Obviously if min_freq was set to update every 1 second, it would be pointless for your JavaScript to check every 100 milliseconds.

Summary

You should now have a solid grasp on how to create a progress bar for file uploads using the session upload progress feature. Moving forward, I encourage you to experiment with uploading multiple files, giving the option to cancel an upload in progress using $_SESSION[$key]["cancel_upload"], or whatever other ideas your mind can muster. Please share in the comments your experiences and improvements you’ve made for others to benefit from and enjoy as well!

Image via file404 / Shutterstock

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Tjorriemorrie

    Even just mentioning increasing post size must go hand-in-hand with a recommendation to extremely limit max_input_vars lest you set them up for hash table attacks.

    • http://www.huskynews.com Husky

      @Tjorriemorrie, please be more specific. I’m not sure I understand your comment. Any explanation will be useful. Thanks.

  • Alex Gervasio

    Great post, Martin. I really enjoyed the clarity in showing how to get a true cross-browser progress bar up and running in a few easy steps. The only small things to compliant about is that the bar has been hardcoded in the markup and the iframe. This isn’t actually a good approach, as the bar doesn’t have a true semantic meaning in the document’s context, and empty tags just don’t look nice. Plus, get rid of the iframe since it’s a hack. Prevent form submissions straight with JS.

    Rather, the bar should be created and dropped in turn with the DOM. You suck the benefits out of Progressive Enhancement, and don’t end up with a couple of useless divs when JavaScript is turned off. There’s an old mantra which I learned myself the hard way: don’t show elements with JS that have been hidden with CSS (and the other way around, of course). So, keep visual presentation and behavior doing what they were meant to be, without overlapping each other. Even though, a juicy, well-structured tutorial.
    Keep them coming along!

    • http://zaemis.blogspot.com Timothy Boronczyk

      I didn’t think it was possible to do a file upload with pure JavaScript until just very recently if the browser supports the File API (thus, not cross-browser). Do you know of a way Alex?

      • Alex Gervasio

        You’re right Tim. AFAIK, still it’s not possible to do cross-browser file uploads using only JavaScript. There’s even an HTML5 Drop & Drop API, which should plug in neatly into the File API. Unfortunately, both are half-backed, and plagued with a bunch of painful, counter-intuitive event handlers.

      • boen_robot

        Well, the iframe and progress bar could’ve been generated with JavaScript, but I guess writing the code for adding them would make the example less than “simple”.

  • http://www.dodesigns.com mike

    How large of a file can this support? For example, say I have a file that is 2G, what is the best way to upload it? Is PHP the best or should I use another language?

    • Jason

      @mike: generally, the language used on the back end isn’t going to be the bottleneck when uploading a large file like that, assuming it’s configured properly. I’ve never tried to upload anything that large through HTTP, but I imagine that PHP would function just fine.

  • http://hydrarulz.com Luca Daniel

    The only problem I have is the code

    That leads to XSS attacks.
    Nice article, will definitely help me in the future

    • http://www.psinas.com Martin Psinas

      What leads to XSS attacks?

  • rudie

    Who doesn’t have APC but does have PHP 5.4 available? Weird…

    Does this session implementation (of what apc does better) create a session? That would be weird… A session and file upload progress should be completely separate IMO.

    I agree about PHP making everything easy though :) Cool.

    • Jason

      Why should they be separate? The idea of a session (regardless of how it’s implemented) is integral to attaching the file upload progress to the client that uploaded it. The alternative is for a single upload request to return multiple progress responses, which isn’t HTTP.

      APCs method for this is identical, except that it uses a runtime generated unique id to mimic a session for the request and track file progress rather than use PHP Sessions. I assume your main complaint is that you don’t want to use PHP Sessions at all?

  • rudahindwa

    Hello,
    I’m new to the world of PHP, and I found your code very interresting, but the last file progress.php which is most important, I do not see anywhere where it operates, can you tell me how integrate for this code to work?

  • rudahindwa

    I do not see the status div also in .css file. Why?

  • http://adeveloper.org Hossein Baghayi

    @rudahindwa have a look at the javascript file for more info about how the progress.php file is used in the sample.

    And also status div is manipulated using the javascript

  • paul

    a nice little tutorial, thanks for that. now i just have to wait for 5.4 to be finished.

  • Vish

    Nice article but i am not able to upload and view the $_SESSION[$key] value while uploading . infact in progress.php, program does not recognize the $_SESSION[$key] variable and always go to the else loop.
    I have upgraded my PHP 5.3 to 5.4 but nothing happend.
    Can anybody tell me what wrong i am doing. Any help is appreciated.

    • Jason

      I’m assuming that you’ve basically copied the code completely from the examples above (i.e. you’ve included the “session_start()” call)? Are sessions working in general? You’ve set all of the appropriate settings in php.ini?

      • Vish

        Yes i have copied the complete code from above example but i have initialized session in both script i.e. in progress_bar.php & porgress.php . now when i register my name in session variable i.e. $_SESSION['user']=’vish’, i can get these values while printing SESSION variables in progress.php but i can not get the $_SESSION['upload_progress_myform'] values in this script. Now i am not getting where to register these value in progress_bar.php script . will it be automatically invoked by the script as i have configrued every thing right in php.ini here is my php.ini setting
        max_execution_time 30 30
        max_file_uploads 20 20
        session.upload_progress.cleanup On On
        session.upload_progress.enabled On On
        session.upload_progress.freq 1% 1%
        session.upload_progress.min_freq 1 1
        session.upload_progress.name PHP_SESSION_UPLOAD_PROGRESS PHP_SESSION_UPLOAD_PROGRESS
        session.upload_progress.prefix upload_progress_ upload_progress_

        Further since, file is being uploaded via AJAX using javascript
        So how file will get upload by this method ?
        Do you have working code? if so please provide me the same

        • http://www.psinas.com Martin Psinas

          Vish: yes, the _SESSION is “automatically” populated with the file information when the upload is in progress.

        • Hernan

          Hi!
          Did you solve it? I have the same problem :(
          Thanks!

    • Buck

      Try set
      session.auto_start = 1

      works for me

  • slawek22

    Well, i think people are divided into 2 groups “published authors” and real “web developers”.

    I am, unlike published author – a “published coder”. I make products that solve problems… that people use. We have some applications to upload files, eg. CMS for an real estates agents.

    Now you tell me that my clients should be uploading files one-by-one and waste countless hours staring into progress bars “because i don’t like flash”. Well one company that we implemented CMS for was using one-at-once file uploading. That was first request, they said people implementing previous soution were just idiots because it takes them 20 minutes to upload a couple of files.

    “flash is not cross browser”. Well you’re completely out of touch with reality. If 98% adoption is not enought so you want to provide sub-standard solution then you’re just fanatic and you’re DREAMING.

    I can upload 20 files AT ONCE with one progress bar… yeah, it is flash (like someone alse beside HTML nerd will care if it gets job done right). And for the remaining 2% users i don’t need progress bar (if you can’t install a stupid plugin why should the coder spent additional 2-3 maybe more hours of time just to make some very not-meaningfull addition targeted at 2% of people?)

    Such articles are very harmful. Actually some low-skilled developer could use this and write something with horrible usability. Add XHTML and short tags (both were obsolete 5 years ago) and you’ll have very bad HTML code. It only works because HTML has high tolerance for errors.

    Developers should write code to solve things most efficiently, not use latest and greatest technology to be “cool”. It’s half-baked, it really shows just how nerdy and out of thouch with real people they are.

    Don’t get me wrong the article compared to what we have on web is rather “good”. But on sitepoint you promised some “enlightment”, what I got was just same set of superstitious and myths repeated over and over with really BAD HTML code and usability.

    • http://www.psinas.com Martin Psinas

      First of all I too am a “published coder” and write code that people use, so I’m not sure where you’re going with that.

      I think perhaps you’re misunderstanding the solution, or I’m misunderstanding your problem. You make it sound as though the article suggests you can only handle one upload at a time; that isn’t the case. The example provided processes one upload, but you can easily add multiple files to be uploaded during the same request and track them all with ONE progress bar. The example on php.net shows how uploading 2+ files will look.

      Flash has 98% adoption you say, so what? 2% is still 2%. If that solution works for you then stick with it. Personally, I think the less dependency the better.

      I appreciate your feedback and I’m more than willing to admit when I’m wrong, but I’m not convinced you have a solid argument. You say the article is harmful and that I’m out of touch with reality? I think you could be less insulting and still sound intelligent.

      • slawek22

        Martin… I said you’re out of touch. And I was right, sure you can upload 2 files, you can place 20 controls and upload 20 files. By SELECTING THEM ONE BY ONE. Hey man, you don’t even know what im talking about!

        For your usability level you’re almost on par with some 20-century Joomla UIs. You know it? You click 3 times to upload one file, then you click continue and 3 more clicks to upload the second one. After 5 minutes and 10 files left you want to hit your PC with a hammer.

        You really think that having to click 40 times to have a simple gallery uploaded to web is a good, modern UI design? Come on. No it isn’t. You just use flash, one button that opens multi-select dialog and you just SELECT 20, 40 or whatever number of files and they get uploaded.

        Yes, simple as that. If your users don’t have flash they get some lame UI of course as you presented here and a quick explaination why i want them to be acting like monkeys. Yes, It’s UI for monkeys, really. If you’d want to take it to the next level you’d tell your user to use only one finger while typing on keyboard it’s as frustrating as uploading files one by one using 5-10 or whatever number of file form fields.

        >First of all I too am a “published coder” and write code that
        >people use
        Well i can only feel bad for your users because instead of going home they’re right now probably uploading files one-by-one, trying to get your apps to work or doing other very “productive” things just because of your superstitions and dislike for WORKING solutions. My users, instead, do their jobs and go home because i use what is BEST FOR THE JOB!

        Sorry don’t feel offended i always say everything straight. Just why you made so bad UI here and present it as “modern”? It’s outdated, using simple forms and UNUSABLE for anything beside uploading one or 2 small files.

        Why “no-flash”? Low faith in your abilities? Low self esteem? Hey why you use PHP at all? It has as bad reputation as flash. Everyone says it’s slow, no programming language really, no OOP and it sucks.

        >Personally, I think the less dependency the better.
        So you’re saying uploading 20 files in 10 minutes is better than uploading 20 files in 10 seconds because earlier is “less dependent”?

        You just trade dependency on flash for dependency on PHP5.4 which almost no one uses in production nowdays, so the solution isn’t even crappy and outdated but almost impossible to implement in real life situations.

        • http://www.psinas.com Martin Psinas

          Okay, I see your point. Your problem isn’t in tracking the upload (which is what this article is about), but in the selection of files. So continue using Flash for the multiselect, and use PHP 5.4 for tracking the progress. Wow, and you’re tearing the article a new one because of that? LOL.. I’m sorry mate, I’ll try to do better.

          • slawek22

            Yes, my problem isn’t tracking upload. Well actually that method isn’t technically good because it requires calling back the server… but acceptable.

            My problem – upload method that has very bad usability and bad html. My other problem is that you advertise this very poor and outdated method as something that will differentiate good developers from bad ones. While it’s actually very bad solution.

            And your overall approach to technology. You just removed flash, java and activex from the equation because of what the other people are saying and that is: “flash, java and activex is bad for everything”… don’t you have your own opinion?

            And who is saying that? Steve Jobs was (backed by some metrosexual, brainless Apple fanboys). You just repeat the words of a man who wanted to destroy flash just to retain control over his application ecosystem and a bunch of idiots that don’t even know what they’re talking about.

            For flash you don’t need PHP 5.4. It’s 100% browser and server side scripting independent. And for the progress you don’t need any communication with server using ajax. You just get the progress via JavaScript callbacks.

            You can do it SAME way using subset of HTML5 (which isn’t widely supported). But it’s the way that will be used in the future. HTML5 made a big effor to make the upload work EXACTLY the same way as flash does it and you say “no flash, thank you”…

            And in 2-3 years you’ll write “WOW XMLHttpRequest Level 2 what a nice way of uploading files”… it was there since 5 years (with help of flash).

            Knowing spec and repeating what’s others are saying isn’t enough if you want to be good developer. You should do some thinking on your own from time to time :)

          • http://www.psinas.com Martin Psinas

            Slawek22, you make an awful lot of assumptions, and seem to get very worked up over small trivial things. Thanks for reading.

        • http://zaemis.blogspot.com Timothy Boronczyk

          Wait, what? 5.4 is outdated? Man I must have missed that memo! :)

          • Slawek22

            @Martin: Yes im very careful about things that seem small to you. These are not trivial obviously, because after all my posts you still seem to miss the point. Such “small things” is what distincts good web apps from bad ones.

            @Timothy: POST-ing form with FILE field(s) is an outdated way of sending files, because it doesn’t provide progress nor multiple file selection needed for modern web applications.

            PHP 5.4 is new version that isn’t widely deployed. I also said that. Where have i said PHP 5.4 is outdated?

        • Jones

          You’re attacking an article for not doing something YOUR way!? The article even states there are many ways to do this. I find your tone very insulting and rude to the author of this article. If you know best why not write your own blog post and preach it there! You’ve come across as a grade A idiot.

          P.s. Flash is a horrible solution. The sooner you realise it the better.

          • slawek22

            >Flash is a horrible solution
            Why?

            Well you’re a grade A ignorant. You can’t even find one thing to back your point. You just wrote 100% personal post that isn’t related to article nor what i wrote in any way.

            I just don’t like stupidity “flash is horrible”. Like 12 y/o kid that says “windows is evil” on some linux geek forum. Stop trolling.

      • http://andrewchamp.com/ Andrew Champ

        Bravo. Well said. You posted a very helpful & thoughtful article w/ lots of insight. That’s called progression. I’m not sure why but a lot developers take new methods personally. It’s like you just talked bad about his mother! Calm down slawek22.
        Cheers & thanks Martin Psinas.

  • Alex Gervasio

    Agreed with other posters. Totally unnecessary pejorative and insulting verbiage thrown around a really good article. If most of the rant is about having multiple file selections, that’s quite easy to achieve at markup level right now, by just picking up the “multiple” input HTML5 attribute. It’s supported by most modern browsers, except for sadists like IE, which gracefully degrades to plain single file selections. In the worst case, there’s heaps of JavaScript fallback options available out there when it comes to dealing with older/untamable browsers standing behind the crowd.

  • Buck

    The first upload works as expected but if I hit the submit button again to upload a new file (or same file) it starts showing a full progressbar for a moment before it starts form zero.

    How can I fix that?

    • http://www.psinas.com Martin Psinas

      Buck: in the javascript, just set the bar_color width back to zero before or after outputting the status.

      • Buck

        Thanks!

  • Slawek22

    Slawek22 , why dont u post a “Flash” solution instead of arguing ??

  • Aarto

    Great code !!! I’m totally agree with your choice about javascript vs jQuery !!!
    To avoid the “timeout” on shared servers, i’ve added a kind of buffer. I think that, even for big files, i if response var haven’t changed, the connection is out.
    add 2 global vars : buffer = 120; and cliche = 0;
    buffer = response == cliche ? buffer-1 : 120;
    cliche = response;
    if (response < 100) {
    if (buffer == 0){
    document.getElementById('status').innerHTML = 'error timeout';
    }else{
    setTimeout("sendRequest()", 1000);
    }
    }else{
    toggleBarVisibility();
    document.getElementById("status").innerHTML = "Done.";
    }

  • http://rawdesigns.net/ Rob

    How could I modify the script to getElementByClass?

  • Jai

    Hi mate, great tutorial!
    I just need to know how can I set the form action to another page instead of the same one, while showing the progress bar on the same page.

    This script ->
    if ($_SERVER["REQUEST_METHOD"] == “POST” && !empty($_FILES["userfile"])) {
    // move_uploaded_file()
    }
    is on that another page, I am referring to.

    Please respond as soon as possible. Thank you.

    • http://www.psinas.com Martin Psinas

      Hey, just change the src attribute of the iframe.

  • http://www.ruzane.com ruzane

    very good

  • Francis

    Hi, I am trying to duplicate your code into one of my application and the AJAX calls only start once the data comes back from the server (ie. after the file is uploaded and the post processing is complete).

    What am I missing?

    Thanks!

    • Francis

      Ah, nevermind… your code is fine, the issue is on my end…

      The progress update I want to provide is not on the upload itself – the files are relatively small – but on the processing that takes place after. So I am using the session variable in the upload script to store where I’m at in the loops, the the ajax script querries those loops. I forgot that the session is locked by the upload script until it is completed, so my ajax script just sits there waiting for the session to be available.

      All I had to do was to write the session then re-open it at each loop and I’m good to go.

  • Vedant

    I am getting 100 of Empty Key Condition from progress.php

    Using php 5.4 Does My Installation is not Right ?? or anything else

    Please Explain !!

  • Budda

    If people are complaining about multiple file uploads and arguing about what to use…. I say just write your own cross platform FTP client application….. jeesh it’s much faster. This article is for uploading a pic or an mp3. Not 2GB video files or 300 pictures. Come on people realize the scope and stop complaining when you can’t instantly find a tutorial for your needs…

  • jay

    Thanks for sharing.

  • Moggz

    Hi, thanks for the great article – I think it could be just what I’ve been hunting for! :)
    I’m trying to modify your solution so that…
    1 – The user submits the file upload form
    2 – The form posts to a new browser window, which then handles the file upload and displays the upload progress bar

    I have put the hidden field to populate the session array in the file upload form. The php to handle the file upload itself, your ‘Real-time Progress’ php segment (my hidden field on first page is still ‘myForm’, so I’ve not altered this) and the javascript functions are all on the page displayed in the new browser window.

    When I test it, the file is uploaded okay via the new browser window that the form posted to, but the window seems to upload the file before it displays any of the pages ‘body’ content. Once the upload has completed, the page content is displayed, and a second or two later the ‘status’ div’s innerHTML property is set to ‘Done.’

    My PHP ini settings show upload_progress as enabled etc (php 5.4)

    Any help or pointers would be much appreciated. Thanks again.

    • Moggz

      I’m triggering the javascript with by the way. Don’t know if that might have anything to do with it? :/

      • Moggz

        lol, sorry, it removed my code snippet :)
        I’m calling javascript startUpload function through the new browser window’s body onload attribute.

  • Tran Khanh

    I don’t know why I couldn’t get the result after doing all of the stuff above, could you upload your completed file?
    Thanks so much.

  • Jayraj

    Great Post … thank you. :-)

  • Wookie

    Hi Martin,
    Thanks for a great tutorial! Everything works fine, progress is shown, but I’ve got one stupid question: how to set to which directory the file will be uploaded?

  • Abdul Jabbar

    Really thanks alot for your kind concepts but I am not getting it work well. files less than 2 mb are uploaded but more than that are not… though I have set my upload_max_size to 8mb and phpinfo() shows that also but still getting it not done why?? any help please!!!! and also files less than 2mb are just moved to server but progress bar doesn’t work or show any progress. please upload some zip files bunch of complete example it’s a request. I need it urgent. it’s really a hopeful request.

  • sasho

    great “POST” Martin, ignore slawek22 since he’s totally on the wron place. he should go to flash forums instead…
    thanx…

  • Roland Hentschel

    Hi,
    I’m trying your code, with this PHP-code at the beginning
    set_time_limit(0);

    The file is uploaded, but the progress isn’t shown
    (just jumps from zero to 100, while upload still keeps running)
    What am I doing wrong, what have I been missing ?
    kind regards ( -: roland :- )

  • http://tehk.org triune

    Absolutely awesome! Cheers for the great tutorial!

  • bwaindwain

    You have move_uploaded_file() commented out. But are you sure it will work there? The form.php isn’t being reloaded after the upload finishes. And with cleanup set to ON the session data is gone immediately after the upload is finished.

    • Richard de Wit

      It is reloaded in the iframe when it finishes
      (see )

  • Usman Sadiq

    ini_get(“session.upload_progress.name”),

    I didnot found any value in it, therefore, the $key has only value, ‘myForm’, and didnot flow the process, can You please help Me.

  • Usman Sadiq

    Sorry, I ini_get(“session.upload_progress.prefix”)
    creates problem, and didn’t returns any value, I need some help, plz.

  • Richard de Wit

    Maybe good to note that <input type="hidden" value="myForm" name="”>
    must be BEFORE the in the form, else it doesn’t work. Spent hours on this trying to figure out what was wrong, since I had it after the input file.

    Also PHP 5.4 is REQUIRED for this to work

    • Richard de Wit

      Forgot to mention that this guide is awesome, thanks!

  • Brad

    I just don’t get it where it says // move_uploaded_file()
    I tried to make it upload to a folder in the same directory called /uploads/, since the upload process was a little too quick, when trying this script. What should I write there to make this work?

    • maayan

      Same question… what part of this code should actually upload the file?

      • http://www.psinas.com Martin Psinas

        The form “action” submits to itself. When you click submit, the same page (form.php) is reloaded in the hidden target frame. The example provided does not actually save the file once it has been uploaded because that isn’t the focus of this article. You will need to add the code to save the file yourself; if you’re not familiar with how file uploads work then you can read about it here: http://phpmaster.com/file-uploads-with-php/

  • Arithan

    Thanks for the great tutorial. I’ve been trying to find a working barebones version for a while that I can modify. The progress bar itself works great. However, is there a way to do the opposite and have the progress bar in the iframe and the form reload on the same page as the form itself? The reason I’m asking is because I have it check for errors before actually putting the form information into a database. Like if I added a “Title” field, I want to check to see if it’s empty. If it is, then output a message asking the user to enter a title. This should be done before the upload actually starts to prevent wasting time and resources.

    I know how to do the error checking, I just need to have the form reload on the same page when the submit button is pressed while having the progress bar in the iframe. Or is there a better solution?

  • Jim

    Hi, thanks for great tutorial. I followed the code to create a testing situation but I can never see the progress bar moving except done (even I tried to use a 20M file.) I added echo at the move_uploaded_file area but it never got to that point. Any idea what I might have done wrong? Thanks.

  • http://order.orniv.co.il jk

    Thanks for the great tutorial!
    I just had a problem with my page reloading before upload completion and your method looks like an elegant solution.
    Unfortunately I probably did not understand well the hidden “iform” way of leaving the visitor on the same page. What I get now is an infinite wait: the page never refreshes to “self”. I did not catch the way the code releases the self refreshing after upload completion. Please help.

  • http://notseeingdesiredeffect steven

    hi, the problem I have is that onthe first click of submit button it shows an empty prgess bar,and on the second click it then shows the fullcolored progress bar,please how can I clear this issue.