【问题标题】:Capture/supress all output from php exec including stderr捕获/抑制来自 php exec 的所有输出,包括 stderr
【发布时间】:2015-10-16 13:11:05
【问题描述】:

我想通过exec() 运行几个命令,但我不希望任何输出到屏幕。但是,我确实希望保留输出,以便在脚本运行时控制详细程度。

这是我的课:

<?php
class System
{
    public function exec($command, array &$output = [])
    {
        $returnVar = null;
        exec($command, $output, $returnVar);
        return $returnVar;
    }
}

问题是,大多数应用程序在stderr 中添加了大量不相关的内容,我似乎无法阻止这些内容。例如,下面是通过它运行 git clone 的输出:

Cloning into '/tmp/directory'...
remote: Counting objects: 649, done.
remote: Compressing objects: 100% (119/119), done.
remote: Total 649 (delta 64), reused 0 (delta 0), pack-reused 506
Receiving objects: 100% (649/649), 136.33 KiB | 0 bytes/s, done.
Resolving deltas: 100% (288/288), done.
Checking connectivity... done.

我看到其他问题声称使用输出缓冲区可以工作,但它似乎不起作用

<?php
class System
{
    public function exec($command, array &$output = [])
    {
        $returnVar = null;
        ob_start();
        exec($command, $output, $returnVar);
        ob_end_clean();
        return $returnVar;
    }
}

这仍然会产生相同的结果。我可以通过在命令中将 stderr 路由到 stdout 来解决问题,但是,这不仅会阻止我区分 stdout 和 stderr,而且该应用程序旨在在 Windows 和 Linux 中运行,所以这是现在一团糟。

<?php
class System
{
    public function exec($command, array &$output = [])
    {
        $returnVar = null;

        // Is Windows
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            exec($command, $output, $returnVar);
            return $returnVar;
        }

        // Is not windows
        exec("({$command}) 2>&1", $output, $returnVar);
        return $returnVar;
    }
}

有没有办法分别捕获和抑制标准错误和标准输出?

更新/回答示例

根据 cmets 中 @hexasoft 的建议,我将方法更新为如下所示:

<?php
class System
{
    public function exec($command, &$stdOutput = '', &$stdError = '')
    {
        $process = proc_open(
            $command,
            [
                0 => ['pipe', 'r'],
                1 => ['pipe', 'w'],
                2 => ['pipe', 'w'],
            ],
            $pipes
        );

        if (!is_resource($process)) {
            throw new \RuntimeException('Could not create a valid process');
        }

        // This will prevent to program from continuing until the processes is complete
        // Note: exitcode is created on the final loop here
        $status = proc_get_status($process);
        while($status['running']) {
            $status = proc_get_status($process);
        }

        $stdOutput = stream_get_contents($pipes[1]);
        $stdError  = stream_get_contents($pipes[2]);

        proc_close($process);

        return $status['exitcode'];
    }
}

这种技术开辟了更多高级选项,包括异步进程。

【问题讨论】:

  • 使用exec?因为proc_open 可能更适合您的问题。详情见php.net/manual/fr/function.proc-open.php(允许为stdin/stdout/stderr设置专用管道)
  • 不,我不必使用exec。我将对此进行探索并回复您。谢谢:)
  • 是的,这似乎工作得很好。它当然不是“更简单”,但它绝对可以满足我的一切需求。我已经更新了我的问题以显示我对该特定方法所做的确切更改,但是稍后我将设置一些更强大的东西。你想弹出一个正确的答案,我会标记为正确的。
  • 为什么不按照2&gt;/dev/null重定向stderr?
  • @mario:正如问题中所述,我最好捕获它,它必须在 *nix 和 Windows 上都可以工作。

标签: php exec stdout stderr


【解决方案1】:

命令proc_exec() 允许使用管道处理执行命令的文件描述符。

函数为:proc_open ( string $cmd , array $descriptorspec , array &amp;$pipes […optional parameters] ) : resource

你在 $cmd 中给你命令(如在exec 中),你给一个数组描述文件描述符来“安装”命令。该数组由文件描述符编号(0=stdin, 1=stdout...)索引,包含类型(文件、管道)和模式(r/w...)以及文件类型的文件名。

然后您在 $pipes 中获得一个文件描述符数组,可用于读取或写入(取决于请求的内容)。

你不应该忘记在使用后关闭这些描述符。

请参阅 PHP 手册页(尤其是示例):https://php.net/manual/en/function.proc-open.php

请注意,读/写与生成的命令有关,而不是 PHP 脚本。

【讨论】:

    猜你喜欢
    • 2010-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-09
    • 2017-05-01
    • 1970-01-01
    • 2011-04-25
    相关资源
    最近更新 更多