开发者

Use PHP's proc_open + bypass_shell to run an executable in the background AND retrieve the correct PID?

So, In PHP on Windows: is it possible to both run an executable in the background AND retrieve its PID? I've deduced that it's possible to accomplish both tasks separately, but not together.

Backgrounding the Process

To background a process launched via the SHELL, the command 'start /B "bg" myprog.exe' must be used and the the SHELL process must be closed immediatel开发者_开发知识库y after.

To do this, many people use pclose( popen( ... ) ) like so pclose( popen( 'start /B "bg" myprog.exe', 'r') ); but to my knowledge it's impossible to retrieve the pid when using popen.

Because it's impossible to get the pid with popen, we must look to proc_open.

Getting the PID

Using proc_open we can retrieve the pid of the exe if and only if bypass_shell is set to true.

If bypass_shell is set to false (the default), Windows returns the pid of the SHELL. For more info see: https://bugs.php.net/bug.php?id=41052

The Problem Explained

The start /B command fails when passed to proc_open when bypass_shell = true because it skips the SHELL and sends the commandline arguments directly to myprog.exe which doesn't know what to do with them.

Conversely, If bypass_shell = false (the default) and proc_close is used to close the SHELL immediately, myprog.exe runs in the background just like when using pclose( popen( ... ) ) BUT the incorrect pid is returned (we get the pid of the SHELL).

So, is backgrounding + correct pid retrieval possible?

If not, what's the next best thing? I need to do this for a PHP script that will be deployed on shared hosting so no third party extensions can be installed. The best I can come up with is taking a snapshot of tasklist before and after launching myprog.exe in the background and then cross-analyzing the results. Note that myprog.exe can be running concurrently.

If it helps, although it shouldn't make a difference, myprog.exe is actually ffmpeg (which comes installed on most shared webhosts).

A Temporary Solution

// background the process
pclose( popen( 'start /B "bg" ffmpeg.exe', 'r') );

// get the pid using tasklist
exec( 'TASKLIST /NH /FO "CSV" /FI "imagename eq ffmpeg.exe" /FI "cputime eq 00:00:00"', $output );
$output = explode( '","', $output[0] );
$pid = $output[1];


this is not exactly an answer for OP's question, since it won't work on windows server, but it will work just fine on any linux server with exec() enabled, so it might help someone ;)

$pidfile = 'myPidFile'; //coule be done better with tempnam(), but for this example will do like that ;)
$outputfile = '/dev/null'; //can be any text file instead of /dev/null. output from executable will be saved there
$cmd = 'sleep 30'; // this would normaly take 30 seconds
exec(sprintf("%s > %s 2>&1 & echo $! > %s", $cmd, $outputfile, $pidfile));

$pid = file_get_contents($pidfile);
echo $pid;
//delete pid file if you want
//unlink($pidfile);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜