如何设计一个AJAX界面来显示基于正在运行的脚本后端的进度条

Ok here is my problem.

  1. I have a file which outputs an XML based on an input X
  2. I have another file which calls the above(1) file with 10000 (i mean many) times with different numbers for X

When an user clicks "Go" It should go through all those 10000 Xs and simultaneously show him a progress of how many are done. (hmm may be updated once every 10sec).

How do i do it? I need ideas. I know how to AJAX and stuff, but whats the structure my program should take?

EDIT

So according to the answer given below i did store my output in a session variable. It then outputs the answer. What is happening is:

When i execute a loong script. It gets executed say within 1min. But in the mean time if i open (in a new window) just the file which outputs my SESSION variable, then it doesnt output will the first script has run. Which is completely opposite to what i want. Whats the problem here? Is it my syste/server which doesnt handle multiple requests or what?

EDIT 2

I use the files approach: To read what i want

> <?php include_once '../includeTop.php'; echo
> util::readFromLog("../../Files/progressData.tmp"); ?>

and in another script

$processed ++;
util::writeToLog($dir.'/progressData.tmp', "Files processed: $processed");

where the functions are:

   public static function writeToLog($file,$data) {
        $f = fopen($file,"w");
        fwrite($f, $data);
        fclose($f);
    }
    public static function readFromLog($file) {
        return file_get_contents($file);
    }

But still the same problem persist :(. I can manually see the file gettin updated like 1, 2, 3 etc. But when i run my script to do from php it just waits till my original script is output.

EDIT 3

Ok i finally found the solution. Instead of seeking the output from the php file i directly goto the log now and seek it.

Edit: I was wrong about $_SESSION. It doesn't update asynchronously, i.e. the values you store in it are not accessible until the script has finished. Whoops.

So the progress needs to be stored in something that does update asynchronously: Memory (like pyroscope suggests, and which is still the best solution), a file, or the database.

In other words, instead of using $_SESSION to store the value, it should be stored by memcached, in a file or in the database.

I.e. using the database

$progress = 0;
mysql_query("INSERT INTO `progress` (`id`, `progress`) VALUES ($uid, $progress)");
# loop starts
    # processing...
    $progress += $some_increment;
    mysql_query("UPDATE `progress` SET `progress`=$progress WHERE `id`=$uid");
# loop ends

Or using a file

$progress = 0;
file_put_contents("/path/to/progress_files/$uid", $progress);
# loop starts
    # processing...
    $progress += $some_increment;
    file_put_contents("/path/to/progress_files/$uid", $progress);
# loop ends

And then read the file/select from the database, when requesting progress via ajax. But it's not a pretty solution compared to memcached.

Also, remember to remove the file/database row once it's all done.


You could put the progress in a $_SESSION variable (you'll need a unique name for it), and update it while the process runs. Meanwhile your ajax request simply gets that variable at a specific interval

function heavy_process($input, $uid) {
    $_SESSION[$uid] = 0;
    # loop begins
        # processing...
        $_SESSION[$uid] += $some_increment;
    # loop ends
}

Then have a url that simply spits out the $_SESSION[$uid] value when it's requested via ajax. Then use the returned value to update the progress bar. Use something like sha1(microtime()) to create the $uid

Edit: pyroscope's solution is technically better, but if you don't have a server with memcached or the ability to run background processes, you can use $_SESSION instead

Put the progress (i.e. how far are you into the 2nd file) into a memcached directly from the background job, then deliver that value if requested by the javascript application (triggered by a timer, as long as you did not reach a 100%). The only thing you need to figure out is how to pass some sort of "transaction ID" to both the background job and the javascript side, so they access the same key in memcached.