Exec()之后的PHP StdErr

mar*_*tin 49 php exec stderr

在PHP中,我正在使用exec()执行命令,如果成功了URL则返回;

$url = exec('report');
Run Code Online (Sandbox Code Playgroud)

但是,如果出现问题,我想检查stderr.我怎么读这个流?我想使用php:// stderr,但我不知道如何使用它.

Pas*_*TIN 70

如果你想执行一个命令,并获得两者stderrstdout不是"合并",那么解决方案可能会使用proc_open,这提供了对正在执行的命令的高级控制 - 包括管道stdin/ stdout/的方法stderr.

这里有一个例子:让我们考虑一下这个shell脚本test.sh,它写入两者stderr并且stdout:

#!/bin/bash

echo 'this is on stdout';
echo 'this is on stdout too';

echo 'this is on stderr' >&2;
echo 'this is on stderr too' >&2;
Run Code Online (Sandbox Code Playgroud)

现在,让我们编写一些PHP代码,temp.php首先,我们初始化i/o描述符:

$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin
   1 => array("pipe", "w"),  // stdout
   2 => array("pipe", "w"),  // stderr
);
Run Code Online (Sandbox Code Playgroud)

然后,test.sh在当前目录中使用这些描述符执行命令,并说i/o应该来自/到$pipes:

$process = proc_open('./test.sh', $descriptorspec, $pipes, dirname(__FILE__), null);
Run Code Online (Sandbox Code Playgroud)

我们现在可以从两个输出管道中读取:

$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);

$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
Run Code Online (Sandbox Code Playgroud)

而且,如果我们输出这两个变量的内容:

echo "stdout : \n";
var_dump($stdout);

echo "stderr :\n";
var_dump($stderr);
Run Code Online (Sandbox Code Playgroud)

执行temp.php脚本时,我们得到以下输出:

$ php ./temp.php
stdout :
string(40) "this is on stdout
this is on stdout too
"
stderr :
string(40) "this is on stderr
this is on stderr too
"
Run Code Online (Sandbox Code Playgroud)

  • 使用它时,请确保在清洁工作完成后全部使用proc_close. (4认同)
  • @BriceFavre他把它放在一个进程var中,以便以后可以用proc_close关闭它,proc_close也会返回进程退出的返回码.`$ returnCode = proc_close($ process);` (4认同)

mpe*_*pen 41

一个可能有用的小功能:

function my_shell_exec($cmd, &$stdout=null, &$stderr=null) {
    $proc = proc_open($cmd,[
        1 => ['pipe','w'],
        2 => ['pipe','w'],
    ],$pipes);
    $stdout = stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    $stderr = stream_get_contents($pipes[2]);
    fclose($pipes[2]);
    return proc_close($proc);
}
Run Code Online (Sandbox Code Playgroud)

如果需要,退出退出代码并且STDOUT和STDERR是参考参数.

  • 有点令人惊讶的是他们还没有在 PHP 中实现这样的东西。 (5认同)

has*_*san 7

做这样的事情的简短方法exec是返回退出代码(命令的状态)

请注意,我正在尝试列出一个不存在的目录 /non-dir/

exec('ls /non-dir/', $out, $retval);
var_dump($retval);
Run Code Online (Sandbox Code Playgroud)

输出

ls: 无法访问 '/non-dir/': 没有这样的文件或目录
int(2)

通常在基于 unix 的系统中,大多数成功的状态代码是 ( 0 ),因此您可以检查$retval以了解命令的状态。

要消除列出无效路径的错误,ls: cannot access '/non-dir/': No such file or directory您可以将stderr重定向到 null

exec('ls /non-dir/ 2>/dev/null', $out, $retval);
var_dump($retval);
Run Code Online (Sandbox Code Playgroud)

这将输出:

整数(2)

此外,如果您需要错误字符串在任何情况下使用它,您可以将您的stderr重定向到stdout

exec('ls /non-dir/ 2>&1', $out, $retval);
print_r($out);
var_dump($retval);
Run Code Online (Sandbox Code Playgroud)

这将输出以下内容:

Array
(
    [0] => ls: cannot access '/non-dir/': No such file or directory
)
int(2)
Run Code Online (Sandbox Code Playgroud)


Li-*_* Wu 6

获得未合并的stdout/stderr的另一种方法.

$pp_name = "/tmp/pp_test";
@unlink($pp_name);
posix_mkfifo($pp_name, 0777);
$pp = fopen($pp_name, "r+");
stream_set_blocking($pp, FALSE);
exec("wget -O - http://www.youtube.com 2>$pp_name", $r_stdout);
$r_stderr = stream_get_contents($pp);
var_dump($r_stderr);
fclose($pp);
unlink($pp_name);
Run Code Online (Sandbox Code Playgroud)

如果你想忽略stdout并只获得stderr,你可以试试这个:

exec("wget -O - http://www.youtube.com 2>&1 >/dev/null", $r_stderr);
Run Code Online (Sandbox Code Playgroud)


Pan*_*cho 6

exec("{$command} 2>&1"
    ,$output
    ,$exitCode
    );
Run Code Online (Sandbox Code Playgroud)
  • 2>&1将 stderr 重定向到 stdout 以实现一致的成功/失败行为。

  • $exitCode确定$command完成状态。

  • $output包含与$exitCode关联的所有输出。