PHP proc_open 是否会阻止 Web 请求?

2023-11-24

默认情况下,在 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):

$proc = proc_open("top -b -n 10000", array(), $pipes);
proc_close($proc);

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

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 上,如果您不这样做,则必须将 /proc/sys/kernel/yama/ptrace_scope 设置为 0以 root 身份运行它。

Enjoy:

$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 足够慢),我懒得将其添加到我的示例中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PHP proc_open 是否会阻止 Web 请求? 的相关文章

随机推荐

  • HTML5 视频的 z-index 分层 (ipad) [重复]

    这个问题在这里已经有答案了 可能的重复 iPad Safari 移动版似乎忽略了 html5 视频元素的 z 索引位置 我正在使用 BrightCove smartplayer 代码将 HTML5 视频标签写入页面 此代码将对象标签替换为视
  • 输出消失Javascript简单innerHTML

    我对 javascript 很陌生 在每一个简单的事情上我都会遇到一些问题 但这对我来说似乎无法解决 我用谷歌搜索了一下 没有类似的东西 当我将数据输入文本框并将其存储到变量中后 我打印出段落中的变量 问题是我打印出来的输出在不到一秒的时间
  • 内联onclick是如何评估的?

    我很好奇内联元素属性事件的内容在幕后是如何工作的 我们从一个简单的函数开始 function handler e console log e 使用案例1 如果我们想将此处理程序添加到我们的按钮中 我们可以这样做
  • 适用于 Google Chrome 的 Google Cast 扩展程序是否支持 1080p? [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 在 选项卡投影质量 下的 Google Cast 扩展选项中 有三个选项 至尊 720p 高码率 高 720p 标准 480p 1080p 未列出 我假设如果我播放 1080p 视频
  • 如何在运行时添加 UIButton

    我正在尝试添加一个UIButton但在运行时它是不可见的 我究竟做错了什么 id initWithFrame CGRect frame if self super initWithFrame frame UIButton btn UIBut
  • Airflow 任务失败/重试工作流程

    我有任务的重试逻辑 但不清楚重试打开时 Airflow 如何处理任务失败 Their 文档只是指出on failure callback当任务失败时被触发 但是如果该任务失败并且也被标记为重试 这是否意味着on failure callba
  • ExtJS 4“始终位于顶部”窗口

    我需要实现可以始终位于顶部的窗口 我该怎么做呢 我对 WindowManager 的所有尝试都没有给我结果 在 Ext window Window 中 有一个名为 modal 将其设置为 true 否则 请使用窗口管理器管理您的窗口 在这种
  • 用于估计统计中位数、众数、偏度、峰度的“在线”(迭代器)算法?

    是否有一种算法可以估计一组值的中值 众数 偏度和 或峰度 但不需要立即将所有值存储在内存中 我想计算一下基本统计数据 平均数 算术平均数 方差 与平均值的平方偏差的平均值 标准差 方差的平方根 中位数 将较大的一半数字与较小的一半数字分开的
  • 如何使用CSS设置缩放级别

    我一直在开发我的网络应用程序 在 Firefox 上使用我最初设置的特定缩放级别 使用 ctrl wheel 现在 当在另一台 PC 上的 Firefox 上进行测试时 默认的 100 似乎太大了 我可以使用CSS设置默认值吗 div st
  • 如何正确处理startForegrounds的两个通知

    我有一个上传文件的 IntentService 一切正常 但我对如何处理通知有点困惑 当我开始使用通知时startForeground 因为文件可能相当大 除非绝对必要 否则我不希望上传被终止 当我使用startForeground 它在通
  • 如何在 docker compose 版本 3 中指定内存和 CPU 限制

    我无法为版本 3 中指定的服务指定 CPU 和内存限制 对于版本 2 它可以正常工作mem limit cpu shares服务下的参数 但使用版本 3 时失败 将它们放在deploy除非我使用群体模式 否则该部分似乎不值得 有人可以帮忙吗
  • 在 ASP.NET Core 中使用 reloadOnChange 重新加载选项

    在我的 ASP NET Core 应用程序中 我将 appsettings json 绑定到强类型类应用程序设置 public Startup IHostingEnvironment environment var builder new
  • PHP json 编码 - 格式错误的 UTF-8 字符,可能编码不正确[重复]

    这个问题在这里已经有答案了 我在用着json encode data 到一个数据数组 有一个字段包含俄语字符 我用过这个mb detect encoding 显示该字段的编码 它显示 UTF 8 我认为 json 编码失败是因为其中有一些坏
  • 获取最后访问的页面

    我需要知道访问我网站的人是否来自另一个特定网站 例子 用户 A 访问 www youtube com myvideo 并点击我网站的链接 用户B访问google 搜索我的网站并点击链接 我的页面上的结果消息 User A Welcome Y
  • 使用 PDO 准备语句在 MySQL 中插入 BIT 值

    如何使用 PDO 准备语句在 MySQL 中插入 BIT 值 以下是我的尝试和结果
  • 更改了 php.ini 中的 upload_max_filesize 但 phpinfo 没有显示更改

    基本上phpinfo说upload max filesize是2M 但我在php ini文件中将其更改为8M 我正在使用MAMP 所以我重新启动MAMP phpinfo仍然显示2M 我检查了 phpinfo 显示的 php ini 文件的路
  • 给出正确的用户名和密码,得到 ORA-01017: invalid username/password;登录被拒绝

    我在tomcat的server xml中有oracle数据库配置
  • 流输出被截断为最后 5000 行

    Google Colab 输出被截断 我查看了设置 没有发现任何限制 解决问题的最佳选择是什么 我遇到了同样的问题 并通过将输出写入驱动器上的文件来管理它 from google colab import drive drive mount
  • Java 连接字符串和数字

    为什么这些情况下的输出不同 int x 20 y 10 System out println printing x y gt 印刷 2010年 System out println printing x y gt 印刷 200 为什么第一个
  • PHP proc_open 是否会阻止 Web 请求?

    默认情况下 在 Linux 上 通过 proc open 创建进程是否会使 PHP 脚本在生成的进程终止之前不会终止 我不想这样做 所以我立即关闭了进程句柄 proc open 本身不会阻塞 这一点很清楚 但是整个 HTTP 请求的执行情况