PHP cURL错误的内容长度由源提供

时间:2018-04-03 17:00:35

标签: php curl content-length

使用cURL

下载图像
https://cdni.rt.com/deutsch/images/2018.04/article/5ac34e500d0403503d8b4568.jpg

将此图像从浏览器手动保存到本地PC时,系统显示的大小为139,880字节

使用cURL下载时,文件似乎已损坏,不会被视为有效图像

使用cURL下载时,其大小为139,845,低于手动下载时的大小

进一步挖掘问题,发现服务器将响应头中的内容长度返回为

content-length: 139845

此长度与cURL下载的长度相同,因此我怀疑cURL在服务器达到所谓的(可能是错误的)长度后关闭传输

有没有办法让cURL完全下载文件,即使内容长度标题错误

使用过的代码:

//curl ini
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER,0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT,20);
curl_setopt($ch, CURLOPT_REFERER, 'http://www.bing.com/');
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8');
curl_setopt($ch, CURLOPT_MAXREDIRS, 5); // Good leeway for redirections.
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // Many login forms redirect at least once.
curl_setopt($ch, CURLOPT_COOKIEJAR , "cookie.txt");

//curl get
$x='error';
$url='https://cdni.rt.com/deutsch/images/2018.04/article/5ac34e500d0403503d8b4568.jpg';
curl_setopt($ch, CURLOPT_HTTPGET, 1);
curl_setopt($ch, CURLOPT_URL, trim($url));
$exec=curl_exec($ch);
$x=curl_error($ch);

$fp = fopen('test.jpg','x');
fwrite($fp, $exec);
fclose($fp);

2 个答案:

答案 0 :(得分:1)

服务器有Accept-Encoding压缩传输机制的错误实现。 响应始终是gzip压缩的,但除非客户端在请求中有Accept-Encoding: gzip标头,否则不会告诉客户端它是gzip压缩的。当服务器没有告诉客户端它被gzip压缩时,客户端在保存之前不会对其进行gzip解压缩,从而导致您的下载损坏。告诉curl通过设置CURLOPT_ENCODING

来提供gzip压缩
curl_setopt($ch,CURLOPT_ENCODING,'gzip');

,然后服务器将告诉curl它是gzip压缩的,curl会在将它解压缩之前为你解压缩。

你应该告诉服务器管理员这个,这是他的网络服务器中的一个严重错误,破坏了下载。

答案 1 :(得分:0)

libcurl有一个名为CURLOPT_IGNORE_CONTENT_LENGTH的选项,遗憾的是这在php中本身不受支持,但你可以通过使用正确的幻数来欺骗php设置选项(至少在我的系统上)是136),

if(!defined('CURLOPT_IGNORE_CONTENT_LENGTH')){
    define('CURLOPT_IGNORE_CONTENT_LENGTH',136);
}
if(!curl_setopt($ch,CURLOPT_IGNORE_CONTENT_LENGTH,1)){
    throw new \RuntimeException('failed to set CURLOPT_IGNORE_CONTENT_LENGTH! - '.curl_errno($ch).': '.curl_error($ch));
}

您可以通过编译和运行以下c ++代码找到适合您系统的编号:

#include <iostream>
#include <curl/curl.h>
int main(){
std::cout << CURLOPT_IGNORE_CONTENT_LENGTH << std::endl;
}
  • 但可能是136。 最后,protip,file_get_contents完全忽略内容长度标题,只是继续下载,直到服务器关闭连接(这可能比curl慢得多) - 另外,你应该联系服务器运营商让他知道,出了什么问题/用他的服务器窃听。