1

I'm writing a php script that has a long execution time, and I want to be able to tell the client the scripts progress.

I can't do it with output buffering because the script is called via AJAX (and I'd like to keep it that way).

I stumbled upon a solution where you save the progress to a $_SESSION variable and make continuous calls to another PHP script to get the progress from the $_SESSION.

However, in my implementation, these calls do not execute until the main (long) process is done. In the Chrome dev tools window, the calls are showing as "Pending" along with the main AJAX call, and they all return the progress instantly after the main call finishes.

enter image description here

This is the main long script (test code):

<?php
@session_start();
for($i=0; $i<10; $i++)
{
    $_SESSION["progress"] = $i;
    sleep(2);
}

This is the updating script

<?php
if(isset($_SESSION["progress"]))
    echo $_SESSION["progress"];
else
    echo 0;

This is the javascript

$("form#form-main").submit(function(e) {
    e.preventDefault();
    var $form = $(this);
    var timeout_id;

    $form.find("div#popup-overlay").show();

    $.ajax(
        {
            url: $form.attr("action"),
            type: $form.attr("method"),
            data: new FormData($form[0]),
            cache: false,
            contentType: false,
            processData: false,
            xhr: function()
            {
                //get the native XmlHttpRequest object
                var xhr = $.ajaxSettings.xhr();

                //update progress
                xhr.upload.onprogress = function(e)
                { 
                    if(e.lengthComputable)
                    {
                        var progress = Math.ceil(e.loaded / e.total * 100);

                        if(progress < 100)
                            $form.find("div#popup-content #status").text("UPLOADING " + progress + "%");
                        else
                        {   
                            //start getting process progress from server
                            timeout_id = setInterval(
                                function() 
                                {
                                    $.post(
                                        "CheckProgress.php",
                                        function(data)
                                        {
                                            $form.find("div#popup-content #status").text("PROCESSED " + data + " pages");
                                        }
                                    );
                                },
                                300
                            );
                        }
                    }
                };

                //return the customized object
                return xhr;
            },
            success: function(data)
            {
                $form.find("div#popup-content").html(data);
            }       
        }
    );
});

What can I do to make the javascript client retrieve the progress?

10
  • what about writing progress to database instead of seesion and retrieve results through javascript? Commented Oct 16, 2014 at 8:13
  • How would that be any different? Commented Oct 16, 2014 at 8:15
  • separation from php. maybe in line if(progress < 100) setIntevral with checkProgress should be for progress < 100 ? Commented Oct 16, 2014 at 8:24
  • I think the problem might be your onprogress only gets called when the 1st ajax completes, since it's not an ajax call that can return a progress. Try starting your first ajax and then your 2nd ajax at the same time, one after the other. Commented Oct 16, 2014 at 8:25
  • The onprogress has nothing to do with the AJAX. That's just to display the upload progress, not the php execution progress. Commented Oct 16, 2014 at 8:29

2 Answers 2

2

According to this post (Using same session ID within two PHP scripts at same time), you cannot execute php scripts simultaneously with the same session id. This is called session lock.

The solution was to only start the session for the write, and to close it immediately after, leaving the session id unused for the CheckProgress to use.

New long script

for($i=0; $i<10; $i++)
{
    @session_start();
    $_SESSION["pages-processed"] = $i;
    session_write_close();
    sleep(2);
}

New CheckProgress

@session_start();
if(isset($_SESSION["pages-processed"]))
    echo $_SESSION["pages-processed"];
else
    echo 0;

Now it works like a charm :)

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

Comments

-1

use

async=false;

in your ajax request

in your code u have looped the php for long time,, the page will load only after the execution so you will get only last value of progress

1 Comment

That just made the whole page hang as soon as I clicked submit

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.