httpsでfgets()した場合に「SSL: fatal protocol error」が出る

MicrosoftのIISサーバーとの通信中に「function.fgets: SSL: fatal protocol error …」のエラーメッセージが出る場合があります。 その原因と対策方法について。

IISとの通信中に発生することがある

毎回ではないですが、たまにIISがSSLの標準に準拠せずデータ送信終了してしまうために、PHPはデータの終わりをちゃんと認識することができず、エラーを出してしまいます。

より具体的にはIISは「close_notify」を送らないで終了してしまうのだそうです。 むむ、思わぬ所に地雷が…

close_notify」とは、データの送信側が「これでデータ終了です」ということを受信側に知らせるために発行するTLSハンドシェイクプロトコルに定義されているAlertプロトコルの一種です。 (参考データ

ちなみに、このエラーはfile_get_contents()でも発生することがあります(情報元(英語))。

エラー回避法

解決ではなくエラーの回避方法ですが、error_reportingのレベルを下げて、警告レベルまでは表示しないようにすると良いでしょう。 多くの人はこれで回避しています。

php.ini で設定する場合

...(前略)...
error_reporting = E_ALL ^ E_WARNING

phpプログラム途中で設定する場合

...(前略)...
error_reporting(E_ALL ^ E_WARNING);

phpプログラム中に一瞬だけ変える場合

この場合は現在のエラーレベルを退避させておいてから設定します。 実行後は再度もとのエラーレベルに設定します。

$fp = fopen("https://~", "r");
if (!$fp) {
return "";
} else {
$nowlevel = error_reporting();
error_reporting(E_ALL ^ E_WARNING);
$data = '';
while (!feof($fp)) {
$data = fgets($fp, 4096);
}
fclose($fp);
error_reporting($nowlevel);
return $data;
}

エラー解決法?

こちらは実際にテストしたわけではなく、PHPのオンラインマニュアルにあった情報です。

PHP4.3.7以降ではfopen()やfile_get_contents()ではなく、fsockopen()を利用してファイルポインタを取得することで、IISが出すエラーの処理を受けてコントロールできるようです。

fsockopen()を使うと、受信したデータが正しいものかどうかは受信者側で判断するようになっているためです。

ただ、この「close_notify」をどうやって受信側が特定するのかについてはどこにも書かれていません。

1 件のコメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

2010-03-26