2

I'm using jQuery + PHP on my website and I want to do something like this:
To simplify things I've got a page with 2 buttons () and according to which I click I want to start a script in background (php script) so I do a simple thing with jquery:

$("#button1").click(function(){
    $.post("script.php", {val:"but1"}, function(result){
        alert(result); // I want something with the result
    });
});

$("#button2").click(function(){
    $.post("script.php", {val:"but2"}, function(result){
        alert(result);
    });
});

and in the script.php I've got a simple if statement deciding what I should do.
In the php script I'm downloading a file and I want to create a progress bar of the file download. The php script would return me values (echo percentage; flush();) in some time interval.
And here comes the problem - when I echo those percentage values and flush it refreshes it "just in php" but the jquery waits until the script is finished anyway. Is there a way to get those values as they appear (after flush) or is there a completely other approach to this? I can't think of anything else right now, maybe I shouldn't be using jquery at all.
Thanks for the help.

5 Answers 5

1

You can store the progress in a text file or DB while running the script and then have another file get the result via AJAX calls.

JS/HTML

<script>
$(function() {
    var id;
    var timeoutLength = 1000;

    $("#button1").click(function() {
        $("#result").html("");

        // Create unique identifier
        id = (new Date().getTime()) + "-" + Math.floor(Math.random()*100);
        $.get("script.php", {id: id}, function(result){
            $("#result").html(result);
        });

        setTimeout(checkProgress, timeoutLength);
    });

    function checkProgress() {
        $.get("script.php", {progress: true, id: id}, function(data) {
            prog = parseInt(data);
            // Display progress bar
            if(prog < 100) {
                $("#progress").css({ display: 'block', width: prog });
                $("#progress").html(prog + "%");

                setTimeout(checkProgress, timeoutLength);
            } else {
                $("#progress").css('display', 'none');
            }
        });
    }
})
</script>
<button id="button1">Click</button>
<div id="progress" style="background: green"></div>
<div id="result"></div>

script.php

<?php

function getProgress($file) {
    return (file_exists($file)) ? file_get_contents($file) : 0;
}

function setProgress($file, $progress) {
    file_put_contents($file, $progress);
}

// Remove invalid characters
$id = str_replace('/[^a-zA-Z0-9\-_]/', '', $_GET['id']);
$file = "progress-" . $id . ".txt";

if(isset($_GET['progress'])) {
    echo getProgress($file);
} else {
    // Do something and update progress
    for($i = 10; $i <= 100; $i += 10) {
        // Do something

        setProgress($file, $i);
        sleep(1);
    }
    unlink($file);
    echo "Result: " . rand(1, 100);
}

Edit: Added support for multiple requests and simple progress bar.

Sign up to request clarification or add additional context in comments.

3 Comments

Won't it be too slow if for example 100 people start downloading 100 files and all of them have to be written on server and then read every 100ms for example
This seems to work well, I'll test it later for the speed and such but seems like a simpliest solution to me since I can't use wget and other stuff suggested here, thanks.
@haluzak did you managed to do performance tests on high users concurrency?
1

i believe that what all you need is the pecl uploadprogress package

it is not very easy to install and its not sure it works, i have find hard to make it work under certain server configurations, but i think its a good shot

EDIT: sorry i didnt see you mention download so have a look here

1 Comment

Yes I thought of checking file size against full file size as well I just wanted to make it in a bit better way since the download script returns the percentage I just don't know how to get it into the progress bar :). But this should work as well I'll try it thanks.
1

Below script will work for the progress-bar.

But, what I would do is, trigger an AJAX call to start the download and trigger another AJAX call to start receiving the input (using How to show file download progress in PHP Shell Scripting?).

PHP:

<?php
echo "wget '$feedURL'\n";
$execute = "wget -O ".$filePath." '$feedURL'\n";
$systemOutput = shell_exec($execute);
$systemOutput = str_replace( "\n", "\n\t", $systemOutput);
echo "\t$systemOutput\n";
?>

GetProgress:

function getProgress(){
  GDownloadUrl("getprogress.php?progress_key=<?php echo($unique_id)?>", 
               function(percent, responseCode) {
                   document.getElementById("progressinner").style.width = percent+"%";
                   if (percent < 100){
                        setTimeout("getProgress()", 100);
                   }
               });

}

Here is nice implementation with the help PHP's APC to get a nice progress-bar during UPLOAD of a file - http://www.haughin.com/2007/10/23/php-upload-progress-with-php-52-apc/

1 Comment

Thanks but I wanted downloading :)
0

Alternative solution: You can store the progress of downloading file into $_SESSION array inside PHP. Besides that, you can write a dedicated PHP to only retrieve this percentage from session. This PHP will be called from your client's AJAX. This way the proccess won't take so much resources from server to calculate or to echo the download's percentage.

Try to avoid I/O from files if you are going to handle high rates of reading/writing onto them. Session variables are less expensive to achieve this functionality.

Comments

-1

Provided that your PHP has some way to know the progress percentage, you should do multiple requests for progress updates:

function receiveProgress(data) {
    // update progres indicator here
    if (parseFloat(data) < 100) {
        setTimeout(checkProgress, 100);
    } else {
        pressedButton = '';
    }
}

function checkProgress() {
    $.post("script.php", {val:pressedButton}, receiveProgress);
}


var pressedButton = '';
$("#button1").click(function(){
    pressedButton = 'but1';
    checkProgress();
});

This will ask server for progress updates every 100ms

3 Comments

Thanks, yes I probably know how to obtain percentage but that's other problem. But won't this just call the script again from the beginning? Because in the script.php I call exec(); which starts the whole downloading so when I call the $.post on script.php multiple times won't it start downloading again every 100ms?
just being blunt, why don't you write the % to a text file and ask some other php to handle only the echo part?
Shrinath: writing it to a file would be quite slow but I want to handle it with sessions now at least I'm trying to :).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.