如何在PHP错误日志文件中获取命令行错误信息

5

我正在尝试在PHP文件中运行curl命令,并尝试将其输出列在错误日志文件中。所有PHP错误都列在文件中,除了从exec()函数获得的错误。我尝试的PHP代码是:

exec("nohup curl --output " . $_SERVER['DOCUMENT_ROOT'] . "/abc.mp3 http://192.99.8.170:8098/stream/1; --max-time $time_in_seconds > /devnull&");

我该如何在错误日志文件中获取此命令生成的错误?我已经搜索了谷歌,但是没有得到足够的结果。


2
请了解有关输出流重定向的内容。您当前忽略了命令中的错误输出。您必须将其重定向。添加一个 2 > /path/to/logfile 或者更好的是 2 > &1,它将 stderr 重定向到 stdout,从而允许 exec 调用接收它。 - arkascha
1
使用PHP时,您只能通过exec($command, &$output)的第二个参数获取标准输出。您可以将curl的标准错误输出重定向到标准输出,或者使用proc_open()代替exec() - Jan Holas
我将上面的代码替换为以下内容:exec("nohup curl --output ".$_SERVER['DOCUMENT_ROOT']."/abc.mp3 http://192.99.8.170:8098/stream/1; --max-time $time_in_seconds 2>&1 & echo $!"); 并使用 proc_open() 做了类似于这样的操作:Proc_open("nohup curl --output ".$_SERVER['DOCUMENT_ROOT']."/abc.mp3 http://192.99.8.170:8098/stream/1; --max-time $time_in_seconds", Array(), $foo); 但是它在错误文件中没有输出任何内容。请问您能否提供一个示例代码? - MKB
1个回答

1

该命令

该命令本身存在几个问题。

exec("nohup curl --output ".$_SERVER['DOCUMENT_ROOT'] . "/abc.mp3 http://192.99.8.170:8098/stream/1; --max-time $time_in_seconds > /devnull&");

(我已经为了清晰起见对原始行进行了换行。)

不需要使用 nohup

nohup 命令的主要目的是在终端线路挂起时,如果您因注销 shell 而退出,则运行进程。 (当 shell 退出时,它会向其子进程发送 SIGHUP。)使用 nohup 可以启动一个命令,然后注销 shell。

curl 命令确实在 SIGHUP 信号被终止。您可以使用 nohup 将下载进程放在后台运行。但您的目标是捕获命令的输出,无论是 STDIN 还是 STDOUT。重要的是要知道命令何时以及如何完成其工作。例如,在同步执行命令后,可以检查退出码(零表示成功),并检查文件是否实际下载到文件系统中:

$output_dir = empty($_SERVER['DOCUMENT_ROOT']) ?
'/tmp/default-download-dir' : $_SERVER['DOCUMENT_ROOT'];
if (!is_dir($output_dir)) {
  if (!mkdir($output_dir, 0755, true))
    die("Failed to create directory $output_dir");
}

$url = 'http://php.net/images/logo.php';
$output_file = "{$output_dir}/logo.svg"; ;
// 2>&1 redirects standard error descriptor (2)
// to the standard output descriptor (1)
$command = sprintf("curl -o %s %s 2>&1",
  escapeshellarg($output_file),
  escapeshellarg($url));
$output = [];
exec($command, $output, $exit_code);
if ($exit_code != 0) {
  die("Failed to download $url to $output_file");
}

clearstatcache(true, $output_file);
if (!file_exists($output_file)) {
  die("File $output_file not found on file system, command: $command");
}

echo "$url has been saved to $output_file:\n",
  implode(PHP_EOL, $output), PHP_EOL;

输出

http://php.net/images/logo.php has been saved to /tmp/default-download-dir/logo.svg:
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  2202  100  2202    0     0   4171    0 --:--:-- --:--:-- --:--:--  4665

请注意使用 escapeshellarg 函数。你应该转义所有 shell 参数,否则 shell 将解释其特殊字符。
分号 (;) 分隔的字符串被解释为不同的命令。因此,--max-time $time_in_seconds > /devnull& 被解释为第二个命令。我不知道你试图实现什么,但你很可能不需要它。
在你的 > /devnull& 表达式中有一个拼写错误。你可能意味着将重定向到伪设备 /dev/null> /dev/null
在上面的代码中,我们捕获了标准输出。如果你想将输出捕获到其他文件描述符中,请使用 proc_open() 函数:
$output_dir = empty($_SERVER['DOCUMENT_ROOT']) ?
  '/tmp/default-download-dir' : $_SERVER['DOCUMENT_ROOT'];
if (!is_dir($output_dir)) {
  if (!mkdir($output_dir, 0755, true))
    die("Failed to create directory $output_dir");
}

$url = 'http://php.net/images/logo.php';
$output_file = "{$output_dir}/logo.svg"; ;
$command = sprintf("curl -o %s %s",
  escapeshellarg($output_file),
  escapeshellarg($url));

$descriptors = [
  1 => ['pipe', 'w'], // stdout
  2 => ['pipe', 'w'], // stderr
];

$proc = proc_open($command, $descriptors, $pipes);
if (!is_resource($proc))
  die("Failed to open process for command $command");

if ($output = stream_get_contents($pipes[1]))
  echo "Output: $output\n\n";
fclose($pipes[1]);

if ($errors = stream_get_contents($pipes[2]))
  echo "Errors: >>>>>>>>\n$errors\n<<<<<<<\n\n";
fclose($pipes[2]);

$exit_code = proc_close($proc);

if ($exit_code != 0) {
  die("Failed to download $url to $output_file");
}

clearstatcache(true, $output_file);
if (!file_exists($output_file)) {
  die("File $output_file not found on file system, command: $command");
}

echo "$url\nhas been saved to $output_file\n";

输出

Errors: >>>>>>>>
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2202  100  2202    0     0   4231      0 --:--:-- --:--:-- --:--:--  4735

<<<<<<<

http://php.net/images/logo.php
has been saved to /tmp/default-download-dir/logo.svg

(curl 输出“详细”输出到标准错误描述符)

固定命令

基于前面的考虑,你的命令应该如下构建:

$url = 'http://192.99.8.170:8098/stream/1';
$command = sprintf("curl -o %s %s --max-time $time_in_seconds",
  escapeshellarg($output_file),
  escapeshellarg($url));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接