Get PHP proc_open() to read a PhantomJS stream for

2019-05-30 05:39发布

问题:

I had a PHP script that relied on shell_exec() and (as a result) worked 99% of the time. The script executed a PhantomJS script that produced an image file. Then using more PHP that image file was processed in a certain way. Problem was that on occasion shell_exec() would hang and cause usability issues. Reading this https://github.com/ariya/phantomjs/issues/11463 I learnt that shell_exec() is the problem and switching to proc_open would solve the hanging.

The problem is that while shell_exec() waits for the executed command to finish proc_open doesn't, and so the PHP commands that follow it and work on the generated image fail as the image is still being produced. I'm working on Windows so pcntl_waitpid is not an option.

What I'm trying to do is continuously have PhantomJS output something (anything) so that proc_open would read via it's stdin pipe and that way I can time the image processing PHP functions to start working as soon as the target image file is ready.

here is my phantomJS script:

interval = setInterval(function() {
  console.log("x");
}, 250);
var page = require('webpage').create();
var args = require('system').args;
page.open('http://www.cnn.com', function () {
  page.render('test.png');
  phantom.exit();
});

And my PHP code:

ob_implicit_flush(true);
$descriptorspec = array(
    0 => array("pipe", "r"),  // stdin
    1 => array("pipe", "w"),  // stdout
    2 => array("pipe", "w")   // stderr 
);

$process = proc_open ("c:\phantomjs\phantomjs.exe /test.js", $descriptorspec, $pipes);
if (is_resource($process))
{
while( ! feof($pipes[1]))
  {
     $return_message = fgets($pipes[1], 1024);
     if (strlen($return_message) == 0) break;
     echo $return_message.'<br />';
     ob_flush();
     flush();
  }
}

The test.png is generated, but I am not getting a single $return_message. What am I doing wrong?

回答1:

As Bill Shander suggested right in your linked github issue, you can use:

Proc_Close(Proc_Open("phantomjs test.js &", Array (), $foo));

to run your phantomjs script (which is based on this answer). It seems that you only need the image, so the pipes are not necessary in this case.

Complete script for reference is here and works on windows as is.