PHP cURL,写入文件

Rya*_*yan 14 php curl

我想尝试连接到远程文件并将输出从那里写入本地文件,这是我的功能:

function get_remote_file_to_cache()
{

$the_site="http://facebook.com";

    $curl = curl_init();
    $fp = fopen("cache/temp_file.txt", "w");
    curl_setopt ($curl, CURLOPT_URL, $the_site);
    curl_setopt($curl, CURLOPT_FILE, $fp);

    curl_setopt($curl,  CURLOPT_RETURNTRANSFER, TRUE);


    curl_exec ($curl);



    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    if($httpCode == 404) {
        touch('cache/404_err.txt');
    }else
    {

    touch('cache/'.rand(0, 99999).'--all_good.txt');
    }


    curl_close ($curl);
}
Run Code Online (Sandbox Code Playgroud)

它在"cache"目录中创建了两个文件,但问题是它没有将数据写入"temp_file.txt",为什么会这样?

谢谢!
[R

dou*_*lix 25

实际上,使用fwrite是部分正确的.为了避免大文件的内存溢出问题(超过PHP的最大内存限制),您需要设置一个回调函数来写入该文件.

注意:我建议专门创建一个类来处理文件下载和文件句柄等,而不是使用全局变量,但是对于本示例的目的,下面显示了如何启动和运行.

所以,请执行以下操作:

# setup a global file pointer
$GlobalFileHandle = null;

function saveRemoteFile($url, $filename) {
  global $GlobalFileHandle;

  set_time_limit(0);

  # Open the file for writing...
  $GlobalFileHandle = fopen($filename, 'w+');

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_FILE, $GlobalFileHandle);
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_USERAGENT, "MY+USER+AGENT"); //Make this valid if possible
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); # optional
  curl_setopt($ch, CURLOPT_TIMEOUT, -1); # optional: -1 = unlimited, 3600 = 1 hour
  curl_setopt($ch, CURLOPT_VERBOSE, false); # Set to true to see all the innards

  # Only if you need to bypass SSL certificate validation
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

  # Assign a callback function to the CURL Write-Function
  curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curlWriteFile');

  # Exceute the download - note we DO NOT put the result into a variable!
  curl_exec($ch);

  # Close CURL
  curl_close($ch);

  # Close the file pointer
  fclose($GlobalFileHandle);
}

function curlWriteFile($cp, $data) {
  global $GlobalFileHandle;
  $len = fwrite($GlobalFileHandle, $data);
  return $len;
}
Run Code Online (Sandbox Code Playgroud)

您还可以创建一个进度回调来显示您下载的速度/速度,但这是另一个例子,因为在输出到CLI时它可能很复杂.

从本质上讲,这将下载每个数据,并立即将其转储到文件中,而不是先将ENTIRE文件下载到内存中.

这样做更安全!当然,您必须确保URL正确(将空格转换为%20等)并且本地文件是可写的.

干杯,詹姆斯.

  • 在现代PHP中,可以通过以下方式使其变得更紧凑:"curl_setopt($ ch,CURLOPT_WRITEFUNCTION,function($ cp,$ data)use($ fp){return fwrite($ fp,$ data);});" (其中"$ GlobalFileHandle"变为"$ fp")?它似乎对我有用,但我想检查行为是否相同. (6认同)

sti*_*til 17

让我们尝试发送GET请求http://facebook.com:

$ curl -v http://facebook.com
* Rebuilt URL to: http://facebook.com/
* Hostname was NOT found in DNS cache
*   Trying 69.171.230.5...
* Connected to facebook.com (69.171.230.5) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: facebook.com
> Accept: */*
> 
< HTTP/1.1 302 Found
< Location: https://facebook.com/
< Vary: Accept-Encoding
< Content-Type: text/html
< Date: Thu, 03 Sep 2015 16:26:34 GMT
< Connection: keep-alive
< Content-Length: 0
< 
* Connection #0 to host facebook.com left intact

发生了什么?似乎Facebook将我们重定向http://facebook.com到安全https://facebook.com/.注意什么是响应体长:

Content-Length: 0

这意味着将写入零字节xxxx--all_good.txt.这就是文件保持空白的原因.

您的解决方案绝对正确:

$fp = fopen('file.txt', 'w');
curl_setopt($handle, CURLOPT_FILE, $fp);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
Run Code Online (Sandbox Code Playgroud)

您需要做的就是将URL更改为https://facebook.com/.

关于其他答案:

  • @JonGauthier:没有,没有必要使用fwrite()curl_exec()
  • @doublehelix:不,你不需要CURLOPT_WRITEFUNCTION将内容复制到文件这么简单的操作.
  • @ScottSaunders:touch()如果不存在,则创建空文件.我认为这是OP的意图.

说真的,三个答案和每个答案都是无效的?


Jon*_*ier 10

您需要使用显式写入文件fwrite,并将其传递给您之前创建的文件句柄:

if ( $httpCode == 404 ) {
    ...
} else {
    $contents = curl_exec($curl);
    fwrite($fp, $contents);
}

curl_close($curl);
fclose($fp);
Run Code Online (Sandbox Code Playgroud)

  • 您将遇到大文件的内存限制.通过doublehelix检查响应,它更安全. (4认同)

小智 5

在你的问题中,你有

    curl_setopt($curl, CURLOPT_FILE, $fp);

    curl_setopt($curl,  CURLOPT_RETURNTRANSFER, TRUE);
Run Code Online (Sandbox Code Playgroud)

但是来自 PHP 的 curl_setopt 文档说明...

It appears that setting CURLOPT_FILE before setting CURLOPT_RETURNTRANSFER doesn't work, presumably because CURLOPT_FILE depends on CURLOPT_RETURNTRANSFER being set.

So do this:

<?php
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FILE, $fp);
?>

not this:

<?php
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
?>
Run Code Online (Sandbox Code Playgroud)

...声明“ CURLOPT_FILE 取决于设置的 CURLOPT_RETURNTRANSFER ”。

参考:https : //www.php.net/manual/en/function.curl-setopt.php#99082