1 <?xml version="1.0" encoding="UTF-8"?>
3 <!-- EN-Revision: 21145 -->
4 <sect1 id="zend.http.client.adapters">
5 <title>Zend_Http_Client - 接続アダプタ</title>
7 <sect2 id="zend.http.client.adapters.overview">
11 <classname>Zend_Http_Client</classname> は、接続アダプタとして設計されています。
12 接続アダプタは実際にサーバへの接続を行うオブジェクトで、
13 リクエストの書き込みやレスポンスの読み込みも行います。
14 この接続アダプタは置き換えることができます。
15 つまり、デフォルトの接続アダプタを継承して自分の好みにあうように変更できます。
16 <acronym>HTTP</acronym> クライアントクラス全体を書き換える必要はありません。
17 同じインターフェイスを実装しているだけでいいのです。
21 現在、<classname>Zend_Http_Client</classname> クラスは四つの組み込み接続アダプタを提供しています。
25 <classname>Zend_Http_Client_Adapter_Socket</classname> (デフォルト)
31 <classname>Zend_Http_Client_Adapter_Proxy</classname>
37 <classname>Zend_Http_Client_Adapter_Curl</classname>
43 <classname>Zend_Http_Client_Adapter_Test</classname>
50 <classname>Zend_Http_Client</classname> オブジェクトの接続アダプタを指定するには、
51 設定オプション 'adapter' を使用します。
52 クライアントオブジェクトのインスタンスを作成する際に、オプション
53 'adapter' にアダプタの名前 (たとえば 'Zend_Http_Client_Adapter_Socket' など)
54 を指定できます。あるいは、アダプタオブジェクトの変数
55 (たとえば <code>new Zend_Http_Client_Adapter_Test</code> など) を指定することもできます。
56 <classname>Zend_Http_Client->setConfig()</classname> メソッドを使用し、
61 <sect2 id="zend.http.client.adapters.socket">
62 <title>ソケットアダプタ</title>
65 デフォルトの接続アダプタは <classname>Zend_Http_Client_Adapter_Socket</classname>
66 です。明示的に接続アダプタを指定しない場合は、これが使用されます。
67 Socket アダプタは <acronym>PHP</acronym> の組み込み関数 fsockopen()
68 を使用しており、特別な拡張モジュールやコンパイルオプションは必要ありません。
72 ソケットアダプタには、追加の設定オプションを指定できます。これは
73 <classname>Zend_Http_Client->setConfig()</classname> で指定するか、
74 あるいはクライアントのコンストラクタに渡します。
76 <table id="zend.http.client.adapter.socket.configuration.table">
77 <title>Zend_Http_Client_Adapter_Socket の設定パラメータ</title>
91 <entry>persistent</entry>
94 持続的な <acronym>TCP</acronym> 接続を使用するかどうか
97 <entry>boolean</entry>
98 <entry><constant>FALSE</constant></entry>
102 <entry>ssltransport</entry>
103 <entry><acronym>SSL</acronym> トランスポート層 (たとえば 'sslv2'、'tls')</entry>
109 <entry>sslcert</entry>
112 <acronym>PEM</acronym> でエンコードした、<acronym>SSL</acronym> 証明書ファイルへのパス
116 <entry><constant>NULL</constant></entry>
120 <entry>sslpassphrase</entry>
123 <acronym>SSL</acronym> 証明書ファイルのパスフレーズ
127 <entry><constant>NULL</constant></entry>
131 <entry>sslusecontext</entry>
133 <!-- TODO : to be translated -->
135 Enables proxied connections to use SSL even if
136 the proxy connection itself does not.
139 <entry>boolean</entry>
140 <entry><constant>FALSE</constant></entry>
147 <title>持続的な TCP 接続</title>
150 持続的な <acronym>TCP</acronym> 接続を使用すると、<acronym>HTTP</acronym>
151 リクエストの処理速度が向上する可能性があります。
152 しかし、たいていの場合はその効果はごくわずかで、
153 接続先の <acronym>HTTP</acronym> サーバにかかる負荷が大きくなります。
157 持続的な <acronym>TCP</acronym> 接続を使用するのは、
159 そのサーバが同時に多数の接続を処理できることがわかっている場合のみにすることを推奨します。
160 いずれにせよ、このオプションを使用する前には
161 クライアント側の速度だけでなくサーバ側の負荷についてもベンチマークをとるようにしましょう。
166 <xref linkend="zend.http.client.configuration" />
167 で説明した Keep-Alive <acronym>HTTP</acronym> リクエストも有効にしておくことを推奨します。
168 そうしないと、持続的な接続の効果はほとんどといっていいほどなくなってしまいます。
173 <title>HTTPS SSL ストリームパラメータ</title>
176 <code>ssltransport, sslcert</code> および <code>sslpassphrase</code>
177 は、<acronym>HTTPS</acronym> 接続で使用する <acronym>SSL</acronym> レイヤーにのみ関連するものです。
181 たいていの場合はデフォルトの <acronym>SSL</acronym> 設定でうまく動作するでしょうが、
182 接続先のサーバが特別なクライアント設定を要求している場合は
183 それにあわせた設定をする必要があるかもしれません。
186 url="http://www.php.net/manual/ja/transports.php#transports.inet">ここ</ulink>
187 で <acronym>SSL</acronym> トランスポート層やオプションについての説明を参照ください。
192 <example id="zend.http.client.adapters.socket.example-1">
193 <title>HTTPS トランスポート層の変更</title>
195 <programlisting language="php"><![CDATA[
198 'adapter' => 'Zend_Http_Client_Adapter_Socket',
199 'ssltransport' => 'tls'
202 // クライアントオブジェクトのインスタンスを作成します
203 $client = new Zend_Http_Client('https://www.example.com', $config);
205 // これ以降のリクエストは、TLS セキュア接続上で行われます
206 $response = $client->request();
211 上の例の結果は、次の <acronym>PHP</acronym> コマンドで <acronym>TCP</acronym>
216 <methodname>fsockopen('tls://www.example.com', 443)</methodname>
219 <sect3 id="zend.http.client.adapters.socket.streamcontext">
220 <title>ソケットアダプタのストリームコンテキストへのアクセスとカスタマイズ</title>
223 Zend Framework 1.9 以降、<classname>Zend_Http_Client_Adapter_Socket</classname>
224 は、リモートサーバへの接続に使用している <ulink
225 url="http://www.php.net/manual/ja/stream.contexts.php">ストリームコンテキスト</ulink>
226 に直接アクセスできるようになります。これを使用すると、
227 <acronym>TCP</acronym> ストリーム (<acronym>HTTPS</acronym> 接続の場合は <acronym>SSL</acronym> ラッパー)
228 固有のオプションやパラメータを渡せるようになります。
232 ストリームコンテキストにアクセスするには、
233 <classname>Zend_Http_Client_Adapter_Socket</classname>
239 <firstterm><methodname>setStreamContext($context)</methodname></firstterm>
240 アダプタが使用するストリームコンテキストを設定します。
241 <acronym>PHP</acronym> の <ulink
242 url="http://php.net/manual/ja/function.stream-context-create.php"><methodname>stream_context_create()</methodname></ulink>
243 関数で作成したストリームコンテキストリソースか、
244 この関数に渡すのと同じ形式のストリームコンテキストオプションの配列のいずれかを指定できます。
245 配列を渡すと、そのオプションを用いて新たなストリームコンテキストを作成し、
252 <firstterm><methodname>getStreamContext()</methodname></firstterm>
253 アダプタのストリームコンテキストを取得します。
254 ストリームコンテキストが設定されていない場合は、
255 デフォルトのストリームコンテキストを作成してそれを返します。
256 あとは、さまざまなコンテキストオプションの設定や取得を通常の
257 <acronym>PHP</acronym> ストリームコンテキスト関数で行うことができます。
263 <example id="zend.http.client.adapters.socket.streamcontext.example-1">
264 <title>ソケットアダプタのストリームコンテキストオプションの設定</title>
266 <programlisting language="php"><![CDATA[
270 // ソケットのローカル側を特定のインターフェイスにバインドします
271 'bindto' => '10.1.2.3:50505'
275 // 無効な証明書や自己署名の SSL 証明書は拒否します
276 'verify_peer' => true,
277 'allow_self_signed' => false,
280 'capture_peer_cert' => true
284 // アダプタオブジェクトを作成し、HTTP クライアントにバインドします
285 $adapter = new Zend_Http_Client_Adapter_Socket();
286 $client = new Zend_Http_Client();
287 $client->setAdapter($adapter);
289 // 方法 1: オプションの配列を setStreamContext() に渡します
290 $adapter->setStreamContext($options);
292 // 方法 2: ストリームコンテキストを作成して setStreamContext() に渡します
293 $context = stream_context_create($options);
294 $adapter->setStreamContext($context);
296 // 方法 3: デフォルトのストリームコンテキストを取得してオプションを設定します
297 $context = $adapter->getStreamContext();
298 stream_context_set_option($context, $options);
301 $response = $client->request();
303 // すべてがうまくいけば、これでまたコンテキストにアクセスできます
304 $opts = stream_context_get_options($adapter->getStreamContext());
305 echo $opts['ssl']['peer_certificate'];
312 アダプタが実際にリクエストを処理しだす前に設定しなければならないことに注意しましょう。
313 コンテキストを設定せずにソケットアダプタで <acronym>HTTP</acronym> リクエストを処理すると、
314 デフォルトのストリームコンテキストが作成されます。
315 リクエストを処理した後にこのコンテキストリソースにアクセスするには
316 <methodname>getStreamContext()</methodname> メソッドを使用します。
322 <sect2 id="zend.http.client.adapters.proxy">
323 <title>プロキシアダプタ</title>
326 <classname>Zend_Http_Client_Adapter_Proxy</classname> アダプタはデフォルトのソケットアダプタとほぼ同じです。
327 ただし、対象となるサーバに直接接続するのではなく
328 <acronym>HTTP</acronym> プロキシサーバを経由して接続するという点が異なります。
329 これにより、<classname>Zend_Http_Client</classname> をプロキシサーバの中から使用できるようになります。
330 セキュリティやパフォーマンス上の理由により、これが必要となる場合もあるでしょう。
335 デフォルトの 'adapter' オプション以外に
336 いくつか追加のパラメータを設定する必要があります。
338 <table id="zend.http.client.adapters.proxy.table">
339 <title>Zend_Http_Client の設定パラメータ</title>
346 <entry>想定している型</entry>
353 <entry>proxy_host</entry>
354 <entry>プロキシサーバのアドレス</entry>
355 <entry>string</entry>
356 <entry>'proxy.myhost.com' あるいは '10.1.2.3'</entry>
360 <entry>proxy_port</entry>
361 <entry>プロキシサーバの <acronym>TCP</acronym> ポート</entry>
362 <entry>integer</entry>
363 <entry>8080 (デフォルト) あるいは 81</entry>
367 <entry>proxy_user</entry>
368 <entry>必要に応じて、プロキシのユーザ名</entry>
369 <entry>string</entry>
370 <entry>'shahar' あるいは指定しない場合は '' (デフォルト)</entry>
374 <entry>proxy_pass</entry>
375 <entry>必要に応じて、プロキシのパスワード</entry>
376 <entry>string</entry>
377 <entry>'secret' あるいは指定しない場合は '' (デフォルト)</entry>
381 <entry>proxy_auth</entry>
382 <entry>プロキシの <acronym>HTTP</acronym> 認証形式</entry>
383 <entry>string</entry>
384 <entry>Zend_Http_Client::AUTH_BASIC (デフォルト)</entry>
392 proxy_host は常に設定しなければなりません。指定しなかった場合は、
393 自動的に <classname>Zend_Http_Client_Adapter_Socket</classname> による直接接続に切り替わります。
394 proxy_port のデフォルトは '8080' です。もし別のポートをプロキシで使用している場合は、
399 proxy_user および proxy_pass は、
400 プロキシサーバが認証を必要とする場合にのみ設定します。
401 これらを指定すると、'Proxy-Authentication'
402 ヘッダがリクエストに追加されます。プロキシで認証を必要としない場合は、
403 このふたつのオプションはそのままにしておきます。
407 proxy_auth は、プロキシが認証を必要としている場合に、
409 Zend_Http_Client::setAuth() メソッドと同じです。現在はベーシック認証
410 (Zend_Http_Client::AUTH_BASIC) のみをサポートしています。
413 <example id="zend.http.client.adapters.proxy.example-1">
414 <title>プロキシサーバを使用した Zend_Http_Client の使用法</title>
416 <programlisting language="php"><![CDATA[
419 'adapter' => 'Zend_Http_Client_Adapter_Proxy',
420 'proxy_host' => 'proxy.int.zend.com',
421 'proxy_port' => 8000,
422 'proxy_user' => 'shahar.e',
423 'proxy_pass' => 'bananashaped'
426 // クライアントオブジェクトのインスタンスを作成します
427 $client = new Zend_Http_Client('http://www.example.com', $config);
434 説明したとおり、もし proxy_host を省略したり空文字列を設定したりすると、
435 自動的に直接接続に切り替わります。これにより、設定パラメータによって
436 オプションでプロキシを使用できるようなアプリケーションを書くことが可能となります。
441 プロキシアダプタは <classname>Zend_Http_Client_Adapter_Socket</classname>
442 を継承しているので、ストリームコンテキストへのアクセスメソッド
443 (<xref linkend="zend.http.client.adapters.socket.streamcontext" /> を参照ください)
444 を使用してプロキシ接続におけるストリームコンテキストオプションを設定できます。
450 <sect2 id="zend.http.client.adapters.curl">
451 <title>cURL アダプタ</title>
454 cURL は標準的な <acronym>HTTP</acronym> クライアントライブラリで、
455 多くの OS に含まれています。また <acronym>PHP</acronym> からは cURL
457 <acronym>HTTP</acronym> クライアントで起こりうる多くの特別な例にも対応することができるので、
458 <acronym>HTTP</acronym> アダプタとしては完璧な選択肢といえるでしょう。
459 セキュアな接続やプロキシ、そしてあらゆる種類の認証にも対応しており、
460 大きなファイルをサーバ間で移動させるときなどにも使用できます。
463 <example id="zend.http.client.adapters.curl.example-1">
464 <title>cURL オプションの設定</title>
466 <programlisting language="php"><![CDATA[
468 'adapter' => 'Zend_Http_Client_Adapter_Curl',
469 'curloptions' => array(CURLOPT_FOLLOWLOCATION => true),
471 $client = new Zend_Http_Client($uri, $config);
477 Socket アダプタとまったく同じ挙動となるように設定されています。
478 また、Socket アダプタおよび Proxy アダプタと同じ設定パラメータを使えます。
479 cURL のオプションを変更するには、アダプタのコンストラクタでキー
480 'curloptions' を指定するか、あるいは
481 <methodname>setCurlOption($name, $value)</methodname> をコールします。
482 <code>$name</code> は、cURL 拡張モジュールの
483 CURL_* 定数に対応します。Curl ハンドルにアクセスするには
484 <code>$adapter->getHandle();</code> をコールします。
487 <example id="zend.http.client.adapters.curl.example-2">
488 <title>ハンドルによるファイル転送</title>
491 cURL を使用して、巨大なファイルを <acronym>HTTP</acronym> 越しに転送できます。
494 <programlisting language="php"><![CDATA[
495 $putFileSize = filesize("filepath");
496 $putFileHandle = fopen("filepath", "r");
498 $adapter = new Zend_Http_Client_Adapter_Curl();
499 $client = new Zend_Http_Client();
500 $client->setAdapter($adapter);
501 $adapter->setConfig(array(
502 'curloptions' => array(
503 CURLOPT_INFILE => $putFileHandle,
504 CURLOPT_INFILESIZE => $putFileSize
507 $client->request("PUT");
512 <sect2 id="zend.http.client.adapters.test">
513 <title>テストアダプタ</title>
516 <acronym>HTTP</acronym> 接続に依存するテストコードを書くのは非常に難しいものです。
517 たとえば、リモートサーバから <acronym>RSS</acronym> を取得するアプリケーションをテストするには、
518 ネットワークにつながっている必要があります。常にネットワークが使用できるとは限りません。
522 このようなときのためにあるのが <classname>Zend_Http_Client_Adapter_Test</classname> アダプタです。
523 <classname>Zend_Http_Client</classname> を使用するアプリケーションを作成し、それをテストしたい場合には、
524 デフォルトのアダプタを Test アダプタ (モックオブジェクト) に変更します。
525 これで、サーバに接続せずにテストを行えるようになります。
529 <classname>Zend_Http_Client_Adapter_Test</classname> には setResponse() というメソッドがあります。
530 このメソッドのパラメータには、<acronym>HTTP</acronym> レスポンスをテキストか
531 <classname>Zend_Http_Response</classname> オブジェクトで指定できます。
532 レスポンスを設定すると、Test アダプタは常にこのレスポンスを返すようになります。
533 実際の <acronym>HTTP</acronym> リクエストは行いません。
536 <example id="zend.http.client.adapters.test.example-1">
537 <title>HTTP レスポンススタブを使用したテスト</title>
539 <programlisting language="php"><![CDATA[
540 // 新しいアダプタとクライアントのインスタンスを作成します
541 $adapter = new Zend_Http_Client_Adapter_Test();
542 $client = new Zend_Http_Client('http://www.example.com', array(
543 'adapter' => $adapter
547 $adapter->setResponse(
548 "HTTP/1.1 200 OK" . "\r\n" .
549 "Content-type: text/xml" . "\r\n" .
551 '<?xml version="1.0" encoding="UTF-8"?>' .
552 '<rss version="2.0" ' .
553 ' xmlns:content="http://purl.org/rss/1.0/modules/content/"' .
554 ' xmlns:wfw="http://wellformedweb.org/CommentAPI/"' .
555 ' xmlns:dc="http://purl.org/dc/elements/1.1/">' .
557 ' <title>Premature Optimization</title>' .
561 $response = $client->request('GET');
562 // .. $response の処理を続けます...
567 上の例のようにすると、<acronym>HTTP</acronym> クライアントにお望みのレスポンスを返させることができます。
568 その際にネットワーク接続は使用しません。また、実際のサーバからのレスポンスも使用しません。
570 レスポンス本文の <acronym>XML</acronym> をアプリケーションが正しくパースできるかどうかということです。
574 時には、オブジェクトに対するひとつのメソッド呼び出しの中で複数の
575 <acronym>HTTP</acronym> トランザクションを行うこともあるでしょう。そのような場合は
576 setResponse() を単独で使うことはできません。なぜなら、
577 結果が呼び出し元に返ってくるまで次のレスポンスを設定できないからです。
580 <example id="zend.http.client.adapters.test.example-2">
581 <title>複数の HTTP レスポンススタブを使用したテスト</title>
583 <programlisting language="php"><![CDATA[
584 // 新しいアダプタおよびクライアントのインスタンスを作成します
585 $adapter = new Zend_Http_Client_Adapter_Test();
586 $client = new Zend_Http_Client('http://www.example.com', array(
587 'adapter' => $adapter
590 // 最初の応答として期待する値を設定します
591 $adapter->setResponse(
592 "HTTP/1.1 302 Found" . "\r\n" .
593 "Location: /" . "\r\n" .
594 "Content-Type: text/html" . "\r\n" .
597 ' <head><title>Moved</title></head>' .
598 ' <body><p>This page has moved.</p></body>' .
602 $adapter->addResponse(
603 "HTTP/1.1 200 OK" . "\r\n" .
604 "Content-Type: text/html" . "\r\n" .
607 ' <head><title>My Pet Store Home Page</title></head>' .
608 ' <body><p>...</p></body>' .
611 // HTTP クライアントオブジェクト ($client) をテスト対象の
612 // オブジェクトに注入し、オブジェクトの動きを以下でテストします
618 <classname>Zend_Http_Client_Adapter_Test</classname> のバッファにあるレスポンスをすべて削除し、
619 最初に返されるレスポンスを設定します。addResponse()
620 メソッドは、それに続くレスポンスを追加します。
624 レスポンスは、それを追加した順に再生されます。
625 登録したよりも多くのリクエストが発生した場合は、
626 返されるレスポンスは最初のものに戻り、そこからまた順に返されるようになります。
630 上の例で、このアダプタがテストするように設定されているのは、
631 302 リダイレクトが発生した場合のオブジェクトの挙動です。
632 アプリケーションの内容によって、リダイレクトさせるべきなのかそうでないのかは異なるでしょう。
633 この例ではリダイレクトさせることを想定しているので、
634 テストアダプタもそれにあわせて設定しています。
635 最初の 302 レスポンスを setResponse() メソッドで設定し、
636 次に返される 200 レスポンスを addResponse() メソッドで設定します。
637 テストアダプタを設定し終えたら、そのアダプタを含む <acronym>HTTP</acronym>
638 クライアントをテスト対象オブジェクトに注入し、その挙動をテストします。
643 <methodname>setNextRequestWillFail($flag)</methodname> を使用します。
644 このメソッドは、次に <methodname>connect()</methodname> をコールしたときに
645 <classname>Zend_Http_Client_Adapter_Exception</classname>
646 を発生させます。これは、外部のサイトのコンテンツをキャッシュするアプリケーションで、
647 (外部サイトがダウンしていたときの) 挙動をテストする際に有用です。
650 <example id="zend.http.client.adapters.test.example-3">
651 <title>アダプタを失敗させる</title>
653 <programlisting language="php"><![CDATA[
654 // 新たなアダプタとクライアントを作成します
655 $adapter = new Zend_Http_Client_Adapter_Test();
656 $client = new Zend_Http_Client('http://www.example.com', array(
657 'adapter' => $adapter
660 // 次のリクエストでわざと例外を発生させます
661 $adapter->setNextRequestWillFail(true);
664 // これは Zend_Http_Client_Adapter_Exception となります
666 } catch (Zend_Http_Client_Adapter_Exception $e) {
670 // これ以降の処理は、 setNextRequestWillFail(true) を次に呼び出すまで
676 <sect2 id="zend.http.client.adapters.extending">
677 <title>独自の接続アダプタの作成</title>
680 独自の接続アダプタを作成し、それを使用することもできます。
681 たとえば持続的なソケットを使用するアダプタを作成したり、
682 キャッシュ機能を追加したアダプタを作成したりなど、
683 作成するアプリケーションの要件にあわせたものを作成することが可能です。
687 そのためには、<classname>Zend_Http_Client_Adapter_Interface</classname>
688 を実装したクラスを作成する必要があります。
689 以下の例は、ユーザ定義のアダプタクラスの雛形となります。
690 この例で定義されているすべてのパブリック関数を、
694 <example id="zend.http.client.adapters.extending.example-1">
695 <title>独自の接続アダプタの作成</title>
697 <programlisting language="php"><![CDATA[
698 class MyApp_Http_Client_Adapter_BananaProtocol
699 implements Zend_Http_Client_Adapter_Interface
704 * @param array $config
706 public function setConfig($config = array())
708 // ここはほとんど変更することはありません -
709 // 通常は Zend_Http_Client_Adapter_Socket の実装をコピーします
715 * @param string $host
717 * @param boolean $secure
719 public function connect($host, $port = 80, $secure = false)
727 * @param string $method
728 * @param Zend_Uri_Http $url
729 * @param string $http_ver
730 * @param array $headers
731 * @param string $body
732 * @return string Request as text
734 public function write($method,
740 // リクエストをリモートサーバに送信します。
741 // この関数は、リクエスト全体 (ヘッダおよび本文)
750 public function read()
752 // リモートサーバからのレスポンスを読み込み、それを文字列で返します。
759 public function close()
761 // リモートサーバとの接続を閉じます。最後にコールされます。
766 $client = new Zend_Http_Client(array(
767 'adapter' => 'MyApp_Http_Client_Adapter_BananaProtocol'