PHP Exec() 后的 StdErr

发布于 2024-08-22 11:02:26 字数 163 浏览 9 评论 0原文

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

$url = exec('report');

但是,我想检查 stderr,是否出现问题。我将如何读取流? 我想使用 php://stderr,但我不知道如何使用它。

In PHP I am executing a command with exec(), and it returns if successful an URL;

$url = exec('report');

However, I want to check stderr, if something went wrong. How would I read the stream?
I want to use php://stderr, but I am not sure how to use it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

辞取 2024-08-29 11:02:26

如果您想执行命令,并同时获取 stderrstdout,而不是“合并”,解决方案可能会使用 proc_open,它提供了对正在执行的命令的高级控制 - 包括一种管道stdin/stdout/stderr的方法。

这是一个例子:让我们考虑一下 test.sh 中有这个 shell 脚本,它写入 stderrstdout

#!/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;

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

$descriptorspec = [
   0 => ["pipe", "r"],  // stdin
   1 => ["pipe", "w"],  // stdout
   2 => ["pipe", "w"],  // stderr
];

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

$process = proc_open('./test.sh', $descriptorspec, $pipes, dirname(__FILE__), null);

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

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

$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);

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

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

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

我们执行 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
"

If you want to execute a command, and get both stderr and stdout, not "merged", a solution would probably to use proc_open, which provides a great level of control over the command that's being executed -- including a way to pipe stdin/stdout/stderr.

And here is an example : let's consider we have this shell-script, in test.sh, which writes to both stderr and 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;

Now, let's code some PHP, in temp.php -- first, we initialize the i/o descriptors :

$descriptorspec = [
   0 => ["pipe", "r"],  // stdin
   1 => ["pipe", "w"],  // stdout
   2 => ["pipe", "w"],  // stderr
];

And, then, execute the test.sh command, using those descriptors, in the current directory, and saying the i/o should be from/to $pipes :

$process = proc_open('./test.sh', $descriptorspec, $pipes, dirname(__FILE__), null);

We can now read from the two output pipes :

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

$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);

And, if we output the content of those two variables :

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

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

We get the following output when executing the temp.php script :

$ 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
"
初心未许 2024-08-29 11:02:26

一个可能有用的小功能:

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);
}

返回退出代码,如果需要的话,STDOUT 和 STDERR 是参考参数。

A little function that might be helpful:

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);
}

The exit code is returned and STDOUT and STDERR are reference params if you need them.

无力看清 2024-08-29 11:02:26

使用 exec 执行此类操作的简短方法是返回退出代码(命令的状态)

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

exec('ls /non-dir/', $out, $retval);
var_dump($retval);

输出

ls: 无法访问“/non-dir/”: 没有这样的文件或目录
整数(2)

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

要消除列出无效路径的错误ls:无法访问'/non-dir/':没有这样的文件或目录,您可以将stderr重定向到null,

exec('ls /non-dir/ 2>/dev/null', $out, $retval);
var_dump($retval);

这将输出:

整数(2)

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

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

这将输出以下内容:

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

The short way to do such a things with exec is to return the exit code ( status of the command )

Note that I am trying to list a non-exists directory /non-dir/

exec('ls /non-dir/', $out, $retval);
var_dump($retval);

Output

ls: cannot access '/non-dir/': No such file or directory
int(2)

Normally in unix-based system most of successful statuses codes is ( 0 ) so you can check your $retval to know the status of the command.

to dismiss the error from listing an invalid path ls: cannot access '/non-dir/': No such file or directory you can redirect your stderr to null

exec('ls /non-dir/ 2>/dev/null', $out, $retval);
var_dump($retval);

this will output :

int(2)

also if you need the error string to use it in any scenario you may redirect your stderr to the stdout.

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

this will output the following:

Array
(
    [0] => ls: cannot access '/non-dir/': No such file or directory
)
int(2)
以可爱出名 2024-08-29 11:02:26

取消合并 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);

如果您想忽略 stdout 并仅获取 stderr,您可以尝试以下操作:

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

Another way to get unmerged 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);

If you want to ignore stdout and get only stderr, you can try this:

exec("wget -O - http://www.youtube.com 2>&1 >/dev/null", $r_stderr);
ま柒月 2024-08-29 11:02:26
exec("{$command} 2>&1"
    ,$output
    ,$exitCode
    );
  • 2>&1 将 stderr 重定向到 stdout,以获得一致的成功/失败行为。

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

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

exec("{$command} 2>&1"
    ,$output
    ,$exitCode
    );
  • 2>&1 redirects stderr to stdout for consistent success / fail behaviour.

  • $exitCode determines $command completion status.

  • $output contains all output associated with $exitCode.

じее 2024-08-29 11:02:26

有点丑但是足够好了。将 stderr 放入临时文件中并将其读回。

$tmp = tempnam("/tmp", "ERR_");
exec('report 2> ' . escapeshellarg($tmp), $stdout, $retcode);
$stderr = file_get_contents($tmp);
unlink($tmp);
if ($retcode == 0)
{
    // good
    $url = $stdout[0];
} else {
    // bad
    error_log("FAIL: $stderr");
}

Slightly ugly but good enough. Put the stderr into a temp file and read it back.

$tmp = tempnam("/tmp", "ERR_");
exec('report 2> ' . escapeshellarg($tmp), $stdout, $retcode);
$stderr = file_get_contents($tmp);
unlink($tmp);
if ($retcode == 0)
{
    // good
    $url = $stdout[0];
} else {
    // bad
    error_log("FAIL: $stderr");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文