StoneLight
StoneLight

Reputation: 27

return response to from php to ajax before script finishes

I have a simple AJAX request that to a PHP file. Once the PHP script reaches a certain point I would like for the response to be completed and sent back to the client. After that I still need the PHP script to run a function that takes up to 15 seconds. Currently the browser waits for the entire PHP script to finish before processing the response. I have tried to use flush(); or ob_flush();, but it still waited for the PHP script to finish running before sending the response.

JQuery code:

jQuery.ajax({
            url: "../phpFile.php",
            data: formdata,
            cache: false,
            contentType: false,
            processData: false,
            type: 'POST',
            success: function (data) {
                data = $.parseJSON(data);
                if(data.success){
                    window.location = "../public/dashboard.php";
                }
           }
});

PHP code:

if ($script_reached_this_point) {

    // ob_start();
    echo json_encode(['success' => 'Ticket added']);
    //flush();
    //  ob_end_flush();

    run_15_second_function();

}

Upvotes: 1

Views: 3214

Answers (1)

BeetleJuice
BeetleJuice

Reputation: 40896

I solved a similar problem by having 2 PHP scripts. Let's call them receiver.php and worker.php. The process is as follows:

  1. AJAX calls receiver.php
  2. receiver.php calls worker.php in a secondary connection, passes it the job instructions and waits for the first line of response.
  3. As soon as the first line of response arrives from worker.php, receiver.php closes that connection
  4. receiver.php returns the response to AJAX immediately and exits.
  5. worker.php continues work in the background

receiver.php

//data to be forwarded to worker.php
$postData = json_encode($_POST);

// headers for the connection to worker.php
$headers =  "POST /path/to/worker.php HTTP/1.1".PHP_EOL;
$headers .= "Host: localhost".PHP_EOL;
$headers .= "Content-Length: ".strlen($postData).PHP_EOL;
$headers .= "Content-Encoding: none".PHP_EOL;
$headers .= "Content-Type: application/json".PHP_EOL;

// create socket to the local webserver for calling background script
$socketToWorker = fsockopen("localhost", 80, $errno, $err_msg);
if(!$socketToWorker) die("fsockopen error #$errno: $err_msg");

// Make the request and send the POST data
fwrite($socketToWorker, $headers.PHP_EOL.$postData);    

//read until the 1st packet is returned, then stop. 8192 is arbitrary
//but needs to be greater than the expected response from worker.php
$data = fread($socketToWorker,8192);
fclose($socketToWorker);

//send response to browser (work still ongoing in background)
if($data==='OK') echo "Success";
else echo "Background work failed. Error: $data";

worker.php

//parse input from receiver.php
$postData = json_decode(file_get_contents('php://input'),true);

//TODO: validate $postData. 

// If data is valid, set below to 'OK' to accept the job
$acceptJob = 'OK'; //replace with an error message to reject the job
ob_start(); //start the buffer
echo $acceptJob; //this is what receiver.php will see

//set headers for the response to receiver.php
header("Content-Encoding: none");
header('Connection: close');
header('Content-Length: '.ob_get_length() );

// flush buffer. Will cause receiver.php to receive data and disconnect
ob_end_flush(); ob_flush(); flush();

if($acceptJob!=='OK') exit;

##################### START THE JOB HERE #####################
set_time_limit(60); //only needed if you expect job to last more than 30 secs
run_15_second_function();

Upvotes: 3

Related Questions