默认情况下,在Linux上,是否通过proc_open()创建进程会使PHP脚本在生成的进程终止之前不会终止?我不希望它,我立即关闭进程句柄.
proc_open本身并没有阻止,这很清楚.但是整个HTTP请求执行呢?
XzK*_*Kto 15
我周末有时间,所以我在*nix系统上对proc_open()进行了一些研究.
虽然proc_open()不会阻止PHP的脚本执行,即使shell脚本没有在后台运行,但是如果你自己不调用PHP的脚本,PHP会自动调用proc_close().所以,我们可以想象我们在脚本末尾总是有一行proc_close().
问题在于不明显但逻辑上的proc_close()行为.让我们假设我们有一个类似的脚本:
$proc = proc_open('top -b -n 10000',
array(
array('pipe', 'r'),
array('pipe', 'w')),
$pipes);
//Process some data outputted by our script, but not all data
echo fread($pipes[1],100);
//Don't wait till scipt execution ended - exit
//close pipes
array_map('fclose',$pipes);
//close process
proc_close($proc);
Run Code Online (Sandbox Code Playgroud)
奇怪的是,proc_close()会在shell脚本执行结束之前等待,但我们的脚本很快就会被终止.它很好,因为我们关闭了管道(如果我们忘记了,似乎PHP会默默地执行它)所以只要该脚本试图将某些东西写入已经不存在的管道 - 它就会出错并终止.
现在,让我们试试没有管道(好吧,会有,但他们将使用当前的tty,没有任何链接到PHP):
$proc = proc_open("top -b -n 10000", array(), $pipes);
proc_close($proc);
Run Code Online (Sandbox Code Playgroud)
现在,我们的PHP脚本正在等待我们的shell脚本结束.我们能避免吗?幸运的是,PHP生成shell脚本
sh -c 'shell_script'
Run Code Online (Sandbox Code Playgroud)
所以,我们可以杀死sh进程并让我们的脚本运行:
$proc = proc_open("top -b -n 10000", array(), $pipes);
$proc_status=proc_get_status($proc);
exec('kill -9 '.$proc_status['pid']);
proc_close($proc);
Run Code Online (Sandbox Code Playgroud)
对于cource,我们可以在后台运行该过程,如:
$proc = proc_open("top -b -n 10000 &", array(), $pipes);
proc_close($proc);
Run Code Online (Sandbox Code Playgroud)
并没有任何问题,但这个功能引出了我们最复杂的问题:我们可以运行proc_open()读取一些输出的进程,然后强制进程到后台吗?好吧,在某种程度上 - 是的.
这里的主要问题是管道:我们无法关闭它们或者我们的流程会死亡,但是我们需要它们从该流程中读取一些有用的数据.事实证明,我们可以在这里使用魔术 - gdb.
首先,在某处创建一个文件(在我的示例中为/ usr/share/gdb_null_descr),其中包含以下内容:
p dup2(open("/dev/null",0),1)
p dup2(open("/dev/null",0),2)
Run Code Online (Sandbox Code Playgroud)
它将告诉gdb将描述符1和2(好吧,它们通常是stdout和stderr)更改为新文件处理程序(在此示例中为/ dev/null,但您可以更改它).
现在,最后一件事:确保gdb可以连接到其他正在运行的进程 - 它在某些系统上是默认的,但是例如在ubuntu 10.10上你必须将/ proc/sys/kernel/yama/ptrace_scope设置为0如果你不这样做以root身份运行它.
请享用:
$proc = proc_open('top -b -n 10000',
array(
array('pipe', 'r'),
array('pipe', 'w'),
array('pipe', 'w')),
$pipes);
//Process some data outputted by our script, but not all data
echo fread($pipes[1],100);
$proc_status=proc_get_status($proc);
//Find real pid of our process(we need to go down one step in process tree)
$pid=trim(exec('ps h -o pid --ppid '.$proc_status['pid']));
//Kill parent sh process
exec('kill -s 9 '.$proc_status['pid']);
//Change stdin/stdout handlers in our process
exec('gdb -p '.$pid.' --batch -x /usr/share/gdb_null_descr');
array_map('fclose',$pipes);
proc_close($proc);
Run Code Online (Sandbox Code Playgroud)
编辑:我忘了提到PHP没有立即运行你的shell脚本,所以在执行其他shell命令之前你必须等一下,但通常它足够快(或者PHP足够慢)而且我懒得去将该检查添加到我的示例中.