php 执行外部 sh 脚本时冻结

php freezes when executing an external sh script

我会尝试在时间线历史中解释我的问题:

我已经尝试 运行 来自 php 的几个外部脚本,并 return 再次调用 ajax 服务器的退出代码。 单个调用应该启动或停止该机器上的服务。这在这台开发机器上运行良好。

然而,我已经将代码导出到一台更大的机器上,而且功能更强大,一切似乎都运行良好,但有一点: 单个调用会导致 php-fpm 冻结并且永远不会回来。通过详细检查,我发现该调用创建了一个我无法终止的僵尸进程(即使使用 sudo)。

唯一的解决办法似乎是停止 php-fpm 进程,而不是重新启动它。然后一切似乎再次正常工作,只要我再次尝试调用该脚本。

呼叫php线路

exec("sudo ".$script, $output, $return_var);

(所有变量都是正常的 'strings',没有特殊字符)

启动脚本

#!/bin/sh
service radicale start 2>&1

顺便说一句,服务已经启动,但每次网络服务器冻结,我不得​​不手动重新启动 php,但这是不可接受的(即使对于网络服务器)。 但只针对那个单一的脚本,只针对那个带有庄严命令(开始)的服务(radicale)。

在 Google 中搜索让我发现 php 命令 exec()[ 之间存在冲突=80=]().

链接:

https://bugs.php.net/bug.php?id=44942

https://bugs.php.net/bug.php?id=44994

他们的结论是,可以使用这样的构造来解决该错误:

...
session_write_close();
exec("sudo ".$script, $output, $return_var);
session_start();
...

但是,在我看来,这不是调试,而是一种无奈的解决方法,因为您失去了让用户知道他的操作已经完全起作用的功能,但更多的是让他相信发生了错误。更令人困惑的是,它 运行 完全在 Raspberry Pi A 上,而不是在具有更大 CPU 和 8 GB RAM 的 64 位机器上。

那么有没有 真正的解决方案 或这个解决方法是解决该问题的唯一方法?我读过一篇关于 php 有一些 exec/shell_exec 的问题以及对 return 值的识别的文章?怎么会丢呢?有人猜吗?

谢谢你阅读了那么长的糟糕英语,但我的母语不是英语,在我的课上也不是很好听的学生。

很可能新机器的设置方式与 Raspberry PI 的设置方式不同 -

您需要在 shell 中做一些事情才能在您的大型计算机上运行:

1).允许 php 使用 sudo。

sudo usermod -G sudo -a your-php-user

请注意,要获取 your-php-user 的用户名,您只需 运行 一个脚本,上面写着:

<?php echo get_current_user(); ?> - 或者: <?php echo exec('whoami'); ?> -

2).允许该用户在没有密码的情况下使用 sudo

sudo visudo - 此命令将打开 /etc/sudoers 并带有故障保护以防止您搞砸任何事情。

将这行添加到最后:

your-php-user ALL=(ALL) NOPASSWD: /path/to/your/script,/path/to/other/script

您可以根据需要在此处放置任意数量的脚本,以逗号分隔。 现在,您的脚本应该可以正常工作了。

再次请注意,您需要将 your-php-user 更改为您的 php 用户。

希望对您有所帮助!

这不是真正的解决方案,但比 none 更好。

使用

调用 bash 脚本
<?php
...
exec("sudo ".$script, $output, $return_var);
...
?>

仅在僵尸线程中的这种特殊情况下结束。当 php-fpm 等待结果时,它仍然保持在线状态,没有放弃也没有超时,因为它的其余线程仍然存在。因此,对 php 服务器的所有其他请求仍在队列中,永远不会被处理。这对于一些长期存在或工作的线程来说可能没问题,但我的请求是在一些 [ms] 内完成的。

我没有找到原因。就我能做的调试而言,我不是触发的 Radicale 进程故障,因为它在 return 中给出了任何时间干净而勇敢的 0。似乎 php 进程无法从中获取 return 行,所以它仍在等待。

没时间了我把故障脚本改成了

#!/bin/sh
service radicale start 2>&1

#!/bin/sh
service radicale start > /dev/null 2>&1 &

...所以将每条 returning 线路发送到 nirvana 并断开所有子例程。现在服务器没有挂起并按预期工作。但这可能是 php 中的一个主要错误的感觉仍然存在于我的脑海中,希望 - 有一天 - 有人可以解决这个错误。