PHP does not return immediately after proc_open().

PHP does not return immediately after proc_open(). … here is a solution to the problem.

PHP does not return immediately after proc_open().

I have 2 PHP scripts, caller.php and task.php. caller.php is called using a JQuery Ajax request, and then caller.php starts a process to run PHP files in the background, as shown in the following code

JQuery Ajax request

var xhr = $.ajax({
    url: "https://www.example.com/caller.php",
    type: "post",
    data: ""
  }).done(function(){}
});

Caller .php

$cmd = 'php task.php &';      To call task.php in background
$descriptorspec = array(
   0 => array('pipe', 'r'),  // STDIN 
   1 => array('pipe', 'w'),  // STDOUT
   2 => array('pipe', 'w')   // STDERR
);
$pipes = array();

$process = proc_open($cmd, $descriptorspec, $pipes);

do {
     get the pid of the child process and it's exit code
    $status = proc_get_status($process);
} while($status['running'] !== FALSE);

$pid = $status['pid'];
$exitcode = $status['exitcode'];

proc_close($process);

if($exitcode == 0){echo 'Task.php is running.'; }

I started with Running a php script via ajax, but only if it is not already running Learned the above code

The above code works perfectly, but proc_open() waits until task.php doesn’t finish its job. I want task.php to run in the background and get a response from caller.php immediately.

I also tried exec() and shell_exec() but neither worked. They wait for task.php to do all its job and then respond.

I also tried xhr.abort()

to leave only ajax responses in ajax, but then I found out that xhr.abort() did not close the connection to the server

Note that I’ve streamlined the code and removed some basic sessions and steps like user login to make the code shorter.

P.S. I have a VPS, so I have enough permissions to enable/disable php features etc.

Solution

Ok, I think you’re missing a flush() statement that returns status to ajax, for example:

do {
     get the pid of the child process and it's exit code
    $status = proc_get_status($process);
    echo $status['running'];
    ob_flush(); flush();  Send output to browser immediately

} while($status['running'] !== FALSE);

Keep in mind that if you use ob_flush() and flush(), you will not get the result in the done function, but in the xhr.onprogress event, which is an example with an explanation https://www.sitepoint.com/php-streaming-output-buffering-explained/

Hope this helps.

Related Problems and Solutions