dポイントプレゼントキャンペーン実施中!

お世話になっております。

fsockopenを使って、証明書付きのSSL通信をして表示内容を取得したいのです。

いろいろ見て回って、下記のようなソースを作りました。

------------------------------------------------------------------------
$context = stream_context_create();
stream_context_set_option($context, 'ssl', 'local_cert', './client.pem');
stream_context_set_option($context, 'ssl', 'cafile', './ca.pem');

$host = "aaa.bbb.ne.jp";
$fp = fsockopen("ssl://{$host}", 443, $errno, $errstr, 10, $context);
------------------------------------------------------------------------

すると、

Warning: fsockopen() expects at most 5 parameters, 6 given

と怒られます。fsockopenに6つ目のパラメータは渡せないってことですよね?

仕方がないので、
$contextをはずしてみると、当然証明ができないので怒られます。

Warning: fsockopen(): SSL operation failed with code 1. OpenSSL Error messages:
error:14094410:SSL routines:func(148):reason(1040) in xxxxxxx~

Warning: fsockopen(): Failed to enable crypto in xxxxxxx~

Warning: fsockopen(): unable to connect to ssl://aaa.bbb.ne.jp:443 (Unknown error) in xxxxxxx~





まる一日解決方法を探し続けているのですが、だめです。

漠然とした内容で申し訳ありませんが、どなたかご教授願えませんでしょうか。

よろしくお願いいたします。

A 回答 (6件)

幾つかの pem ファイルを指定していることから、SSL クライアント認証が必要なサーバにアクセスしてコンテンツを得たいということですよね?



ソケットを開いて openssl関数を駆使して自前で頑張るのもアリですが、参照URLのとおり面倒なネゴシエーションをしなくてはなりません。
頑張って実装してください。。

って面倒ですよね。もし cURL extension が利用できるのであれば以下のソースが参考になるかもしれません。手元にすぐにSSLクライアント認証が試せる環境がなかったので動作は未検証になります。

<?php
if( function_exists( 'curl_init' ) === FALSE ) {
die( 'cURL 使えないッス!' );
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'aaa.bbb.ne.jp');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // コンテンツはテキスト文字列
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_CAPATH, 'client.pem のあるディレクトリを指定');
curl_setopt($ch, CURLOPT_CAINFO, 'ca.pem をフルパス指定');
curl_setopt($ch, CURLOPT_SSLCERT, 'client.pem');
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, 'client.pem のパスワードを指定');

// CURLOPT_RETURNTRANSFER を 1 にしているのでresponse body を変数に格納
$result = curl_exec($ch);
curl_close($ch);
echo $result .PHP_EOL
exit;

参考URL:http://alk.dip.jp/apache2-default/sv290.html
    • good
    • 0
この回答へのお礼

ありがとうございます。

ご丁寧にサンプルまで。。。(泣)

curlが使えない状態だったので、PHPのリコンパイルして使えるようになったのですが、

実行しても、実行中のまま変化なしでした。

どうもpfxから変換したpemが怪しいような気がしてきました。

中身が理解できてなくて、コピペだからうまくいかないんですよね。

参考URLなど勉強してもうちょっとがんばってみます。

ありがとうございます。

お礼日時:2010/12/22 11:01

hogehoge78 さんの Zend Framework 簡単でいいですね。


Zend Framework はコンポーネントを単体でライブラリのように使えると聞いたことがあります。#使ったことがないのでわかりません。
導入するのに抵抗がないのであれば HTTP ヘッダをパースしてクッキーにセットしてなど雑多な処理から開放されそうです。

質問者の方の補足の質問ですが、人間がブラウザを利用して操作する事をトレースするわけですから、 curl_init() をリクエスト回数分コールすることになりそうです。

設定したオプションを再利用したいのであれば curl_setopt_array() や curl_copy_handle() があるようですので関数やオブジェクトのメソッドでラッピングして使うと便利そうですね。

先のZend_Http_Clientを使う案も素敵だと思います。

#Webアプリケーションなんでしょうか?だとしたら本来各ブラウザで分散される処理を一手に引き受けるのですからアクセス数によってはCPUぶん回しになりそうですね。接続先はSSLアクセラレータが使えるかもしれませんが、クライアントの振舞いをする側はそうはいきませんし。
    • good
    • 0
この回答へのお礼

>人間がブラウザを利用して操作する事をトレースするわけですから、

そういうことなんですね。

やっとイメージできました。

一応curlを何度かたたくことで実現できました!!

これからZendも試してみようと思います。

未知の世界だったのですが、少し理解することができました。

ありがとうございました!!

お礼日時:2010/12/23 11:19

よこからですみませんが、


HTTPの通信は、一度のリクエストとレスポンスの組ですので、最後にcurl_close関数を叩いたら、
次回もう一度、curl_initをし直す必要があります。

また、curlだけに限らない話ですが、セッションを引き継ぐリクエストを送るときに自前でコードを記述するのは結構手間がかかるので、ZendFrameworkの「Zend_Http_Client」をライブラリとして使ってみてはいかがでしょう。
NARHさんの書かれたスクリプトを参考にして、Zend_Http_Clientを使った記述は、
<?php
/*

Zend Framework ダウンロードはここ
http://framework.zend.com/download/latest

Zend_Http_Clientのマニュアルはここ
http://framework.zend.com/manual/ja/zend.http.cl …

*/

require_once 'Zend/Http/Client.php';

$uri = 'https://example.com';

$config = array(
'adapter' => 'Zend_Http_Client_Adapter_Curl',
'curloptions' => array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYHOST => 1,
CURLOPT_SSL_VERIFYPEER => 1,
CURLOPT_CAPATH => 'path',
CURLOPT_CAINFO => 'path/to/ca.pem',
CURLOPT_SSLCERT => 'path/to/client.pem',
CURLOPT_SSLCERTPASSWD => 'password',
),
);

$client = new Zend_Http_Client($uri, $config);
$client->setCookieJar();//セッションを保持できるようにします。
$client->setParameterPost('name', 'value'); //POST値を入力します。

$response = $client->request('POST');

if($response->getStatus() == 200){
$client->setUri('http://example.com/next/page');

$response = $client->request('GET');

}

?>

このようになります。
アダプタとして、curlを使いますので(別のモジュールを選択することも可能)、内部的には、NARHさんのやっていることと同じです。
ソレとは別に、Cookieで取得したセッション用のIDなどを取り持って次の遷移に持込してくれるルーチンが仕込まれています。

ご参考まで。
    • good
    • 0
この回答へのお礼

Zendは使ったことがありませんでした。

とてもわかりやすいサンプルをありがとうございました。

早速試してみます。

お礼日時:2010/12/23 11:16

実は、先ほどのサンプルではポート指定を忘れてました。

(テヘッ!)

curl_setopt($ch, CURLOPT_URL, 'https://aaa.bbb.ne.jp');
でもいけると思います。
#すみません。相変わらず未検証です。

でも pem が上手くいっていなかったらダメなんですが、タイムアウトの指定はできたので、PHP のcURLのマニュアルも参考にしてみてくださいね。

#Web上にあんまりビンゴな資料ってありそうでないですね。
    • good
    • 0
この回答へのお礼

再びありがとうございます!

なんと証明書の件はクリアできました。
pemの件はOKだったようです。


また別の問題が・・・

アクセス先のサイトは、SSL証明書を通過したあと、更にログインの必要があり、
セッションを持ちまわっているようなのです。

その後、必要なパラメータをPOSTして情報を引き出します。

このような場合は、いったんログインページにcurl_initし、

その後検索フォームのページで再びcurl_initするようなイメージでいいのでしょうか。

あつかましくて申し訳ありませんが、もしお分かりのようでしたら

ご教授いただけると助かります。

よろしくお願いいたします。

お礼日時:2010/12/22 17:16

〉No.2


勉強になりました。
ネットワークはきちんと勉強しなくては行けませんね。

質問者さんにも、外した回答してすみませんでした。

とりあえず
stream_context_createで作ったコンテキストつきで通信する場合は、stream_socket_clientが使えます。

http://jp.php.net/stream_socket_client
    • good
    • 0
この回答へのお礼

ありがとうございました。

ネットワーク難しいです。

勉強になります。

お礼日時:2010/12/22 16:48

PHPが、OpenSSLのサポートが有効な状態でインストールされていますか?


その場合であれば、「ssl://」といったスキームを記述してやれば、自動的に暗号化して通信を行うので
そのようなエラーが出てくることは無いと思います。(プロキシかましてたりすると一手間かける必要がありますが・・・)

phpinfo();
あたりで、OpenSSLのサポートが有効になっているか確認してみてはいかがでしょう。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!