【问题标题】:PHP: Outputting the system / Shell_exec command output in web browserPHP:在 Web 浏览器中输出系统 / Shell_exec 命令输出
【发布时间】:2013-12-13 10:48:42
【问题描述】:


我尝试使用 shell_exec 以与终端中显示类似的方式(同时)在网页上输出一个简单的 ping 命令;但它仅在完全执行后显示,而我需要它在终端上显示时显示,

我的代码是

<?php
$i= shell_exec("ping -c 4 google.com");
echo "<pre> $i <pre>";
?>

等了一会儿,一枪把整个东西都转储了..PHP可以识别每一行的输出并显示在网页上

编辑
我也试过了

    <?php
    $proc = popen("ping -c 4 google.com", 'r');
    echo '<pre>';
    while (!feof($proc)) {
        echo fread($proc, 4096);
    }
    echo '</pre>';
    ?>

但我仍然得到相同的结果..

编辑
当我尝试在终端中执行此 PHP 代码时,(php test.php)它以与我们直接在服务器上执行 ping 时相同的方式正常工作。但在网页上还是一样。

【问题讨论】:

  • shell_exec 在命令完成之前不会返回。它不可能触发命令,然后让执行继续到 echo 命令。你可能会 popen() 然后 fread 在一个循环中抓取可用的行。
  • @MarcB所以这应该是这样做的方法!能详细点吗?
  • @MarcB 我已经编辑了我的问题,我用 popen 和 fread 尝试了上面的代码,但它也给了我相同的输出?我做错了什么?
  • 这可能不仅是一步一步获取信息的问题,还可能是输出到浏览器的问题——请查看刷新输出缓冲区。这是一个相当复杂的主题,因为这里有多种因素在起作用——PHP 的输出缓冲,也可能是 Web 服务器的缓冲……最后但并非最不重要的一点是,浏览器是否希望在收到部分信息后立即显示。
  • @CBroe 正如我在编辑中提到的,我能够通过命令行执行这个 php 程序并获得所需的输出,但正如你所提到的,它在进入网页时会导致问题。有没有办法解决这个问题??

标签: javascript php


【解决方案1】:

嗯,来自网络浏览器的奇怪行为。我正在使用此代码:

<?php
ob_end_flush();
ini_set("output_buffering", "0");
ob_implicit_flush(true);

function pingtest()
{
    $proc = popen("ping -c 5 google.com", 'r');
    while (!feof($proc))
    {
        echo "[".date("i:s")."] ".fread($proc, 4096);
    }
}

?>
<!DOCTYPE html>
<html>
<body>
  <pre>
Immediate output: 
<?php
pingtest();
?>
  </pre>
</body>
</html>

在浏览器中,内容会在收到所有字节后出现。 但是,内容实际上是按时交付的,做这个测试:

wget -O - -q "http://localhost/ping.php"

你会看到响应是由php & apache2按时传递的。

我在长任务上使用这种执行方式有一段时间了,但使用了更复杂的解决方案:

  • 接口的html文件
  • 一个运行长任务的 php 文件
  • 使用EventSource对象连接html接口和php长执行(在html5上可用)

界面(test.html)

<!DOCTYPE html>
<html>
<head>
    <title>Simple EventSource example</title>
</head>
<body>
    <script type="text/javascript">
    function eventsourcetest() {
        var ta = document.getElementById('output');
        var source = new EventSource('test.php');
        source.addEventListener('message', function(e) {
            if (e.data !== '') {
               ta.value += e.data + '\n';
            }
        }, false);
        source.addEventListener('error', function(e) {
            source.close();
        }, false);
    }
    </script>
    <p>Output:<br/><textarea id="output" style="width: 80%; height: 25em;"></textarea></p>
    <p><button type="button" onclick="eventsourcetest();">ping google.com</button>
</html>

服务器端组件(test.php)

<?php
ob_end_flush();
ini_set("output_buffering", "0");
ob_implicit_flush(true);
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

function echoEvent($datatext) {
    echo "data: ".implode("\ndata: ", explode("\n", $datatext))."\n\n";
}

echoEvent("Start!");
$proc = popen("ping -c 5 google.com", 'r');
while (!feof($proc)) {
    echoEvent(fread($proc, 4096));
}
echoEvent("Finish!");

将两个文件放在网络服务器上的一个位置并输入 test.html,我认为这就是您从一开始就在寻找的内容。

【讨论】:

  • 哇,谢谢!
【解决方案2】:

使用输出缓冲和flush。您可能还想查看 Symfony 2 process component

【讨论】:

    【解决方案3】:

    这不是 PHP 的问题,或者说它是 php 和浏览器之间的共享问题。

    在 PHP 中:确保关闭输出缓冲,您可以通过在输出任何内容之前运行 ob_end_clean() 来做到这一点。

    作为this SO post suggests,您必须将输出的第一个字符串填充到 512 字节或通过 http 标头指定字符集编码。填充解决方案很可能是解决此问题的最简单方法,基本上是这样:echo(str_pad("Live Ping Test!",512));,然后开始回显fread 的结果。

    【讨论】:

      【解决方案4】:

      您可能想尝试使用 flush() 在输出就绪时刷新输出,并使用 passthru() 执行命令。

      【讨论】:

      • flush() 是关键——但根据您的网络服务器,您可能需要添加虚假字符才能使 flush() 真正刷新。
      【解决方案5】:

      Carlos C Soto 是对的,你必须使用 javascript。事件源是要走的路。基本上,它是不断调用 url 的 javascript 代码

      你可以把 ping 的输出写在一个文件里,写一个 php 脚本来读取最后一行,然后用 eventsource 调用这个脚本。

      在网络上搜索“服务器发送事件”以查找更多示例

      【讨论】:

        【解决方案6】:

        如果可以使用 apache 执行用户解决。如果您的 root 用户不同,服务器用户不同,则不允许执行命令行命令。

        【讨论】:

          【解决方案7】:

          我在我这边测试了卡洛斯的答案...

          我必须添加 flush();ob_flush();使其正常工作(都需要刷新和 ob_flush)

          喜欢这个

          <?php
          
          $proc = popen("ping -c 5 google.com", 'r');
          while (!feof($proc))
          {
              echo "[".date("i:s")."] ".fread($proc, 4096).'<br>';flush();ob_flush();
          }
          
          ?>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-11-15
            • 2013-04-28
            • 2019-02-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多