无法通过HTTPS进行file_get_contents或cURL

时间:2017-02-11 10:58:25

标签: php curl https file-get-contents

我多年来一直使用file_get_contents来抓取网站的内容。

最近,他们将网址更新为HTTPSfile_get_contents停止了工作。

我已经阅读过以前的问题并尝试过有效的解决方案,但没有任何效果。

例如,我尝试了this,它返回了以下内容:

openssl: yes http wrapper: yes https wrapper: yes wrappers: array ( 0 => 'https', 1 => 'ftps', 2 => 'compress.zlib', 3 => 'compress.bzip2', 4 => 'php', 5 => 'file', 6 => 'data', 7 => 'http', 8 => 'ftp', 9 => 'zip', )

然后我用file_get_contents尝试this solution,但无济于事。

然后我尝试使用cURLextension=php_openssl.dll完全忽略加密,但无济于事

无论我尝试哪种解决方案,都会返回没有

我根据this solution allow_url_include = OnPHP.ini添加到HTTPS,因为此特定网站位于共享主机和托管位置公司不允许编辑PHP.ini字段,但默认情况下它们可能已经启用。

我尝试了其他HTTPS个网站,有些工作,有些则没有,我不确定原因。

我尝试在同一个网络托管上使用不同的服务器(和不同的IP),但它也无法与目标curl cURL support enabled cURL Information libcurl/7.36.0 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5 libssh2/1.8.0网站一起使用。

我该如何调试和解决此问题?

更新

phpinfo显示:

openssl OpenSSL support enabled OpenSSL Version OpenSSL 0.9.8e-fips-rhel5 01 Jul 2008

{{1}}

6 个答案:

答案 0 :(得分:2)

最终答案

如果您的ISP不会将openSSL升级到TLS 1.2,您应该认真考虑另一个ISP。您应该使用下面的“SSL SERVER TEST”链接测试您的服务器。您的服务器可能存在SSL安全漏洞。

您尝试连接的服务器仅支持TLS 1.2和TLS 1.1
不支持:TLS 1.0,SSL 3,SSL2。

当发出SSL请求时,作为SSL协议的一部分,curl会向主机服务器提供密码列表。然后,服务器根据curl提供的列表选择要使用的cypher协议。

您尝试连接的主机支持这些密码套件

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)  
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)  
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x9f) 
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x9e)  
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)  
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)  
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x6b)  
TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x39) 
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027) 
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)  
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x67)  
TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x33) 
TLS_RSA_WITH_AES_256_GCM_SHA384 (0x9d) 
TLS_RSA_WITH_AES_128_GCM_SHA256 (0x9c) 
TLS_RSA_WITH_AES_256_CBC_SHA256 (0x3d) 
TLS_RSA_WITH_AES_256_CBC_SHA (0x35) 
TLS_RSA_WITH_AES_128_CBC_SHA256 (0x3c) 
TLS_RSA_WITH_AES_128_CBC_SHA (0x2f) 

因为您的openSSL于2008年7月发布,而TLSv1.2于2008年8月发布,所以您最好的是TLSv1.1

可能的临时修复,直到您升级

我对你的工作没有很高的信心

您应该使用类似SSL SERVER TEST

的内容测试您自己的服务器的SSL

如果您的服务器支持TLS1.1,那么您可以尝试以下操作。我无法测试这个,因为我在你的openSSL版本的旧服务器上没有与你相同版本的curl。

使用curl选项CURLOPT_SSL_CIPHER_LIST来限制主机服务器使用除TLS 1.1以外的任何其他内容

curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'TLSv1');
curl_setopt($ch, CURL_SSLVERSION_TLSv1_1);

如果没有,请尝试:

curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'DEFAULT');
curl_setopt($ch, CURL_SSLVERSION_TLSv1_1);

BOTTOM LINE

出于此问题的原因,您需要升级openSSL。

-------------------------------------------------------------------------


 -

以前的故障排除

以前的故障排除

我要做的第一件事就是在浏览器中关闭javascript。如果我可以使用没有javascript的浏览器检索页面,我知道我可以用PHP获得它。

我构建的请求看起来与浏览器中的完全一样。我转到Inspector的Network选项卡并编辑Request Header并将其粘贴到我的代码中。

enter image description here

enter image description here

$request = array();
$request[] = 'Host: example.com';
$request[] = 'Connection: keep-alive';
$request[] = 'Pragma: no-cache';
$request[] = 'Cache-Control: no-cache';
$request[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
$request[] = 'User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36';
$request[] = 'DNT: 1';
$request[] = 'Origin: https://example.com';
$request[] = 'Referer: https://example.com/entry/login';
$request[] = 'Accept-Encoding: gzip, deflate';
$request[] = 'Accept-Language: en-US,en;q=0.8';

初始化卷曲

$url = 'https://example.com/entry/login';
$ch = curl_init($url);

添加请求参数

curl_setopt($ch, CURLOPT_HTTPHEADER, $request);

告诉curl包含标题

curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HEADER, true);

返回回复

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

关注重定向 重定向可能是一个陷阱。您可能不必关注并分析响应。重定向通常用于设置cookie。

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_COOKIESESSION , true );

让curl处理压缩

curl_setopt($ch, CURLOPT_ENCODING,"");

设置超时参数

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT,10);
curl_setopt($ch, CURLOPT_FAILONERROR,true);

发出请求并获得响应

以下内容将提供您需要了解的有关请求的所有信息。 $ info也将包含所有重定向标头。如果重定向,则$ responseHeader将包含所有响应标头。

更新:新的完全测试代码

这可能无关紧要,因为这也适用于我的机器:

echo file_get_contents($url);

如果curl失败,此代码应该为您提供原因,以便它失败。

更改网址。此属于客户端。

<?php
header('content-type: text/plain');

$url = 'https://amxemr.com';
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_ENCODING,"");
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT,10);
curl_setopt($ch, CURLOPT_FAILONERROR,true);
curl_setopt($ch, CURLOPT_ENCODING,"");
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HEADER, true);


$data = curl_exec($ch);
if (curl_errno($ch)){
    echo 'Retreive Base Page Error: ' . curl_error($ch);
}
else {
  $info = rawurldecode(var_export(curl_getinfo($ch),true));

 // Get the cookies:

  $skip = intval(curl_getinfo($ch, CURLINFO_HEADER_SIZE)); 
  $responseHeader= substr($data,0,$skip);
  $data= substr($data,$skip);
  echo "HEADER: $responseHeader\n";
  echo "\n\nINFO: $info\n\nDATA: $data";
}  
?>

如果以上不起作用,请运行phpinfo()

<?php
phpinfo();
?>  

应该有一个卷曲部分和openSSL。

enter image description here

phpinfo openSSL

--------------------------------------------------------------------

更新两次

好消息

我知道问题,我能够复制你得到的错误。

Retreive Base Page Error: 
Unknown SSL protocol error in connection to www.xxxx.com:443 

注意xxx是您给我的链接中的网站,您现在可以删除该消息。

有趣的是,我有一台服务器我没有更新。幸运的是,它从2008年7月开始使用相同版本的openSSL。

您需要升级openSSL。此服务器上的file_get_contents()也失败了。它适用于2013年2月版本的openSSL以及2014年6月。

我不能说是否需要升级其他任何东西,就像使用openSSL的功能可能(或可能不需要)升级一样。

如果没有破坏,我会跟着格言去解决它。我相信一些升级实际上是降级。我还在使用XP。但它破了,你需要解决它。

至少它不是黑暗修复的镜头。我相信你必须升级。这是一个有条不紊的故障排除程序,能够复制您的错误。您也可以返回使用file_get_contents()

答案 1 :(得分:1)

curlcurl一起使用,您可以轻松引入https以上的任何页面。

注意这一行:

curl_setopt($ch, CURLOPT_SSLVERSION, 4);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

这是工作代码,针对twitterfacebook

进行了测试
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
//ini_set('display_errors',1);
//$crawled = [];
set_time_limit(0);// to infinity for example
ob_start();
$output;
function grabAll($url){

$ch = curl_init();

// 2. set the options, including the url
curl_setopt($ch, CURLOPT_URL,$url);
// curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// curl_setopt($ch, CURLOPT_HEADER, 0);


//curl_setopt ($ch, CURLOPT_CAINFO, "ca-cert/cacert.pem");

curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSLVERSION, 4);
//curl_setopt($ch, CURLOPT_HEADER, 1);
  curl_setopt($ch, CURLOPT_MAXREDIRS, '1L');

curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//curl_setopt($ch, CURLOPT_TIMEOUT, 400);   
//curl_setopt ($ch, CURLOPT_POST, 1);

// 3. execute and fetch the resulting HTML output
//curl_exec($ch);
$output = curl_exec($ch);
ob_flush();//Flush the data here
if ($output === FALSE) {

    echo "cURL Error: " . curl_error($ch);

}

$info = curl_getinfo($ch);



//echo 'Took ' . $info['total_time'] . ' seconds for url ' . $info['url'];


// 4. free up the curl handle
curl_close($ch);
//print_r($crawled);    


//return $output ;

echo $output;
}


grabAll('https://twitter.com/?lang=en');

更新1:使用此代码保存文件

   function grab_image($url,$saveto){
        $ch = curl_init ($url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSLVERSION, 4);
        curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
        $raw=curl_exec($ch);
        curl_close ($ch);
        if(file_exists($saveto)){
            unlink($saveto);
        }
        $fp = fopen($saveto,'x');
        fwrite($fp, $raw);
        fclose($fp);
    }






  grab_image('i.imgur.com/85wsoLI.jpg','download/');
希望这能解决你的问题!!

这是我服务器上的演示: http://54.167.121.86/curl/curl.php

答案 2 :(得分:0)

如果按nothing,则表示空响应正文,它听起来不像是httpS问题。如果是,则curl_exec会抱怨,curl_exec()将返回bool(false),curl_error()将指示SSL问题。

How can I debug and fix this?

调查您的浏览器在收到有效回复时发送的请求(使用浏览器的开发者工具进行此操作。例如,Google Chrome的Ctrl + shift + i中的“网络”标签),然后将其与发送的请求进行比较当你得到一个无效的响应时使用curl(对此使用CURLOPT_VERBOSE)和1比1,添加浏览器发送的所有头文件,

例如,您会注意到libcurl没有发送user-agent标头,而您的浏览器会发送user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36之类的内容,因此请添加该标头。 您还会注意到libcurl默认发送Accept: */*,而您的浏览器发送Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 - 所以修复它,使curl发送相同的标头。

继续这样做,直到2个请求无法区分,并且在此过程中,你会发现使卷曲被阻挡的差异。

我的赌注在用户代理标题上。

答案 3 :(得分:0)

有时它不会验证证书和主机,但只是信任SSL中的加密。

$context = stream_context_create(
    array('http' => array(
            'follow_location' => true
        ),
        'ssl' => array(
            'verify_peer' => false, 
            'verify_peer_name' => false
        )
    )
);

$content = @file_get_contents($file, FALSE, $context);

答案 4 :(得分:0)

HTTPS站点是否具有自签名证书?您能为一些有效的网站提供域名吗?有些网站没有提供域名吗?

您是否尝试在流上下文配置中使用"allow_self_signed" => true

所以它变得像:

$arrContextOptions=array(
    "ssl"=>array(
        "verify_peer"=>false,
        "verify_peer_name"=>false,
        "allow_self_signed"=>true,
    ),
);  

$response = file_get_contents($url, false, stream_context_create($arrContextOptions));

答案 5 :(得分:0)

由于看起来SSL版本存在问题,您可以使用 CURLOPT_SSL_VERIFYPEER 将CURL设置为忽略它。

这是一个使用您发布的网址的脚本

$url = 'https://XXX/YYY/view-all';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
print_r($response);