【问题标题】:Make cURL write data as it receives it使 cURL 在收到数据时写入数据
【发布时间】:2023-08-16 15:13:02
【问题描述】:

我找到了以下 php 代码 here:

function download_xml()
{
    $url = 'http://tv.sygko.net/tv.xml';

    $ch = curl_init($url);
    $timeout = 5;

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);

    $data = curl_exec($ch);

    echo("curl_exec was succesful"); //This never gets called

    curl_close($ch);
    return $data;
}

$my_file = 'tvdata.xml';
$handle = fopen($my_file, 'w');
$data = download_xml();
fwrite($handle, $data);

我要做的是在指定的 url 下载 xml 并将其保存到磁盘。但是,它会在大约 80% 完成后停止,并且在 curl_exec 调用之后永远不会到达 echo 调用。我不知道为什么,但我相信这是因为它的内存不足。因此,我想问是否可以让 curl 每次下载 4kb 时将数据写入文件。如果这是不可能的,有没有人知道一种方法来获取存储在 url 中的 xml 文件,使用 php 下载并存储在我的磁盘上?

非常感谢, 本。

编辑: 这是现在的代码,它不起作用。它将数据写入文件,但仍然只有大约 80% 的文件。也许不是因为它超出了内存,而是其他原因?我真的不敢相信将文件从 URL 复制到光盘这么难......

    <?

$url = 'http://tv.sygko.net/tv.xml';
$my_file = fopen('tvdata.xml', 'w');

$ch = curl_init($url);
$timeout = 300;

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FILE, $my_file);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_BUFFERSIZE, 4096);

curl_exec($ch) OR die("Error in curl_exec()");

echo("got to after curl exec");

fclose($my_file);
curl_close($ch);

    ?>

【问题讨论】:

  • 试一试:加“;” fopen 2 之后:fclose 文件
  • 和3:将超时时间增加到300秒,因为您链接到的页面很大
  • 刚看到“;”问题,我已经更新了代码。它仍然停在同一个地方(大约 80%),我现在正在尝试以 300 超时运行脚本
  • 我将超时设置为 300,但它仍然停在完全相同的位置。
  • 好吧,我一直在尝试这种可能性和其他可能性,但没有任何效果。我发现无法从 URL 下载文件令人难以置信。不过,感谢这里的所有答案。我会继续战斗,当然如果有人找到解决方案,请发布!当我找到解决方案时,我当然会在这里发布。

标签: php curl fwrite


【解决方案1】:

这里有一个完整的例子:

public function saveFile($url, $dest) {

        if (!file_exists($dest))
                touch($dest);

        $file = fopen($dest, 'w');
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progressCallback');
        curl_setopt($ch, CURLOPT_BUFFERSIZE, (1024*1024*512));
        curl_setopt($ch, CURLOPT_NOPROGRESS, FALSE);
        curl_setopt($ch, CURLOPT_FAILONERROR, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
        curl_setopt($ch, CURLOPT_FILE, $file);

        curl_exec($ch);
        curl_close($ch);

        fclose($file);
}
?>

秘密在于将 CURLOPT_NOPROGRESS 设置为 FALSE,然后,CURLOPT_BUFFERSIZE 将为每个 CURLOPT_BUFFERSIZE 字节生成回调报告。值越小,报告的频率越高。这也取决于您的下载速度等,因此不要指望它每 X 秒报告一次,因为它会为每 X 个接收/传输的字节报告一次。

【讨论】:

    【解决方案2】:

    有一个名为 CURELOPT_FILE 的选项允许您指定 curl 应该写入的文件 handler。我很确定它会做“正确”的事情并在读取时“写入”,从而避免您的记忆问题

    $file = fopen('test.txt', 'w'); //<--------- file handler
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL,'http://example.com');
    curl_setopt($ch, CURLOPT_FAILONERROR,1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 15);
    curl_setopt($ch, CURLOPT_FILE, $file);   //<------- this is your magic line
    curl_exec($ch); 
    curl_close($ch);
    fclose($file);
    

    【讨论】:

    • 我添加到我的原始帖子中。这不起作用。代码甚至没有执行,但我不知道错误在哪里。
    【解决方案3】:

    您的超时设置为 5 秒,这可能会太短,具体取决于文档的文件大小。尝试将其增加到 10-15,以确保它有足够的时间来完成传输。

    【讨论】:

      【解决方案4】:

      curl_setopt CURLOPT_FILE - 传输应该写入的文件。默认为 STDOUT(浏览器窗口)

      http://us2.php.net/manual/en/function.curl-setopt.php

      【讨论】:

      • 只是想知道:您是否碰巧知道 cURL 是否在接收到数据时将数据写入文件中,或者是否正在进行某种缓冲?
      • 即使我已经这样做了(参见第一篇文章中的代码,我对其进行了编辑),但它不起作用。