Memo/PHP/phpでSSL通信

http://dexlab.net/pukiwiki/index.php?Memo%2FPHP%2Fphp%A4%C7SSL%C4%CC%BF%AE
 

Memo/PHP

phpでSSL通信

目的

https://〜/へリクエストを投げる事。
サーバー側プログラムは通常通り標準出力すれば、apache等のwebサーバーが勝手にSSLで処理してくれます。

モジュールバージョン
cURL7.13.0(2005-02-18 (金) 16:18:09)
PEAR Net_Curl0.2(stable) / 1.0.1(beta)2005-02-18 (金) 16:39:06

バグ

  • Windowsだと、php.iniに「extension=php_openssl.dll」を指定しても動作しない。
    staticリンクだと動作する模様。

cURLを使用する場合

PEAR Net_Curlを使用する場合

0.2と1.0.1betaがあるが、最新の1.0.1betaで実験してみる。
内部でcURLを呼んでいるようなので、cURLが必要。

インストール

pear install Net_Curl-beta

ソケット通信

fsockopen()で行う場合。
PHPのBugがあるので注意。

  • メリット
    • cURLがなくともOpenSSLが入っていれば使える。(大抵は標準で入ってる)
    • 関数が一つのなのでお手軽
    • 細かい処理に対応できる
  • デメリット
    • メンテナンスは自前:p
      1. <?php
      2. /**
      3. * @file
      4. * @brief HTTP関係クラス
      5. */
      6.  
      7. /**
      8. * HTTPリクエストの送信(GET, POST, SSL, NameVirtualHost, Basic認証対応)
      9. *
      10. * @param string $url URL ex: http://example.com:80/path/to, https://example.com:443/path/to, tls://example.com:443/path/to
      11. * @param array $options
      12. * 'content' => array('key'=>'value'), 送信データ
      13. * 'method' => 'GET' or 'POST' デフォルト:'GET'
      14. * 'header' => array(
      15. 'User-Agent:' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)'
      16. ), httpヘッダ
      17. * 'host' => 'IPアドレス',  (省略可。ネームベースのバーチャルホストで特定のサーバにアクセスしたい場合は、IPアドレスを指定)
      18. * 'time_limit' => 10, (タイムアウト秒数。省略可。デフォルト10秒)
      19. * 'errno' => エラーがある場合はエラー番号,
      20. * 'errstr' => エラーがある場合はエラー文字列,
      21. * @return array list($head, $body)
      22. *
      23. * @note
      24. * - file_get_contents()では Location:ヘッダ + bodyがあった場合にリダイレクトされ、bodyを取得できない。この関数はリダイレクトしないため、bodyを取得できる。
      25. * - 例
      26. *   - GET:list($head, $body) = httpRequest("http://example.com/path/to?key1=val1", $options);
      27. *   - GET:
      28. @code
      29. $options = array('method'=>'get', 'content'=>array('key1' => 'val1') );
      30. list($head, $body) = httpRequest("http://example.com/path/to", $options);
      31. @endcode
      32. *   - GET(SSL):
      33. @code
      34. $options = array('method'=>'get', 'content'=>array('key1' => 'val1') );
      35. list($head, $body) = httpRequest("https://example.com/path/to", $options);
      36. @endcode
      37. *   - POST:
      38. @code
      39. $options = array('method'=>'post', 'content'=>array('key1' => 'val1') );
      40. list($head, $body) = httpRequest("http://example.com/path/to", $options);
      41. @endcode
      42. *   - エラーの判定
      43. @code
      44. list($head, $body) = httpRequest("http://example.com/path/to", $options);
      45. if($options['errno'] != 0){
      46. // エラー処理
      47. echo $options['errstr'] . "\n";
      48. }
      49. @endcode
      50. *   - NameVirtualHostの特定ホストにリクエストを送る
      51. @code
      52. $options = array('host'=>'xxx.xxx.xxx.xxx');
      53. list($head, $body) = httpRequest("http://example.com/path/to", $options);
      54. @endcode
      55. *   - GET: 8080ポートを指定
      56. @code
      57. $options = array('method'=>'get', 'content'=>array('key1' => 'val1') );
      58. list($head, $body) = httpRequest("http://example.com:8080/path/to", $options);
      59. @endcode
      60. *   - basic認証
      61. @code
      62. list($head, $body) = httpRequest("http://username:password@example.com/path/to", $options);
      63. @endcode
      64. *   - 任意のhttpヘッダを送信する
      65. @code
      66. $options = array( 'header'=>array('User-Agent:' => "PHP/".phpversion() ) );
      67. list($head, $body) = httpRequest("http://username:password@example.com/path/to", $options);
      68. @endcode
      69. */
      70. function httpRequest($url, &$options)
      71. {
      72. $_options = array(
      73. 'content' => '', // postデータ
      74. 'method' => 'GET', // 'post' or 'get'
      75. 'header' => array(
      76. 'Accept-Language:' => 'ja',
      77. 'User-Agent:' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)', // IE7 or "User-Agent: PHP/".phpversion()."\r\n";
      78. ),
      79. 'host' => '',
      80. 'time_limit' => 10,
      81. );
      82.  
      83. $options['errno'] = -1;
      84. $options['errstr'] = '';
      85. $_options = array_merge($_options, $options);
      86.  
      87. $url = trim($url);
      88. $purl = parse_url($url);
      89.  
      90. $purl['scheme'] = strtolower($purl['scheme']);
      91. switch($purl['scheme']){
      92. case 'http':
      93. $purl['scheme'] = '';
      94. $purl['port'] = ($purl['port'] != '') ? $purl['port'] : 80;
      95. break;
      96. case 'https':
      97. $purl['scheme'] = 'ssl://';
      98. $purl['port'] = ($purl['port'] != '') ? $purl['port'] : 443;
      99. break;
      100. case 'tls':
      101. $purl['scheme'] = 'tls://';
      102. $purl['port'] = ($purl['port'] != '') ? $purl['port'] : 443;
      103. break;
      104. default:
      105. break;
      106. }
      107.  
      108. // Build the request string
      109. $request = '';
      110. if($_options['content'] != ''){
      111. if(is_array($_options['content'])){
      112. $request =  http_build_query($_options['content']);
      113. }else{
      114. $request = $_options['content'];
      115. }
      116. }
      117. if (isset($purl["query"])) {
      118. $request .= ($request == '') ? $purl["query"] : '&'.$purl["query"];
      119. }
      120.  
      121. if($_options['host'] != ''){ // ホストが指定されている場合
      122. $purl["host"] = $_options['host'];
      123. }
      124.  
      125. $request_length = strlen($request);
      126.  
      127. // Build the header
      128. $_options['method'] = strtoupper($_options['method']);
      129. $header = '';
      130. $x_header = '';
      131. if( is_array($_options['header']) ){
      132. foreach($_options['header'] as $key => $val){
      133. if(!preg_match("/\:$/",$key) ) $key .= ':';
      134. $x_header .= sprintf("%s %s\r\n", $key, $val);
      135. }
      136. }else{
      137. $x_header = $_options['header'];
      138. if(!preg_match("/\r\n$/",$x_header) ) $x_header .= "\r\n";
      139. }
      140.  
      141. switch($_options['method']){
      142. case 'POST':
      143. $header .= "POST {$purl["path"]} HTTP/1.0\r\n";
      144. $header .= "Host: {$purl["host"]}\r\n";
      145. $header .= $x_header;
      146. $header .= "Content-type: application/x-www-form-urlencoded\r\n";
      147. $header .= "Content-length: {$request_length}\r\n";
      148. break;
      149. case 'GET':
      150. $header .= "GET {$purl["path"]}?$request HTTP/1.0\r\n";
      151. $header .= "Host: {$purl["host"]}\r\n";
      152. $header .= $x_header;
      153. $request = '';
      154. break;
      155. default:
      156. $header .= "$method {$purl["path"]} HTTP/1.0\r\n";
      157. $header .= "Host: {$purl["host"]}\r\n";
      158. $header .= $x_header;
      159. break;
      160. }
      161.  
      162. // Basic認証用ヘッダ
      163. if (isset($purl['user']) || isset($purl['pass'])) {
      164. $header .= "Authorization: Basic ".base64_encode($purl['user'].":".$purl['pass'])."\r\n";
      165. }
      166.  
      167. $header .= "\r\n";
      168.  
      169. // Open the connection
      170. $fp = @fsockopen($purl['scheme'] . $purl["host"], $purl["port"], $options['errno'], $options['errstr'], $_options['time_limit']);
      171. if (!$fp) {
      172. if ( $options['errno'] == 0 ){
      173. $options['errno'] = 500;
      174. $options['errstr'] = 'fsockopen failed';
      175. }
      176. return array();
      177. }
      178. if(is_int($_options['time_limit'])) socket_set_timeout($fp, $_options['time_limit']);
      179.  
      180. // Send everything
      181. fputs($fp, $header . $request);
      182.  
      183. // Get the response
      184. $response = '';
      185. while (!feof($fp)) {
      186. // PHP Bug #23220 「Warning: fgets(): SSL: fatal protocol error」の抑制
      187. // file_get_contents()でも起こるようだ。
      188. $response .= @fgets($fp, 4096);
      189. }
      190. fclose($fp);
      191. $fp = NULL;
      192.  
      193. $DATA = split("\r\n\r\n", $response, 2);
      194.  
      195. if(preg_match('#^HTTP/[\d\.]+\s+(\d+)[^\r\n]+#i', $DATA[0], $matches)){
      196. $status_code = intval($matches[1]);
      197. if($status_code >= 200 && $status_code <= 299){
      198. // 2xx Success
      199. }else if($status_code >= 300 && $status_code <= 399){
      200. // 3xx Redirection
      201. }else{
      202. $options['errno'] = $status_code;
      203. $options['errstr'] = $matches[0];
      204. }
      205. }
      206.  
      207. return $DATA;
      208. }

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2010-05-08 (土) 10:07:57 (2970d)