使 cURL 输出 STDERR 到文件(或字符串)

Posted

技术标签:

【中文标题】使 cURL 输出 STDERR 到文件(或字符串)【英文标题】:Make cURL output STDERR to file (or string) 【发布时间】:2012-02-10 17:35:29 【问题描述】:

我们正在尝试调试服务器上的一些 cURL 错误,我想查看 STDERR 日志。目前,我们只能看到“错误代码:7”并且我们无法连接到目标服务器。我们已经联系了主机并制定了特殊规则来打开我们需要的端口,我们甚至暂时忽略了证书。

仍然无法连接。我需要对此进行调试,但我看不到任何相关信息。

我认为,提到“VERBOSE”和“STDERR”的那几行是最重要的。没有任何内容写入 $curl_log。我究竟做错了什么?按照手册的逻辑,这应该是正确的......

php 使用中:

<?php
$curl = curl_init();
$curl_log = fopen("curl.txt", 'w');
$url = "http://www.google.com";

curl_setopt_array($curl, array(
    CURLOPT_URL             => $url,        // Our destination URL
    CURLOPT_VERBOSE         => 1,           // Logs verbose output to STDERR
    CURLOPT_STDERR          => $curl_log,   // Output STDERR log to file
    CURLOPT_SSL_VERIFYPEER  => 0,           // Do not verify certificate
    CURLOPT_FAILONERROR     => 0,           // true to fail silently for http requests > 400
    CURLOPT_RETURNTRANSFER  => 1            // Return data received from server
));

$output = fread($curl_log, 2048);
echo $output; // This returns nothing!
fclose($curl_log);

$response = curl_exec($curl);
//...restofscript...
?>

来自 PHP 手册:http://php.net/manual/en/function.curl-setopt.php

CURLOPT_VERBOSE TRUE 以输出详细信息。将输出写入 STDERR CURLOPT_STDERR 将错误输出到的替代位置,而不是 STDERR。

这也不是权限问题,我在服务器端将文件和脚本权限设置为 777,而我的本地客户端是 windows,从不关心权限设置(无论如何它只适用于开发人员)。

【问题讨论】:

脚本是否完整?我问是因为缺少curl_exec()。您期望的输出是什么(以及为什么)? 哦,是的,我在复制/粘贴中取出了它。把 curl_exec 放回去。我希望能得到一些调试信息,虽然我真的不知道能从中得到什么。我不知道是什么导致服务器端的连接失败。 你可以找到detailed code-examples in a related answer to a different question including doing this in memory and not on disk 这让我找到了实际问题在哪里description here 【参考方案1】:

我需要先关闭文件才能读取它,这对我有用:

$filename = 'curl.txt';
$curl_log = fopen($filename, 'w'); // open file for write (rw, a, etc didn't help)
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_STDERR, $curl_log);        

$result = curl_exec($ch);

fclose($curl_log);      
$curl_log = fopen($filename, 'r'); // open file for read
$output= fread($curl_log, filesize($filename));
echo $output;

(PHP 5.6.0,Apache/2.2.15)

【讨论】:

【参考方案2】:

聚会有点晚了,但是这个页面仍然在 Google 中弹出很高,所以我们走吧。

如果 CURLINFO_HEADER_OUT 也设置为 TRUE,CURLOPT_VERBOSE 似乎不会记录任何内容。

这是 PHP 中的一个已知错误 (#65348),由于某些原因,他们决定不修复它。

【讨论】:

【参考方案3】:

将以上所有答案放在一起,我使用此函数发出带有登录到文件选项的 Curl Post 请求:

function CURLPostRequest($url, array $post = NULL, array $options = array(), $log_file = NULL)
    $defaults = array(
            CURLOPT_POST => 1,
            CURLOPT_HEADER => 0,
            CURLOPT_URL => $url,
            CURLOPT_FRESH_CONNECT => 1,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_FORBID_REUSE => 1,
            CURLOPT_TIMEOUT => 4,
            CURLOPT_POSTFIELDS => http_build_query($post)
    );

    if (is_resource($log_file))
        $defaults[CURLOPT_VERBOSE]=1;
        $defaults[CURLOPT_STDERR]=$log_file;
        $defaults[CURLINFO_HEADER_OUT]=1;
    

    $ch = curl_init();
    curl_setopt_array($ch, ($options + $defaults));
    if( ! $result = curl_exec($ch))
        throw new Exception(curl_error($ch));
    

    if (is_resource($log_file))

        $info = curl_getinfo($ch);

        if (isset($info['request_header']))
            fwrite($log_file, PHP_EOL.PHP_EOL.'* POST Content'.PHP_EOL.PHP_EOL);
            fwrite($log_file, print_r($info['request_header'],true));
            fwrite($log_file, http_build_query($post));
        

        fwrite($log_file, PHP_EOL.PHP_EOL.'* Response Content'.PHP_EOL.PHP_EOL);
        fwrite($log_file, $result.PHP_EOL.PHP_EOL);
    

    curl_close($ch);
    return $result;

希望这对某人有所帮助。

【讨论】:

应该是 $defaults[CURLINFO_HEADER_OUT]=1; 启用 CURLINFO_HEADER_OUT 时不会写入详细信息【参考方案4】:

您在示例中犯了几个错误:

1) 在读取“详细日志”之前,您必须调用 curl_exec(),因为 curl_setopt() 不执行任何操作,因此在 curl_exec( )。

2)您打开$curl_log = fopen("curl.txt", 'w'); 仅用于写入,因此即使您写入文件并倒回内部文件指针,也无法读取任何内容。

所以正确的缩短代码应该是这样的:

<?php
$curl = curl_init();
$curl_log = fopen("curl.txt", 'rw'); // open file for READ and write
$url = "http://www.google.com";

curl_setopt_array($curl, array(
    CURLOPT_URL             => $url,
    CURLOPT_VERBOSE         => 1,
    CURLOPT_STDERR          => $curl_log,
    CURLOPT_RETURNTRANSFER  => 1
));

$response = curl_exec($curl);

rewind($curl_log);
$output= fread($curl_log, 2048);
echo "<pre>". print_r($output, 1). "</pre>";
fclose($curl_log);

// ...

?>

注意:详细日志可能超过 2048 字节,因此您可以在 curl_exec() 之后“关闭”$curl_log,然后使用例如 file_get_contents() 读取整个文件。 在这种情况下,这点 2) 不应被视为错误:-)

【讨论】:

【参考方案5】:

你应该放

$output = fread($curl_log, 2048);
echo $output; // This returns nothing!
fclose($curl_log);

$response = curl_exec($curl); 之后,否则在 curl 执行期间文件被关闭。

【讨论】:

【参考方案6】:

来自函数 curl_setopt 的 php 手册:

CURLOPT_FILE The file that the transfer should be written to. The default is STDOUT (the browser window).  

【讨论】:

CURLOPT_VERBOSE 声称要写入 STDERR,CURLOPT_FILE 何时输出数据? CURLOPT_FILE => $curl_log ...仍然不写入文件。

以上是关于使 cURL 输出 STDERR 到文件(或字符串)的主要内容,如果未能解决你的问题,请参考以下文章

如何将时间戳添加到 cronjob 输出的行并将 stdout 和 stderr 重定向到不同的进程和/或文件

web自动化的利器 -- cURL

exec.Command错误,没有输出到stdout或stderr

如何使 xcodebuild 向 stderr 打印编译错误和警告?

Bash CURL GET 请求输出到单个 JSON 文件,包括服务器响应和 CURL 信息

使用系统命令将stdout和stderr输出重定向到文件在perl中不起作用[重复]