使用PHP的proc_open + bypass_shell在后台运行可执行文件并检索正确的PID?

时间:2011-08-23 13:04:48

标签: php windows background pid proc-open

所以,在Windows上的PHP中:是否可以在后台运行可执行文件并且检索其PID ?我已经推断出可以单独完成这两项任务,但不能一起完成。

背景化过程

要对通过SHELL启动的进程进行后台处理,必须使用命令'start /B "bg" myprog.exe',并且必须在之后立即关闭SHELL进程。

要做到这一点,很多人都会pclose( popen( ... ) )使用pclose( popen( 'start /B "bg" myprog.exe', 'r') );,但据我所知,使用popen时无法检索pid

因为用popen获取pid是不可能的,所以我们必须看看proc_open。

获取PID

使用proc_open我们可以检索exe的pid(如果,并且只有 bypass_shell设置为true。

如果bypass_shell设置为false(默认值),Windows将返回SHELL的pid。有关详细信息,请参阅:https://bugs.php.net/bug.php?id=41052

问题解释

start /B命令在bypass_shell = true传递给proc_open时失败,因为它跳过SHELL并将命令行参数直接发送到myprog.exe,而myprog.exe不知道如何处理它们。

相反,如果使用bypass_shell = false(默认值)和proc_close立即关闭SHELL,myprog.exe在后台运行就像使用pclose( popen( ... ) )不正确 pid(我们得到SHELL的pid

那么,背景+正确的pid检索可能吗?

如果没有,那么下一个最好的东西是什么?我需要为将部署在共享主机上的PHP脚本执行此操作,因此不能安装第三方扩展。我能想到的最好的方法是在后台启动myprog.exe之前和之后拍摄tasklist的快照,然后交叉分析结果。请注意,myprog.exe可以同时运行。

如果它有帮助,虽然它不应该有所作为,myprog.exe实际上是ffmpeg(它安装在大多数共享的webhosts上)。

临时解决方案

// 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];

1 个答案:

答案 0 :(得分:1)

这不是OP问题的答案,因为它不能在Windows服务器上运行,但它可以在任何启用了exec()的Linux服务器上正常工作,因此它可以帮助某人;)

$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);