我多年来一直使用file_get_contents
来抓取网站的内容。
最近,他们将网址更新为HTTPS
,file_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,但无济于事。
然后我尝试使用cURL
与extension=php_openssl.dll
完全忽略加密,但无济于事
无论我尝试哪种解决方案,都会返回没有。
我根据this solution 不将allow_url_include = On
和PHP.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}}
答案 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);
出于此问题的原因,您需要升级openSSL。
-------------------------------------------------------------------------
-
我要做的第一件事就是在浏览器中关闭javascript。如果我可以使用没有javascript的浏览器检索页面,我知道我可以用PHP获得它。
我构建的请求看起来与浏览器中的完全一样。我转到Inspector的Network选项卡并编辑Request Header并将其粘贴到我的代码中。
$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。
--------------------------------------------------------------------
好消息
我知道问题,我能够复制你得到的错误。
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)
将curl
与curl
一起使用,您可以轻松引入https
以上的任何页面。
注意这一行:
curl_setopt($ch, CURLOPT_SSLVERSION, 4);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
这是工作代码,针对twitter
和facebook
<?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);