Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/243.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP proc_open是否阻止Web请求?_Php_Process - Fatal编程技术网

PHP proc_open是否阻止Web请求?

PHP proc_open是否阻止Web请求?,php,process,Php,Process,默认情况下,在Linux上,通过proc_open()创建进程是否会使PHP脚本在生成的进程终止之前不会终止?我不想这样,我马上关闭进程句柄 proc_open本身不会阻塞,这一点很清楚。但是HTTP请求的整体执行情况如何?我周末有一些时间,所以我对*nix系统上的proc_open()进行了一些研究 虽然proc_open()不会阻止PHP脚本的执行,即使shell脚本没有在后台运行,但如果您自己不调用它,PHP脚本完全执行后,PHP会自动调用proc_close()。所以,我们可以想象,在脚

默认情况下,在Linux上,通过proc_open()创建进程是否会使PHP脚本在生成的进程终止之前不会终止?我不想这样,我马上关闭进程句柄


proc_open本身不会阻塞,这一点很清楚。但是HTTP请求的整体执行情况如何?

我周末有一些时间,所以我对*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);
奇怪的是,proc_close()会在shell脚本执行结束之前等待,但我们的脚本很快就终止了。这可能是因为我们关闭了管道(如果我们忘记了,PHP似乎会默默地完成这项工作),所以一旦该脚本尝试向已经不存在的管道写入内容,它就会收到错误并终止

现在,让我们尝试不使用管道(当然会有,但它们将使用当前的tty,而不使用任何到PHP的链接):

现在,我们的PHP脚本正在等待shell脚本结束。我们能避免吗?幸运的是,PHP生成了带有

sh -c 'shell_script'
所以,我们可以终止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);
当然,我们可以在后台运行该过程,如:

$proc = proc_open("top -b -n 10000 &", array(), $pipes);
proc_close($proc);
并且没有任何问题,但是这个特性将我们引向一个最复杂的问题:我们是否可以运行一个进程,让proc_open()读取一些输出,然后将进程强制到后台?嗯,在某种程度上——是的

这里的主要问题是管道:我们不能关闭它们,否则我们的进程将死亡,但我们需要它们从该进程读取一些有用的数据。事实证明,我们可以在这里使用一个魔术——gdb

首先,在某处创建一个包含以下内容的文件(/usr/share/gdb_null_descr):

p dup2(open("/dev/null",0),1)
p dup2(open("/dev/null",0),2)
它将告诉gdb将描述符1和2(通常是stdout和stderr)更改为新的文件处理程序(本例中为/dev/null,但您可以更改它)

现在,最后一件事:确保gdb可以连接到其他正在运行的进程——这在某些系统上是默认的,但在ubuntu 10.10上,如果您不以root用户身份运行它,您必须将/proc/sys/kernel/yama/ptrace_scope设置为0

享受:

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

编辑:我忘了提到PHP不会立即运行shell脚本,所以在执行其他shell命令之前,您必须等待一段时间,但通常它足够快(或PHP足够慢),我懒得将这些检查添加到示例中。

我遇到了类似的问题,并编写了一个小脚本来处理它:


我所做的是对进程进行后台处理,并且仍然可以访问后台处理的结果(stderr和stdout)。

不,proc_open()不会阻止任何内容。但这里有几个问题:proc_close()可能无法关闭进程并阻塞PHP应用程序。如果是这种情况,请尝试在尝试proc_close()或/或使用proc_terminate()+proc_get_status()之前关闭所有打开的管道,至少用于调试-它们不会阻止脚本的执行。整个HTTP请求的执行取决于您所使用的web服务器—可以在所有PHP子进程终止之前执行请求阻塞,但至少Apache/Nginx不会这样做。Tx。管道不是问题-我没有传递任何管道。那么为什么要使用proc_open而不是exec/system/passthru等?它们的行为更加透明。passthru()将输出传递到HTTP响应中——我不希望这样。Exec()和system()等待进程完成。一、 同时,希望启动一个可能需要一段时间(大约1分钟)的后台进程,然后继续进行HTTP处理。如果进程超过当前HTTP请求的时间,就这样吧。否,exec()和system()仅在您不在后台运行它时才等待进程完成—请尝试exec(“top-b-n 1000>/dev/null 2>/dev/null&”;你能解释一下这个短语是什么意思吗?>PHP不会立即运行shell脚本,因此在执行其他shell命令之前必须等待一段时间。在PHP中执行类似“proc_open(shell_CMD);runPhpFunction();”的操作时,可以在shell_CMD实际在系统中运行之前执行runPhpFunction()。虽然proc_open()似乎是同步的,因为它返回SHELL_CMD的PID(这在SHELL_CMD启动之前是不可能做到的),但这实际上不是您的SHELL_CMD的PID,而是SHELL_CMD将在其中执行的SHELL的PID(/bin/sh或其他),SHELL实际执行SHELL_CMD可能需要一些时间(从而导致比赛状态),但大多数情况下,它的速度足够快,似乎运行正常。
$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);