fsockopenを使った証明書付きのSSL通信

このQ&Aのポイント
  • fsockopenには6つ目のパラメータを渡すことができません
  • 証明書を使用しない場合にはSSL通信ができません
  • 解決方法を探していますが、まだ見つかっていません
回答を見る
  • ベストアンサー

fsockopenを使った証明書付きのSSL通信

お世話になっております。 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~ まる一日解決方法を探し続けているのですが、だめです。 漠然とした内容で申し訳ありませんが、どなたかご教授願えませんでしょうか。 よろしくお願いいたします。

  • PHP
  • 回答数6
  • ありがとう数7

質問者が選んだベストアンサー

  • ベストアンサー
  • NARH
  • ベストアンサー率82% (88/107)
回答No.2

幾つかの 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
seiroku55
質問者

お礼

ありがとうございます。 ご丁寧にサンプルまで。。。(泣) curlが使えない状態だったので、PHPのリコンパイルして使えるようになったのですが、 実行しても、実行中のまま変化なしでした。 どうもpfxから変換したpemが怪しいような気がしてきました。 中身が理解できてなくて、コピペだからうまくいかないんですよね。 参考URLなど勉強してもうちょっとがんばってみます。 ありがとうございます。

その他の回答 (5)

  • NARH
  • ベストアンサー率82% (88/107)
回答No.6

hogehoge78 さんの Zend Framework 簡単でいいですね。 Zend Framework はコンポーネントを単体でライブラリのように使えると聞いたことがあります。#使ったことがないのでわかりません。 導入するのに抵抗がないのであれば HTTP ヘッダをパースしてクッキーにセットしてなど雑多な処理から開放されそうです。 質問者の方の補足の質問ですが、人間がブラウザを利用して操作する事をトレースするわけですから、 curl_init() をリクエスト回数分コールすることになりそうです。 設定したオプションを再利用したいのであれば curl_setopt_array() や curl_copy_handle() があるようですので関数やオブジェクトのメソッドでラッピングして使うと便利そうですね。 先のZend_Http_Clientを使う案も素敵だと思います。 #Webアプリケーションなんでしょうか?だとしたら本来各ブラウザで分散される処理を一手に引き受けるのですからアクセス数によってはCPUぶん回しになりそうですね。接続先はSSLアクセラレータが使えるかもしれませんが、クライアントの振舞いをする側はそうはいきませんし。

seiroku55
質問者

お礼

>人間がブラウザを利用して操作する事をトレースするわけですから、 そういうことなんですね。 やっとイメージできました。 一応curlを何度かたたくことで実現できました!! これからZendも試してみようと思います。 未知の世界だったのですが、少し理解することができました。 ありがとうございました!!

回答No.5

よこからですみませんが、 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.client.adapters.html */ 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などを取り持って次の遷移に持込してくれるルーチンが仕込まれています。 ご参考まで。

seiroku55
質問者

お礼

Zendは使ったことがありませんでした。 とてもわかりやすいサンプルをありがとうございました。 早速試してみます。

  • NARH
  • ベストアンサー率82% (88/107)
回答No.4

実は、先ほどのサンプルではポート指定を忘れてました。(テヘッ!) curl_setopt($ch, CURLOPT_URL, 'https://aaa.bbb.ne.jp'); でもいけると思います。 #すみません。相変わらず未検証です。 でも pem が上手くいっていなかったらダメなんですが、タイムアウトの指定はできたので、PHP のcURLのマニュアルも参考にしてみてくださいね。 #Web上にあんまりビンゴな資料ってありそうでないですね。

seiroku55
質問者

お礼

再びありがとうございます! なんと証明書の件はクリアできました。 pemの件はOKだったようです。 また別の問題が・・・ アクセス先のサイトは、SSL証明書を通過したあと、更にログインの必要があり、 セッションを持ちまわっているようなのです。 その後、必要なパラメータをPOSTして情報を引き出します。 このような場合は、いったんログインページにcurl_initし、 その後検索フォームのページで再びcurl_initするようなイメージでいいのでしょうか。 あつかましくて申し訳ありませんが、もしお分かりのようでしたら ご教授いただけると助かります。 よろしくお願いいたします。

回答No.3

〉No.2 勉強になりました。 ネットワークはきちんと勉強しなくては行けませんね。 質問者さんにも、外した回答してすみませんでした。 とりあえず stream_context_createで作ったコンテキストつきで通信する場合は、stream_socket_clientが使えます。 http://jp.php.net/stream_socket_client

seiroku55
質問者

お礼

ありがとうございました。 ネットワーク難しいです。 勉強になります。

回答No.1

PHPが、OpenSSLのサポートが有効な状態でインストールされていますか? その場合であれば、「ssl://」といったスキームを記述してやれば、自動的に暗号化して通信を行うので そのようなエラーが出てくることは無いと思います。(プロキシかましてたりすると一手間かける必要がありますが・・・) phpinfo(); あたりで、OpenSSLのサポートが有効になっているか確認してみてはいかがでしょう。

関連するQ&A

  • fsockopenの例外について

    お世話になります。 現在、fsockopen関数を利用してソケット通信を行うシステムを開発しております。 上記、システムを利用する中で考えられる例外として「apacheが停止しているサーバーに通信を行った場合」というのを想定して、例外処理を作成しております。 例外処理をtry catchによって検知しようとしたのですが、try catchでは受け取れませんでした。 ソースは下記のとおりです。 $api_url = "http://localhost/webapp/test"; $api_arr = parse_url($api_url); try{ // ソケット通信開始 $fp = fsockopen($api_arr["host"], 80, $errno, $errstr, 30 ); }catch(ErrorException $e){ echo "Error - failed to connect to the API - ".$e->getMessage(); exit; }catch(Exception $e){ echo "hoge2"; } 上記、ソースをunixのコマンドから実行した場合に出力されたエラーは下記のとおりです。 Error: fsockopen(): unable to connect to localhost:80 (Connection refused) もし、お分かりになる方がおられましたら、ご教示お願い致します。

    • 締切済み
    • PHP
  • fsockopenで下層ページの内容を取得するには

    わたくしphp歴4ヶ月のものです。 fsockopenで下層ページの内容を取得するにはどうすればよいのでしょうか。説明がうまくできないので例を書きます。 business.yahoo.co.jp/prod/store を指定するとエラーが出ます。 例1) $fp=fsockopen("business.yahoo.co.jp/prod/store", 80, $errno, $errstr, 30); if(!$fp) { echo "$errstr ($errno)<br>\n"; } else{ fputs($fp, "GET / HTTP/1.0\r\n\r\n"); while(!feof($fp)) { echo fgets ($fp,600); } fclose($fp); } business.yahoo.co.jpを指定するとエラーが出ません。 例2) $fp=fsockopen("business.yahoo.co.jp", 80, $errno, $errstr, 30); if(!$fp) { echo "$errstr ($errno)<br>\n"; } else{ fputs($fp, "GET / HTTP/1.0\r\n\r\n"); while(!feof($fp)) { echo fgets ($fp,600); } fclose($fp); } 下層ディレクトリのページはどのように指定すればよいのでしょうか。/←スラッシュに問題があるのでしょうか。 その場合のエラーの内容は下記です。 Warning: fsockopen(): php_network_getaddresses: getaddrinfo failed: Name or service not known in /home/mero/public_html/test.php on line 23 Warning: fsockopen(): unable to connect to business.yahoo.co.jp/prod/store:80 in /home/mero/public_html/test.php on line 23 No such file or directory (2) 基本的な質問でたいへん恐縮ですが、 ご指導お願いいたします!

    • ベストアンサー
    • PHP
  • MYSQL再起動後に接続できなくなってしまいました

    CENTOS5.6でMYSQL5.5.22を入れて使用しています。 テスト用プログラムを作っていて、MSYQLへのデータ挿入が止まらなかったためMSYQLをリスタートしました。 すると、起動後おそらく接続できないとのメッセージが出ています。 postfixをMysqlで使用して使っているため、メールができなくて困っています。 下記エラーメッセージがmysqlのログにありました。 120626 14:15:57 [Warning] Unknown character set: 'utf8a' 120626 14:15:57 [Warning] Aborted connection 131 to db: 'postfix用のDB名' user: 'postfix用のユーザー名' host: 'localhost' (init_connect command failed) 120626 14:15:57 [Warning] Unknown character set: 'utf8a' 120626 14:15:57 [Warning] Aborted connection 132 to db:'postfix用のDB名' user: 'postfix用のユーザー名' host: 'localhost' (init_connect command failed) 120626 14:15:57 [Warning] Unknown character set: 'utf8a' 120626 14:16:58 [Warning] Aborted connection 133 to db: 'postfix用のDB名' user: 'postfix用のユーザー名' host: 'localhost' (init_connect command failed) 120626 14:16:58 [Warning] Unknown character set: 'utf8a' 120626 14:16:58 [Warning] Aborted connection 134 to db: 'postfix用のDB名' user: 'postfix用のユーザー名' host: 'localhost' (init_connect command failed) 120626 14:16:58 [Warning] Unknown character set: 'utf8a' 120626 14:16:58 [Warning] Aborted connection 135 to db: 'postfix用のDB名' user: 'postfix用のユーザー名' host: 'localhost' (init_connect command failed) 120626 14:16:58 [Warning] Unknown character set: 'utf8a' Aborted connection の部分を色々調べたのですが、情報が少なく解決策がわかりませんでした。 Mysqlの再起動やサーバー自体の再起動を行ったのですが解決できませんでした。 何かヒントになるような事がありましたら、教えていただけないでしょうか? 宜しくお願いします。

    • ベストアンサー
    • MySQL
  • 自己証明時エラー

    SSL_CTX_use_PrivateKey_file "sample.crt" failed - aborted error:0906D06C:PEM routines:PEM_read_bio:no start line opensslを使用して自己証明をおこないたいのですが、上記のようなエラーが出ます。 これは、どういう意味なのでしょうか? また、対応策を教えていた抱けたらと思います。 よろしくお願いします。

  • fsockopenなどについて

    呼び出し元:aaaa.php 呼び出し先:https://bbbbb.jp/php/cccc.php 認証:Basic ユーザー/パス:user/pass メソッド:POST PHP:5.x という前提でfsockopenを使ってaaaa.phpからcccc.phpにPOSTでデータを投げようと考えています。 今回初めてコマンドラインからPOSTをすることになり、いろいろと模索している状況です。PEARやPECL系は入れないみたいなので、fsockopenをつかうことになりました。 aaaa.phpの中身 $POST = "postData"; $request = "POST /php/cccc.php HTTP/.0\n". "Host: https://cccc.jp\n". "Authorization: Basic".base64_encode("dddd:eeee"); "\n". $POST ."\n". "\n"; $fp = fsockopen("ssl://bbbbb.jp",443); fputs($fp,$request); $res=""; while(!feof($fp)){ $res=fgets,4096); fclose($fp); と、こんな感じです(今手書きだったので、このままだとコンパイルエラーになる可能性もありますが、それは無視とします) タイムアウトを15に設定しデバッグしても、それを過ぎてもなんのレスもない状態です。 requestの書き方がまずいんだと思うのですが、どこをどうすればいいのかわかりません。 authを入れない状態だと、resに"</body></html>"というタグが入ってきます。 受け取り側のスクリプトはPOSTで受け取ったものをログに吐き出すだけの単純なものです。 ちょっとつかみづらい内容で申し訳ありません。もし情報が足りなければ捕捉いたしますので、ご教授願います。

    • 締切済み
    • PHP
  • Permission denied in

    PHPを実行するとWarning: fopen failed to open stream Permission denied inと 表示されてしまいます。 インターネットを使い、調べてはいますが、 上記のように表示してしまいます。 ファイルです。パーミッションは606にしました。 このWarningを表示させないようにするには、どのようにすれば 良いのか教えて頂けると嬉しいです。

    • ベストアンサー
    • PHP
  • xampp+snoopyのエラーについて 教えてください

    php初心者なのですが、どうしてわからなくて困っています。 winXPでxamppを使用してローカル環境でphpを使っています。 phpライブラリのブラウザシミュレータ snoopy(http://snoopy.sourceforge.net/)を入れたのですが、 付属サンプルのsample2.phpとsample3.php で以下のようなエラーが出て困っています。 ______________________________________________________________ Warning: fsockopen() [function.fsockopen]: php_network_getaddresses: gethostbyname failed in C:\Program Files\xampp\php\pear\Snoopy.class.php on line 1128 Warning: fsockopen() [function.fsockopen]: unable to connect to lnk.ispi.net:80 in C:\Program Files\xampp\php\pear\Snoopy.class.php on line 1128 error fetching document: connection failed (0) ______________________________________________________________ 知り合いの人にapacheのhttpd.conf内、HostnamelookupsがOffなのでは? と言われたのでapacheの該当箇所変更したのですが、 変わりませんでした。 また、エラー表示されているSnoopy.class.phpの該当箇所も、 問題ないと思います。 どなたかご存知の方がいれば、教えてください。お願いします。

    • ベストアンサー
    • PHP
  • drupalでエラーが表示される

    drupalを利用してサイトを作成しようとしております。 インストールまでは終わったのですが、どのページを表示しても以下のようなエラーが出てきます。 ---------- * Warning: file_put_contents(temporary://filezqqgJ1) [function.file-put-contents]: failed to open stream: "DrupalTemporaryStreamWrapper::stream_open" call failed in file_unmanaged_save_data() (line 1847 of /home/sites/*****.jp/users/************/web/public_html/includes/file.inc). * ファイルを作成できませんでした。 * Warning: file_put_contents(temporary://fileBtkpQw) [function.file-put-contents]: failed to open stream: "DrupalTemporaryStreamWrapper::stream_open" call failed in file_unmanaged_save_data() (line 1847 of /home/sites/*****.jp/users/************/web/public_html/includes/file.inc). * ファイルを作成できませんでした。 ---------- ↑このエラーの意味と対処法をお分かりの方がいましたら、教えていただけないでしょうか。 よろしくお願いいたします。

  • PHPからHTMLファイルを書き出し

    PHPプログラムからHTMLファイル(aaa.html)を書き出しているのですが、 その作られたHTMLファイルにブラウザでアクセスすると以下のようなエラーメッセージが表示されます。 Warning: Unknown: SAFE MODE Restriction in effect. The script whose gid is 1000 is not allowed to access /****/aaa.html owned by uid 1000 in Unknown on line 0 Warning: Unknown: SAFE MODE Restriction in effect. The script whose uid is 1000 is not allowed to access /****/aaa.html owned by uid 1000 in Unknown on line 0 Warning: Unknown: failed to open stream: Success in Unknown on line 0 Fatal error: Unknown: Failed opening required '/****/aaa.html' (include_path='.:/usr/local/lib/php') in Unknown on line 0 HTMLファイル名はユニークなので、あらかじめサーバーにアップロードし用意しておくという事ができません。 PHPプログラムの所有者と作成されたHTMLファイルの所有者が異なっていました。 chownはサーバーの仕様で使うことができません。 HTMLファイルのパーミッションを777として書き出しても、変化はありませんでした。 またPHPはsafemodeです。こちらも仕様でoffにできません。 長くなってしまい申し訳ないです。 HTMLファイルを閲覧できる方法はありますでしょうか。 どうかお知恵をお借りしたく思います。

    • 締切済み
    • PHP
  • SSL_connect(ssl)

    お世話になっています。 VC++2005、MFC、Win7、openssl で作業しています。 Gメールから、POP3S 接続でメールを受け取りたいと考えています。 メールヘッダーの受信後に、本文を取り出す前に接続が切れます。 最初に、接続の部分ですが、問題点がありましたら、アドバイスをください。 void CSQMailBoxTreeView::GmailMailDL(){ int nReturnCode; WSADATA wsaData; CFileException fileExpection; #define MAJOR_VERSION_REQUIRED 1 #define MINOR_VERSION_REQUIRED 1 struct sockaddr_in server; std::string req; // リクエスト std::string res; // レスポンス std::string host_url = "pop.googlemail.com"; strcpy_s(gszGmailServerName,(LPCTSTR)oc_Gmailpop3servername); if(strlen(gszGmailServerName)==0){ MessageBox("設定 - Gmail POP3サーバー から、\n受信メール(POP3)サーバを\n入力して下さい。","POP Server", MB_OK); } strcpy_s(gszGmailUserId, (LPCTSTR)oc_Gmailpop3userid); if(strlen(gszGmailUserId)==0){ MessageBox("設定 - Gmail POP3サーバー から、\nメールサーバのユーザ名を\n入力してください。","POP User ID", MB_OK); } strcpy_s(gszGmailPassword, (LPCTSTR)oc_Gmailpop3password); if(strlen(gszGmailPassword)==0){ MessageBox("設定 - Gmail POP3サーバー から、\nパスワードを入力してください。","警告 PassWord", MB_OK); } strcpy_s(gszGmailPOP3Port, (LPCTSTR)oc_Gmailpop3port); if(strlen(gszGmailPassword)==0){ MessageBox("設定 - Gmail POP3サーバー から、\nポート番号を入力してください。","POP3 PortNumber", MB_OK); } // Prepare version for WSAStartup() WORD wVersionRequired = MAKEWORD(MAJOR_VERSION_REQUIRED, MINOR_VERSION_REQUIRED); // Initialize the WinSock DLL nReturnCode = WSAStartup(wVersionRequired, &wsaData); if (nReturnCode != 0 ){ MessageBox("Error on WSAStartup()", "CheckGMail", MB_OK); return ; } // Confirm that the version requested is available. if (wsaData.wVersion != wVersionRequired){ // Version needed is not available. MessageBox("Wrong WinSock Version", "CheckGMail", MB_OK); WSACleanup(); return ; } sock = socket(AF_INET, SOCK_STREAM, 0); server.sin_family = AF_INET; server.sin_port = htons(995); server.sin_addr.S_un.S_addr = inet_addr(host_url.c_str()); if (server.sin_addr.S_un.S_addr == 0xffffffff) { struct hostent *host; unsigned int **addrptr; host = gethostbyname(host_url.c_str()); if (host == NULL) { return ; } addrptr = (unsigned int **)host->h_addr_list; while (*addrptr != NULL) { server.sin_addr.S_un.S_addr = *(*addrptr); if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) { break; } } if (*addrptr == NULL) { sprintf_s(outbuf3, "Fatal error: unable to connect to the server.\n"); MessageBox(outbuf3,"Error", MB_OK); WSACleanup(); return;// -1; } } else { if (connect(sock, (struct sockaddr *)&server, sizeof(server)) != 0){ return ; } } SSL_load_error_strings(); SSL_library_init(); ctx = SSL_CTX_new(TLSv1_method()); if (ctx == NULL) { return;// 1; } ssl = SSL_new(ctx); if (ssl == NULL) { return;// 1; } if (SSL_set_fd(ssl, sock) == 0) { return;// 1; } RAND_poll(); while (RAND_status() == 0) { unsigned short rand_ret = rand() % 65536; RAND_seed(&rand_ret, sizeof(rand_ret)); } int ev = SSL_connect(ssl); if ( ev != 1) { int ret = SSL_get_error(ssl, ev); if(ret <= 0){ ERR_print_errors_fp(stderr); return;// 1; } } if (WSAAsyncSelect(sock, *this, SM_GASYNC3, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE) == SOCKET_ERROR){ MessageBox("WSAAsyncSelect() failed","Error", MB_OK); closesocket(sock); sock = INVALID_SOCKET; return; } gnAppState = STATE_CONNECTING; }

専門家に質問してみよう