web-dev-qa-db-ja.com

HTTPS経由でfile_get_contentsまたはcURLを実行できません

私は何年もの間、サイトのコンテンツを取得するためにfile_get_contentsを使用しています。

最近、URLを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で試しましたが、役に立ちませんでした。

次に、暗号化を完全に無視するためにcURLを使用して このソリューション を試しましたが、役に立ちませんでした

どのソリューションを試しても、nothingは返されません。

this のようにextension=php_openssl.dllallow_url_include = OnPHP.ininot追加しましたこの特定のサイトは共有ホスト上にあり、ホスティング会社はPHP.iniファイルの編集を許可していませんが、デフォルトですでに有効になっている場合があります。

他のHTTPSサイトを試しましたが、機能するものと機能しないものがありますが、その理由はわかりません。

同じウェブホスト上の別のサーバー(および別のIP)から試しましたが、ターゲットのHTTPSサイトでも機能しませんでした。

これをデバッグして修正するにはどうすればよいですか?

更新:

phpinfoは示しています:

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

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

11
ProgrammerGirl

最終回答

ISPがopenSSLをTLS1.2にアップグレードしない場合は、別のISPを真剣に検討する必要があります。以下の「SSLSERVERTEST」リンクを使用してサーバーをテストする必要があります。サーバーにSSLセキュリティの脆弱性がある可能性があります。

接続しようとしているサーバーは、TLS1.2とTLS1.1のみをサポートしています
サポートしていません:TLS 1.0、SSL 3、SSL2。

SSL要求が行われると、SSLプロトコルの一部として、curlは暗号のリストをホストサーバーに提示します。次に、サーバーは、curlによって提示されたリストに基づいて、使用する暗号プロトコルを選択します。

あなたが続けようとしているホストは、これらの暗号スイートをサポートしています

_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をテストする必要があります SSL SERVER TEST

サーバーがTLS1.1をサポートしている場合は、次のことを試すことができます。古いサーバーでopenSSLのバージョンを使用しているのと同じバージョンのcurlがないため、これをテストできません。

CurlオプションCURLOPT_SSL_CIPHER_LISTを使用して、ホストサーバーがTLS1.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で取得できることはわかっています。

ブラウザの場合とまったく同じようにリクエストを作成します。インスペクターの[ネットワーク]タブに移動し、リクエストヘッダーを編集してコピーし、コードに貼り付けます。

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_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が失敗した場合、このコードは失敗した理由を示します。

URLを変更します。これはクライアントに属しています。

_<?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();
?>  
_

CurlセクションとopenSSLが必要です。

enter image description here

phpinfo openSSL

_--------------------------------------------------------------------_

更新2

グッドニュース

私は問題を知っており、あなたが得たエラーを再現することができました。

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

注xxxはあなたが私に与えたリンクからのサイトでした、あなたは今そのメッセージを削除することができます。

面白いことに、更新しないサーバーが1つあります。そして運が良ければ、2008年7月から同じバージョンのopenSSLがありました。

OpenSSLをアップグレードする必要があります。また、file_get_contents()はこのサーバーでも失敗しました。 2013年2月バージョンのopenSSLと2014年6月に動作しました。

OpenSSLを使用する関数をアップグレードする必要がある(またはしない)など、他にアップグレードが必要かどうかはわかりません。

それが壊れていなければ私は格言を使いますそれを修正しないでください。一部のアップグレードは実際にはダウングレードだと思います。私はまだXPを使用しています。しかし、それは壊れていて、あなたはそれを修正する必要があります。

少なくとも、それは暗い修正でのショットではありません。アップグレードする必要があると確信しています。エラーを再現することができたのは、系統だったトラブルシューティング手順でした。 file_get_contents()の使用に戻ることもできます。

2
Misunderstood

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');

UPDATE 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

1
EaBangalore

証明書とホストを検証せずに、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);
0
powtac

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));
0
peiiion

nothingが空の応答本文を意味する場合、httpSの問題のようには聞こえません。もしそうなら、curl_execは文句を言い、curl_exec()はbool(false)を返し、curl_error()はSSLの問題を示します。

_How can I debug and fix this?_

有効な応答を受け取ったときにブラウザから送信されたリクエストを調査し(ブラウザの開発者ツールを使用します。たとえば、GoogleChromeのCtrl + shift + iの[ネットワーク]タブ)、curlから送信されたリクエストと比較します。無効な応答が返され(これにはCURLOPT_VERBOSEを使用)、ブラウザーが送信するすべてのヘッダーを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つのリクエストが区別できなくなるまで、これを続けます。途中で、カールがブロックされる違いを見つけることができます。

私の賭けはuser-agentヘッダーにあります。

0
hanshenrik

SSLバージョンの問題のように見えるので、CURLOPT_SSL_VERIFYPEERを使用してCURLを無視するように設定できます。

これはあなたが投稿したURLで動作するスクリプトです

$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);
0
Iñaki Soria