Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting XMLHttpRequest Progress from PHP Script

I am using javascript to run a XMLHttpRequest to a PHP script which returns data. Basically I want to be able to provide the user with a progress bar (instead of a spinning circle or something) that shows the progress of getting and receiving the data. I know if I was getting a file, I could just check the content length header and use that, but in the case of a script, you don't know how much data it's retrieving.

The answer to this might be as easy as, "it's not possible," because right now it seems that way. But in conclusion: How do you monitor progress of a running script (php) over and XMLHttpRequest?

like image 720
Evan4623 Avatar asked Oct 25 '22 04:10

Evan4623


1 Answers

If you're using FireFox (and I'm fairly sure most other browsers other than IE), then there is indeed a way to report how much data has been transferred during an XHR operation. If the operation in question sends the correct header, it's fairly easy to use this information to calculate the percentage of the data downloaded.

I wrote this code for determining the percentage of data transferred in an XHR operation years ago, so I apologize for it not reflecting the years of coding experience I've gained since. I almost certainly wouldn't write it this way now! Still, I managed to fish it out, and hope it's of use for you.

At the time this was written, IE7 was the latest version of Explorer available, and I remember the code didn't work in that, hence it contains code to prevent it initializing under IE. I've never tried this code out under version 8 or the beta of version 9, and it may indeed work in those versions as well, but I can't vouch for it. If you can get it working in a new version of IE, please let me know!

It works by running code in beforeSend (a callback jQuery provides for code you want to run before starting an ajax request) to set up a Javascript interval (in the code I've put 50 miliseconds, which is probably far too often. 200 miliseconds should still be plenty, and put less strain on the system). Every time the interval timer fires, it runs a function that looks at the responseText attribute of the XHR request. The responseText attribute holds the raw text of the data received thus far. By counting how many characters are in there with the length() string method, we can work out how many bytes have been collected so far.

As far as working out the percentage of total data to be sent, this will require that your server side code sends a content-length header with an accurate count of how many bytes it is going to send. This will require a little cleverness on your part, but shouldn't prove too difficult. If you send an accurate content-length header, then it is used to calculate a percentage of data received so far. If you don't set a content header, then the amount of data received so far is displayed instead.

<script type="text/javascript">
$.ajax ({
    beforeSend  : function (thisXHR)
    {
        // IE doesn't support responseText access in interactive mode
        if (!$.browser.msie)
        {
            myTrigger = setInterval (function ()
            {
                if (thisXHR.readyState > 2)
                // When there is partial data available use it to determine how much of the document is downloaded
                {   
                    var dlBytes = thisXHR.responseText.length;
                    if (totalBytes == -1)
                        totalBytes  = thisXHR.getResponseHeader ('Content-length');
                    (totalBytes > 0)?
                        $('#progress').html (Math.round ((dlBytes / totalBytes) * 100) + "%"):
                        $('#progress').html (Math.round (dlBytes / 1024) + "K");
                }
            }, 50); // Check the status every 50 miliseconds
        }
    },
    complete    : function ()
    {
        // Kill the download progress polling timer
        if (myTrigger)
            clearInterval (myTrigger);
    }
});
</script>
like image 111
GordonM Avatar answered Nov 16 '22 12:11

GordonM