httpsで用意されているAPIにアクセスしてJSON形式の情報を取得するプログラムをPHPで書いたのですが、file_get_contents($url)をすると
上記のとおり、verify_peerを無効にしてればよいのかもしれませんが、以下のようにTLS1.0を使用する旨を設定してやれば正常に取得できるようになりました。
PHP Warning: file_get_contents(): SSL: Connection reset by peer
というエラーが出ました。
現象を調査したところ、
・curlで対象のAPIを呼び出すことはできる
・file_get_contents()で呼び出すことができるhttpsサイトと、エラーが出ないhttpsサイトがある
ことがわかりました。
サイトによって違う、ということは証明書関連か?と思い、呼び出せるサイトと呼び出せないサイトを比べて見ました。
・呼び出せるサイト
・エラーになるサイト
TLSのバージョンが違う、、、
犯人はこれか?と思いググるとありました。
PHP 5.6.x における OpenSSL 関連の変更
「Connection reset by peer」というエラーメッセージを見るに、おそらくここがヒットしているのではないでしょうか。」
ストリームラッパーが、SSL/TLS を使っている場合のピア証明書とホスト名の検証にデフォルトで対応 ¶
暗号化されたすべてのクライアントストリームで、ピア検証がデフォルトで有効になりました。 デフォルトでは、OpenSSL のデフォルト CA バンドルを使ってピア証明書を検証します。 たいていの場合は、正しい SSL 証明書を持つサーバーと通信するならこれを変更する必要はありません。 OpenSSL が、よく知られた CA バンドルを使うように設定されているからです。
デフォルトの CA バンドルを上書きすることもできます。 openssl.cafile あるいは openssl.capath を設定すればグローバルに変更でき、コンテキストオプション
cafile
あるいはcapath
を使えばリクエスト単位で変更できます。一般的にはおすすめできませんが、 コンテキストオプション
verify_peer
をFALSE
にしてリクエストでのピア証明書の検証を無効化することもできます。 また同じく、ピア名の検証も、コンテキストオプションverify_peer_name
をFALSE
にすれば無効化できます。
上記のとおり、verify_peerを無効にしてればよいのかもしれませんが、以下のようにTLS1.0を使用する旨を設定してやれば正常に取得できるようになりました。
$ctx = stream_context_create([ 'ssl' => [ 'crypto_method' => STREAM_CRYPTO_METHOD_TLS_CLIENT, ], ]); $html = file_get_contents('https://example.com/', false, $ctx);