Zend_Http_Client-Adapters.xml 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- Reviewed: no -->
  3. <sect1 id="zend.http.client.adapters">
  4. <title>Zend_Http_Client - Connection Adapters</title>
  5. <sect2 id="zend.http.client.adapters.overview">
  6. <title>Overview</title>
  7. <para>
  8. Zend_Http_Client is based on a connection adapter design. The
  9. connection adapter is the object in charge of performing the
  10. actual connection to the server, as well as writing requests
  11. and reading responses.
  12. This connection adapter can be replaced, and you can create and
  13. extend the default connection adapters to suite your special needs,
  14. without the need to extend or replace the entire HTTP client
  15. class, and with the same interface.
  16. </para>
  17. <para>
  18. Currently, the Zend_Http_Client class provides three built-in
  19. connection adapters:
  20. <itemizedlist>
  21. <listitem>
  22. <para>
  23. <classname>Zend_Http_Client_Adapter_Socket</classname> (default)
  24. </para>
  25. </listitem>
  26. <listitem>
  27. <para>
  28. <classname>Zend_Http_Client_Adapter_Proxy</classname>
  29. </para>
  30. </listitem>
  31. <listitem>
  32. <para>
  33. <classname>Zend_Http_Client_Adapter_Test</classname>
  34. </para>
  35. </listitem>
  36. <listitem>
  37. <para>
  38. <classname>Zend_Http_Client_Adapter_Curl</classname>
  39. </para>
  40. </listitem>
  41. </itemizedlist>
  42. </para>
  43. <para>
  44. The Zend_Http_Client object's adapter connection adapter is set
  45. using the 'adapter' configuration option. When instantiating the
  46. client object, you can set the 'adapter' configuration option to
  47. a string containing the adapter's name (eg. 'Zend_Http_Client_Adapter_Socket')
  48. or to a variable holding an adapter object (eg. <code>
  49. new Zend_Http_Client_Adapter_Test</code>). You can also set the
  50. adapter later, using the Zend_Http_Client->setConfig() method.
  51. </para>
  52. </sect2>
  53. <sect2 id="zend.http.client.adapters.socket">
  54. <title>The Socket Adapter</title>
  55. <para>
  56. The default connection adapter is the Zend_Http_Client_Adapter_Socket
  57. adapter - this adapter will be used unless you explicitly set the
  58. connection adapter. The Socket adapter is based on PHP's built-in
  59. fsockopen() function, and does not require any special extensions or
  60. compilation flags.
  61. </para>
  62. <para>
  63. The Socket adapter allows several extra configuration options that
  64. can be set using <classname>Zend_Http_Client->setConfig()</classname> or
  65. passed to the client constructor.
  66. <table id="zend.http.client.adapter.socket.configuration.table">
  67. <title>Zend_Http_Client_Adapter_Socket configuration parameters</title>
  68. <tgroup cols="4">
  69. <thead>
  70. <row>
  71. <entry>Parameter</entry>
  72. <entry>Description</entry>
  73. <entry>Expected Type</entry>
  74. <entry>Default Value</entry>
  75. </row>
  76. </thead>
  77. <tbody>
  78. <row>
  79. <entry>persistent</entry>
  80. <entry>Whether to use persistent TCP connections</entry>
  81. <entry>boolean</entry>
  82. <entry>false</entry>
  83. </row>
  84. <row>
  85. <entry>ssltransport</entry>
  86. <entry>SSL transport layer (eg. 'sslv2', 'tls')</entry>
  87. <entry>string</entry>
  88. <entry>ssl</entry>
  89. </row>
  90. <row>
  91. <entry>sslcert</entry>
  92. <entry>Path to a PEM encoded SSL certificate</entry>
  93. <entry>string</entry>
  94. <entry>null</entry>
  95. </row>
  96. <row>
  97. <entry>sslpassphrase</entry>
  98. <entry>Passphrase for the SSL certificate file</entry>
  99. <entry>string</entry>
  100. <entry>null</entry>
  101. </row>
  102. </tbody>
  103. </tgroup>
  104. </table>
  105. <note>
  106. <title>Persistent TCP Connections</title>
  107. <para>
  108. Using persistent TCP connections can potentially speed up
  109. HTTP requests - but in most use cases, will have little
  110. positive effect and might overload the HTTP server you are
  111. connecting to.
  112. </para>
  113. <para>
  114. It is recommended to use persistent TCP connections only if
  115. you connect to the same server very frequently, and are
  116. sure that the server is capable of handling a large number
  117. of concurrent connections. In any case you are encouraged
  118. to benchmark the effect of persistent connections on both
  119. the client speed and server load before using this option.
  120. </para>
  121. <para>
  122. Additionally, when using persistent connections it is
  123. recommended to enable Keep-Alive HTTP requests as described
  124. in <xref linkend="zend.http.client.configuration" /> -
  125. otherwise persistent connections might have little or no
  126. effect.
  127. </para>
  128. </note>
  129. <note>
  130. <title>HTTPS SSL Stream Parameters</title>
  131. <para>
  132. <code>ssltransport, sslcert</code> and <code>sslpassphrase</code>
  133. are only relevant when connecting using HTTPS.
  134. </para>
  135. <para>
  136. While the default SSL settings should work for most
  137. applications, you might need to change them if the server
  138. you are connecting to requires special client setup. If so,
  139. you should read the sections about SSL transport layers and
  140. options <ulink url="http://www.php.net/manual/en/transports.php#transports.inet">here</ulink>.
  141. </para>
  142. </note>
  143. </para>
  144. <example id="zend.http.client.adapters.socket.example-1">
  145. <title>Changing the HTTPS transport layer</title>
  146. <programlisting language="php"><![CDATA[
  147. // Set the configuration parameters
  148. $config = array(
  149. 'adapter' => 'Zend_Http_Client_Adapter_Socket',
  150. 'ssltransport' => 'tls'
  151. );
  152. // Instantiate a client object
  153. $client = new Zend_Http_Client('https://www.example.com', $config);
  154. // The following request will be sent over a TLS secure connection.
  155. $response = $client->request();
  156. ]]></programlisting>
  157. </example>
  158. <para>
  159. The result of the example above will be similar to opening a TCP
  160. connection using the following PHP command:
  161. </para>
  162. <para>
  163. <code>fsockopen('tls://www.example.com', 443)</code>
  164. </para>
  165. </sect2>
  166. <sect2 id="zend.http.client.adapters.proxy">
  167. <title>The Proxy Adapter</title>
  168. <para>
  169. The Zend_Http_Client_Adapter_Proxy adapter is similar to the default
  170. Socket adapter - only the connection is made through an HTTP proxy
  171. server instead of a direct connection to the target server. This
  172. allows usage of Zend_Http_Client behind proxy servers - which is
  173. sometimes needed for security or performance reasons.
  174. </para>
  175. <para>
  176. Using the Proxy adapter requires several additional configuration
  177. parameters to be set, in addition to the default 'adapter' option:
  178. <table id="zend.http.client.adapters.proxy.table">
  179. <title>Zend_Http_Client configuration parameters</title>
  180. <tgroup cols="4">
  181. <thead>
  182. <row>
  183. <entry>Parameter</entry>
  184. <entry>Description</entry>
  185. <entry>Expected Type</entry>
  186. <entry>Example Value</entry>
  187. </row>
  188. </thead>
  189. <tbody>
  190. <row>
  191. <entry>proxy_host</entry>
  192. <entry>Proxy server address</entry>
  193. <entry>string</entry>
  194. <entry>'proxy.myhost.com' or '10.1.2.3'</entry>
  195. </row>
  196. <row>
  197. <entry>proxy_port</entry>
  198. <entry>Proxy server TCP port</entry>
  199. <entry>integer</entry>
  200. <entry>8080 (default) or 81</entry>
  201. </row>
  202. <row>
  203. <entry>proxy_user</entry>
  204. <entry>Proxy user name, if required</entry>
  205. <entry>string</entry>
  206. <entry>'shahar' or '' for none (default)</entry>
  207. </row>
  208. <row>
  209. <entry>proxy_pass</entry>
  210. <entry>Proxy password, if required</entry>
  211. <entry>string</entry>
  212. <entry>'secret' or '' for none (default)</entry>
  213. </row>
  214. <row>
  215. <entry>proxy_auth</entry>
  216. <entry>Proxy HTTP authentication type</entry>
  217. <entry>string</entry>
  218. <entry>Zend_Http_Client::AUTH_BASIC (default)</entry>
  219. </row>
  220. </tbody>
  221. </tgroup>
  222. </table>
  223. </para>
  224. <para>
  225. proxy_host should always be set - if it is not set, the client will
  226. fall back to a direct connection using Zend_Http_Client_Adapter_Socket.
  227. proxy_port defaults to '8080' - if your proxy listens on a different
  228. port you must set this one as well.
  229. </para>
  230. <para>
  231. proxy_user and proxy_pass are only required if your proxy server
  232. requires you to authenticate. Providing these will add a 'Proxy-Authentication'
  233. header to the request. If your proxy does not require authentication,
  234. you can leave these two options out.
  235. </para>
  236. <para>
  237. proxy_auth sets the proxy authentication type, if your proxy server
  238. requires authentication. Possibly values are similar to the ones
  239. accepted by the Zend_Http_Client::setAuth() method. Currently, only
  240. basic authentication (Zend_Http_Client::AUTH_BASIC) is supported.
  241. </para>
  242. <example id="zend.http.client.adapters.proxy.example-1">
  243. <title>Using Zend_Http_Client behind a proxy server</title>
  244. <programlisting language="php"><![CDATA[
  245. // Set the configuration parameters
  246. $config = array(
  247. 'adapter' => 'Zend_Http_Client_Adapter_Proxy',
  248. 'proxy_host' => 'proxy.int.zend.com',
  249. 'proxy_port' => 8000,
  250. 'proxy_user' => 'shahar.e',
  251. 'proxy_pass' => 'bananashaped'
  252. );
  253. // Instantiate a client object
  254. $client = new Zend_Http_Client('http://www.example.com', $config);
  255. // Continue working...
  256. ]]></programlisting>
  257. </example>
  258. <para>
  259. As mentioned, if proxy_host is not set or is set to a blank string,
  260. the connection will fall back to a regular direct connection. This
  261. allows you to easily write your application in a way that allows a
  262. proxy to be used optionally, according to a configuration parameter.
  263. </para>
  264. </sect2>
  265. <sect2 id="zend.http.client.adapters.test">
  266. <title>The Test Adapter</title>
  267. <para>
  268. Sometimes, it is very hard to test code that relies on HTTP connections.
  269. For example, testing an application that pulls an RSS feed from a remote
  270. server will require a network connection, which is not always available.
  271. </para>
  272. <para>
  273. For this reason, the Zend_Http_Client_Adapter_Test adapter is
  274. provided. You can write your application to use Zend_Http_Client,
  275. and just for testing purposes, for example in your unit testing
  276. suite, you can replace the default adapter with a Test adapter (a
  277. mock object), allowing you to run tests without actually
  278. performing server connections.
  279. </para>
  280. <para>
  281. The Zend_Http_Client_Adapter_Test adapter provides an additional
  282. method, setResponse() method. This method takes one parameter,
  283. which represents an HTTP response as either text or a Zend_Http_Response
  284. object. Once set, your Test adapter will always return this response,
  285. without even performing an actual HTTP request.
  286. </para>
  287. <example id="zend.http.client.adapters.test.example-1">
  288. <title>Testing Against a Single HTTP Response Stub</title>
  289. <programlisting language="php"><![CDATA[
  290. // Instantiate a new adapter and client
  291. $adapter = new Zend_Http_Client_Adapter_Test();
  292. $client = new Zend_Http_Client('http://www.example.com', array(
  293. 'adapter' => $adapter
  294. ));
  295. // Set the expected response
  296. $adapter->setResponse(
  297. "HTTP/1.1 200 OK" . "\r\n" .
  298. "Content-type: text/xml" . "\r\n" .
  299. "\r\n" .
  300. '<?xml version="1.0" encoding="UTF-8"?>' .
  301. '<rss version="2.0" ' .
  302. ' xmlns:content="http://purl.org/rss/1.0/modules/content/"' .
  303. ' xmlns:wfw="http://wellformedweb.org/CommentAPI/"' .
  304. ' xmlns:dc="http://purl.org/dc/elements/1.1/">' .
  305. ' <channel>' .
  306. ' <title>Premature Optimization</title>' .
  307. // and so on...
  308. '</rss>');
  309. $response = $client->request('GET');
  310. // .. continue parsing $response..
  311. ]]></programlisting>
  312. </example>
  313. <para>
  314. The above example shows how you can preset your HTTP client to
  315. return the response you need. Then, you can continue testing your
  316. own code, without being dependent on a network connection, the server's
  317. response, etc. In this case, the test would continue to check how
  318. the application parses the XML in the response body.
  319. </para>
  320. <para>
  321. Sometimes, a single method call to an object can result in that
  322. object performing multiple HTTP transactions. In this case, it's
  323. not possible to use setResponse() alone because there's no
  324. opportunity to set the next response(s) your program might need
  325. before returning to the caller.
  326. </para>
  327. <example id="zend.http.client.adapters.test.example-2">
  328. <title>Testing Against Multiple HTTP Response Stubs</title>
  329. <programlisting language="php"><![CDATA[
  330. // Instantiate a new adapter and client
  331. $adapter = new Zend_Http_Client_Adapter_Test();
  332. $client = new Zend_Http_Client('http://www.example.com', array(
  333. 'adapter' => $adapter
  334. ));
  335. // Set the first expected response
  336. $adapter->setResponse(
  337. "HTTP/1.1 302 Found" . "\r\n" .
  338. "Location: /" . "\r\n" .
  339. "Content-Type: text/html" . "\r\n" .
  340. "\r\n" .
  341. '<html>' .
  342. ' <head><title>Moved</title></head>' .
  343. ' <body><p>This page has moved.</p></body>' .
  344. '</html>');
  345. // Set the next successive response
  346. $adapter->addResponse(
  347. "HTTP/1.1 200 OK" . "\r\n" .
  348. "Content-Type: text/html" . "\r\n" .
  349. "\r\n" .
  350. '<html>' .
  351. ' <head><title>My Pet Store Home Page</title></head>' .
  352. ' <body><p>...</p></body>' .
  353. '</html>');
  354. // inject the http client object ($client) into your object
  355. // being tested and then test your object's behavior below
  356. ]]></programlisting>
  357. </example>
  358. <para>
  359. The setResponse() method clears any responses in the
  360. Zend_Http_Client_Adapter_Test's buffer and sets the
  361. first response that will be returned. The addResponse()
  362. method will add successive responses.
  363. </para>
  364. <para>
  365. The responses will be replayed in the order that they
  366. were added. If more requests are made than the number
  367. of responses stored, the responses will cycle again
  368. in order.
  369. </para>
  370. <para>
  371. In the example above, the adapter is configured to test your
  372. object's behavior when it encounters a 302 redirect. Depending on
  373. your application, following a redirect may or may not be desired
  374. behavior. In our example, we expect that the redirect will be
  375. followed and we configure the test adapter to help us test this.
  376. The initial 302 response is set up with the setResponse() method
  377. and the 200 response to be returned next is added with the
  378. addResponse() method. After configuring the test adapter, inject
  379. the HTTP client containing the adapter into your object under test
  380. and test its behavior.
  381. </para>
  382. </sect2>
  383. <sect2 id="zend.http.client.adapters.curl">
  384. <title>The cURL Adapter</title>
  385. <para>
  386. cURL is a standard HTTP client library that is distributed with many
  387. operating systems and can be used in PHP via the cURL extension. It
  388. offers functionality for many special cases which can occur for a HTTP
  389. client and make it a perfect choice for a HTTP adapter. It supports
  390. secure connections, proxy, all sorts of authentication mechanisms
  391. and shines in applications that move large files around between servers.
  392. </para>
  393. <example id="zend.http.client.adapters.curl.example-1">
  394. <title>Setting cURL options</title>
  395. <programlisting language="php"><![CDATA[
  396. $config = array(
  397. 'adapter' => 'Zend_Http_Client_Adapter_Curl',
  398. 'curloptions' => array(CURLOPT_FOLLOWLOCATION => true),
  399. );
  400. $client = new Zend_Http_Client($uri, $config);
  401. ]]></programlisting>
  402. </example>
  403. <para>
  404. By default the cURL adapter is configured to behave exactly like
  405. the Socket Adapter. You can change the cURL options by either specifying
  406. the 'curloptions' key in the constructor of the adapter or by calling
  407. <code>setCurlOption($name, $value)</code>. The <code>$name</code> key
  408. corresponds to the CURL_* constants of the cURL extension.
  409. </para>
  410. <example id="zend.http.client.adapters.curl.example-2">
  411. <title>Transfering Files by Handle</title>
  412. <para>
  413. You can use cURL to transfer very large files over HTTP by filehandle.
  414. </para>
  415. <programlisting language="php"><![CDATA[
  416. $putFileSize = filesize("filepath");
  417. $putFileHandle = fopen("filepath", "r");
  418. $adapter = new Zend_Http_Client_Adapter_Curl();
  419. $client = new Zend_Http_Client();
  420. $client->setAdapter($adapter);
  421. $adapter->setConfig(array(
  422. 'curloptions' => array(
  423. CURLOPT_INFILE => $putFileHandle,
  424. CURLOPT_INFILESIZE => $putFileSize
  425. )
  426. ));
  427. $client->request("PUT");
  428. ]]></programlisting>
  429. </example>
  430. </sect2>
  431. <sect2 id="zend.http.client.adapters.extending">
  432. <title>Creating your own connection adapters</title>
  433. <para>
  434. You can create your own connection adapters and use them. You could, for
  435. example, create a connection adapter that uses persistent sockets,
  436. or a connection adapter with caching abilities, and use them as
  437. needed in your application.
  438. </para>
  439. <para>
  440. In order to do so, you must create your own adapter class that implements
  441. the Zend_Http_Client_Adapter_Interface interface. The following example
  442. shows the skeleton of a user-implemented adapter class. All the public
  443. functions defined in this example must be defined in your adapter as well:
  444. </para>
  445. <example id="zend.http.client.adapters.extending.example-1">
  446. <title>Creating your own connection adapter</title>
  447. <programlisting language="php"><![CDATA[
  448. class MyApp_Http_Client_Adapter_BananaProtocol
  449. implements Zend_Http_Client_Adapter_Interface
  450. {
  451. /**
  452. * Set the configuration array for the adapter
  453. *
  454. * @param array $config
  455. */
  456. public function setConfig($config = array())
  457. {
  458. // This rarely changes - you should usually copy the
  459. // implementation in Zend_Http_Client_Adapter_Socket.
  460. }
  461. /**
  462. * Connect to the remote server
  463. *
  464. * @param string $host
  465. * @param int $port
  466. * @param boolean $secure
  467. */
  468. public function connect($host, $port = 80, $secure = false)
  469. {
  470. // Set up the connection to the remote server
  471. }
  472. /**
  473. * Send request to the remote server
  474. *
  475. * @param string $method
  476. * @param Zend_Uri_Http $url
  477. * @param string $http_ver
  478. * @param array $headers
  479. * @param string $body
  480. * @return string Request as text
  481. */
  482. public function write($method,
  483. $url,
  484. $http_ver = '1.1',
  485. $headers = array(),
  486. $body = '')
  487. {
  488. // Send request to the remote server.
  489. // This function is expected to return the full request
  490. // (headers and body) as a string
  491. }
  492. /**
  493. * Read response from server
  494. *
  495. * @return string
  496. */
  497. public function read()
  498. {
  499. // Read response from remote server and return it as a string
  500. }
  501. /**
  502. * Close the connection to the server
  503. *
  504. */
  505. public function close()
  506. {
  507. // Close the connection to the remote server - called last.
  508. }
  509. }
  510. // Then, you could use this adapter:
  511. $client = new Zend_Http_Client(array(
  512. 'adapter' => 'MyApp_Http_Client_Adapter_BananaProtocol'
  513. ));
  514. ]]></programlisting>
  515. </example>
  516. </sect2>
  517. </sect1>