PHP cURL,读取远程文件并将内容写入本地文件
我想连接到远程文件并将远程文件的输出写入本地文件,这是我的功能:PHP cURL,读取远程文件并将内容写入本地文件,php,curl,php-curl,Php,Curl,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, $th
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);
}
它会在“cache”目录中创建两个文件,但问题是它不会将数据写入“temp_file.txt”,这是为什么?您需要使用显式写入文件,并将您先前创建的文件句柄传递给它:
if ( $httpCode == 404 ) {
...
} else {
$contents = curl_exec($curl);
fwrite($fp, $contents);
}
curl_close($curl);
fclose($fp);
touch()
函数对文件内容没有任何作用。它只是更新修改时间。看看。实际上,使用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;
}
您还可以创建一个进度回调来显示下载的速度,但这是另一个示例,因为输出到CLI时可能会比较复杂
从本质上讲,这将获取下载的每个数据块,并立即将其转储到文件中,而不是首先将整个文件下载到内存中
这样做更安全!
当然,您必须确保URL是正确的(将空格转换为%20等),并且本地文件是可写的
干杯,
James。让我们尝试将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
这意味着零字节将被写入xxxx--all_good.txt
。这就是文件保持为空的原因
您的解决方案绝对正确:
$fp = fopen('file.txt', 'w');
curl_setopt($handle, CURLOPT_FILE, $fp);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
您只需将URL更改为https://facebook.com/
关于其他答复:
- @JonGauthier:不,不需要在
curl\u exec()之后使用
fwrite()
- @doublehelix:不,您不需要使用
来执行将内容复制到文件的简单操作CURLOPT\u WRITEFUNCTION
- @ScottsUnders:
如果文件不存在,则创建空文件。我认为这是行动的意图touch()
说真的,三个答案都是无效的?为了避免内存泄漏问题: 我也遇到了这个问题。说起来真的很愚蠢,但解决办法是在CURLOPT_文件之前设置CURLOPT_RETURNTRANSFER 似乎CURLOPT_文件依赖于CURLOPT_RETURNTRANSFER
$curl = curl_init();
$fp = fopen("cache/temp_file.txt", "w+");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FILE, $fp);
curl_setopt($curl, CURLOPT_URL, $url);
curl_exec ($curl);
curl_close($curl);
fclose($fp);
在你的问题中,你有
curl_setopt($curl, CURLOPT_FILE, $fp);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
但是从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);
?>
在设置CURLOPT_RETURNTRANSFER之前设置CURLOPT_文件似乎不起作用,可能是因为CURLOPT_文件取决于正在设置的CURLOPT_RETURNTRANSFER。
这样做:
不是这个:
…声明“CURLOPT\u文件取决于设置的CURLOPT\u RETURNTRANSFER”
参考资料:我不认为你可以在同一个操作中设置
CURLOPT_FILE
和CURLOPT_RETURNTRANSFER
。在现代PHP中,这可以通过“curl_setopt($ch,CURLOPT_WRITEFUNCTION,function($cp,$data)use($fp){return fwrite($fp,$data);”(其中“$GlobalFileHandle”变成“$fp”)来简化吗?它似乎对我有效,但我想检查行为是否相同。指定CURLOPT_文件时不需要回调。我刚试过。它直接写入文件,而不首先将整个内容读入内存。请尝试指向此文件。您将看到已达到硬内存限制<代码>致命错误:允许的内存大小134217728字节已用尽(尝试分配65015808字节)请记住,不同的环境每个进程将有不同的默认内存限制。这在Windows/Linux之间也有所不同。对于大文件,您将遇到内存限制。请检查doublehelix的响应,这样更安全。@JonGauthier这并不能解决您的内存限制问题,您希望避免将整个文件加载到内存,而只想将其转储到本地文件。请在本页上投票选出唯一正确的答案:在OP发布的代码中,cURL代码是正确的,除了RETURNTRANSFER
选项在FILE
选项之后。在这种情况下,cURL忽略FILE
选项,下载的文件作为响应返回。这就是为什么关于使用fwrite
的所有其他答案看起来都像是可行的解决方案,因为它们是从FILE
选项失败开始的,并且在响应中处理文件(这也是它们必须处理内存错误的原因)。你是对的,就这么简单。只需记住提前创建“file.txt”,并设置其权限(例如777)。不要将权限设置为777,将所有权限授予所有人会带来安全风险。尽量不要像安德烈所说的那样将CURLOPT_RETURNTRANSFER与CURLOPT_文件一起使用。我得到了302个返回码,我只使用CURLOPT_文件尝试了CURLOPT_FOLLOWLOCATION,现在没有空文件,我将数据写入文件。我必须删除curl_setopt($handle,CURLOPT_RETURNTRANSFER,true)
使其工作。请注意,即使在使用curl\u setopt\u数组
时也是如此-您必须在数组中的CURLOPT\u文件
之前列出CURLOPT\u RETURNTRANSFER
。您根本不需要CURLOPT\u RETURNTRANSFER。CURLOPT_RETURNTRANSFER将返回值设置为单个字符串;CURLOPT_文件改变了这种行为,它不再将返回值存储为单个字符串,而是在运行时打印到文件中。这就是为什么在CURLOPT_RETURNTRANSFER之后使用CURLOPT_文件的原因。。。但事实上你根本不需要转车。Thx@ATJ!我试试看。我注意到这种行为,但没有得到正确的解释。
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);
?>