今回は、CakePHP 3 の小ネタになります。
おそらく PHP 5.6 以降の問題になると思うのですが、OpenSSL 関連の仕様変更に伴い少しハマった場合の対処法を紹介しようと思います。
Cake\Network\Http\Client でオレオレ証明書のサーバに接続しようとして以下のエラーが発生してしまいました。
Exception: fopen(): Peer certificate CN=`hogehoge' did not match expected CN=`fugafuga'
fopen(): Failed to enable crypto
内部で利用しているストリームラッパーが PHP 5.6 からデフォルトで証明書とホスト名をチェックするようになったようです。
参考:http://php.net/manual/ja/migration56.incompatible.php#migration56.incompatible.peer-verification
そこで、オプションで証明書とホスト名を無視する設定が必要なのですが、Client の内部で使用されている Stream クラスは、ホスト名を無視するための verify_peer_name を渡すことができないようです。
同様の問題が CakePHP 2.x でも起こっていて issue が上がっていましたが、却下されてしまいました。
https://github.com/cakephp/cakephp/issues/7078
サーバーや証明書は、取引先が用意したものなので修正はできません・・・。さて、どうしようかと悩んだのですが、Client に Stream クラスを継承したアダプタをセットすることにしました。
<?php
use Cake\Network\Http\Adapter\Stream;
use Cake\Network\Http\Request;
class CustomAdapter extends Stream
{
protected function _buildSslContext(Request $request, $options)
{
parent::_buildSslContext($request, $options);
// 強制的にオプションを設定
$this->_sslContextOptions['verify_peer'] = false;
$this->_sslContextOptions['verify_peer_name'] = false;
}
}
使うときは、
// オプション指定
$client = new Client(['adapter' => 'CustomAdapter']);
とオプションに指定します。ただし、証明書を無視する設定は、セキュリティ的によろしくないので、このアダプターは開発時のみに使用し、本番には指定しないようにしましょう。
このように、CakePHP のクラスのメソッドやパラメータは、public か protected で定義されているので、困った時は継承して、柔軟に対応することができるます。
コアのソースを追って行けば案外なんとかなって、いいフレームワークですね!