Zend_Http_Client-Adapters.xml 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 24249 -->
  3. <!-- Reviewed: 22743 -->
  4. <sect1 id="zend.http.client.adapters">
  5. <title>Zend_Http_Client - Verbindungsadapter</title>
  6. <sect2 id="zend.http.client.adapters.overview">
  7. <title>Verbindungsadapter</title>
  8. <para>
  9. <classname>Zend_Http_Client</classname> basiert auf einem Design mit
  10. Verbindungsadaptern. Der Verbindungsadapter ist das Objekt, welches für die Ausführung
  11. der aktuellen Verbindung zum Server sowie für das Schreiben der Anfragen und Lesen von
  12. Antworten verantwortlich ist. Dieser Verbindungsadapter kann ersetzt werden und man kann
  13. den Standard-Verbindungsadapter durch seinen eigenen Adapter erweitern, um ihn mit
  14. demselben Interface auf seine eigenen Bedürfnisse anzupassen, ohne dass man die gesamte
  15. <acronym>HTTP</acronym> Client-Klasse erweitern oder ersetzen muss.
  16. </para>
  17. <para>
  18. Derzeit stellt die <classname>Zend_Http_Client</classname>-Klasse vier eingebaute
  19. Verbindungsadapter bereit:
  20. <itemizedlist>
  21. <listitem>
  22. <para>
  23. <classname>Zend_Http_Client_Adapter_Socket</classname> (Standard)
  24. </para>
  25. </listitem>
  26. <listitem>
  27. <para><classname>Zend_Http_Client_Adapter_Proxy</classname></para>
  28. </listitem>
  29. <listitem>
  30. <para><classname>Zend_Http_Client_Adapter_Curl</classname></para>
  31. </listitem>
  32. <listitem>
  33. <para><classname>Zend_Http_Client_Adapter_Test</classname></para>
  34. </listitem>
  35. </itemizedlist>
  36. </para>
  37. <para>
  38. Der Verbindungsadapter für das <classname>Zend_Http_Client</classname>-Objekt wird durch
  39. Verwendung der Konfigurationsoption 'adapter' gesetzt. Beim Instanzieren des Client
  40. Objektes kann man die Konfigurationsoption 'adapter' mit einem String setzen, der den
  41. Adapternamen (z.B. 'Zend_Http_Client_Adapter_Socket') enthält, oder mit einer Variablen,
  42. die ein Adapterobjekt (z.B. <command>new Zend_Http_Client_Adapter_Test</command>)
  43. enthält. Man kann den Adapter auch danach setzen, indem man die
  44. <classname>Zend_Http_Client->setConfig()</classname> Methode verwendet.
  45. </para>
  46. </sect2>
  47. <sect2 id="zend.http.client.adapters.socket">
  48. <title>Der Socket-Adapter</title>
  49. <para>
  50. Der Standard-Adapter ist <classname>Zend_Http_Client_Adapter_Socket</classname>.
  51. Dieser wird benutzt, wenn kein anderer angegeben wird. Der Socket-Adapter benutzt die
  52. native <acronym>PHP</acronym>-Funktion fsockopen(), um die Verbindung aufzubauen, dafür
  53. werden keine besonderen Erweiterungen oder Einstellungen benötigt.
  54. </para>
  55. <para>
  56. Der Socket-Adapter erlaubt verschiedene zusätzliche Konfigurationsoptionen, die gesetzt
  57. werden können durch Verwendung von <classname>Zend_Http_Client->setConfig()</classname>
  58. oder deren Übergabe an den Konstruktor des Clients.
  59. <table id="zend.http.client.adapter.socket.configuration.table">
  60. <title>Zend_Http_Client_Adapter_Socket Konfigurationsparameter</title>
  61. <tgroup cols="4">
  62. <thead>
  63. <row>
  64. <entry>Parameter</entry>
  65. <entry>Beschreibung</entry>
  66. <entry>Erwarteter Typ</entry>
  67. <entry>Standardwert</entry>
  68. </row>
  69. </thead>
  70. <tbody>
  71. <row>
  72. <entry>persistent</entry>
  73. <entry>
  74. Ob eine persistente <acronym>TCP</acronym>-Verbindung verwendet
  75. werden soll oder nicht
  76. </entry>
  77. <entry>boolean</entry>
  78. <entry><constant>FALSE</constant></entry>
  79. </row>
  80. <row>
  81. <entry>ssltransport</entry>
  82. <entry>Der Transport-Layer für SSL (z.B. 'sslv2', 'tls')</entry>
  83. <entry>string</entry>
  84. <entry>ssl</entry>
  85. </row>
  86. <row>
  87. <entry>sslcert</entry>
  88. <entry>
  89. Pfad zu einem <acronym>PEM</acronym> verschlüsselten
  90. <acronym>SSL</acronym>-Zertifikat
  91. </entry>
  92. <entry>string</entry>
  93. <entry><constant>NULL</constant></entry>
  94. </row>
  95. <row>
  96. <entry>sslpassphrase</entry>
  97. <entry>
  98. Die PassPhrase für die <acronym>SSL</acronym> zertifizierte Datei
  99. </entry>
  100. <entry>string</entry>
  101. <entry><constant>NULL</constant></entry>
  102. </row>
  103. <row>
  104. <entry>sslusecontext</entry>
  105. <entry>
  106. Aktiviert, dass Proxy Verbindungen SSL verwenden sogar wenn die Proxy
  107. Verbindung selbst es nicht tut.
  108. </entry>
  109. <entry>boolean</entry>
  110. <entry><constant>FALSE</constant></entry>
  111. </row>
  112. </tbody>
  113. </tgroup>
  114. </table>
  115. <note>
  116. <title>Persistente TCP Verbindungen</title>
  117. <para>
  118. Die Verwendung persistenter <acronym>TCP</acronym>-Verbindungen kann
  119. <acronym>HTTP</acronym>-Anfragen potentiell schneller machen - aber in den
  120. meisten Fällen, wird es nur einen kleinen positiven Effekt haben und könnte den
  121. <acronym>HTTP</acronym>-Server überlasten, zu dem man sich verbindet.
  122. </para>
  123. <para>
  124. Es wird empfohlen persistente <acronym>TCP</acronym>-Verbindungen nur dann zu
  125. verwenden, wenn man sich zu dem gleichen Server sehr oft verbindet, und man
  126. sicher ist, dass der Server eine große Anzahl an gleichzeitigen Verbindungen
  127. behandeln kann. In jedem Fall wird empfohlen, dass der Effekt von persistenten
  128. Verbindungen auf beiden, der Geschwindigkeit des Clients und dem Serverload
  129. gemessen wird, bevor diese Option verwendet wird.
  130. </para>
  131. <para>
  132. Zusätzlich, wenn persistente Verbindungen verwendet werden, sollte man
  133. Keep-Alive <acronym>HTTP</acronym>-Anfragen aktivieren wie im <link
  134. linkend="zend.http.client.configuration">Abschnitt für Konfiguration</link>
  135. beschrieben - andernfalls werden persistente Verbindungen nur wenig oder gar
  136. keinen Effekt haben.
  137. </para>
  138. </note>
  139. <note>
  140. <title>HTTPS SSL Stream Parameter</title>
  141. <para>
  142. <property>ssltransport</property>, <property>sslcert</property> und
  143. <property>sslpassphrase</property> sind nur relevant wenn
  144. <acronym>HTTPS</acronym> für die Verbindung verwendet wird.
  145. </para>
  146. <para>
  147. Wärend die Standard <acronym>SSL</acronym>-Einstellungen für die meisten
  148. Anwendungen funktionieren, kann es notwendig sein diese zu ändern, wenn der
  149. Server zu dem man sich verbindet ein spezielles Client-Setup benötigt. Wenn dem
  150. so ist, sollte man das Kapitel über <acronym>SSL</acronym>-Transport-Layer und
  151. Optionen lesen das <ulink
  152. url="http://www.php.net/manual/en/transports.php#transports.inet">hier</ulink>
  153. zu finden ist.
  154. </para>
  155. </note>
  156. </para>
  157. <example id="zend.http.client.adapters.socket.example-1">
  158. <title>Den Stream-Typen für eine HTTPS-Verbindung einstellen</title>
  159. <programlisting language="php"><![CDATA[
  160. // Konfigurationsparameter setzen
  161. $config = array(
  162. 'adapter' => 'Zend_Http_Client_Adapter_Socket',
  163. 'ssltransport' => 'tls'
  164. );
  165. // Client-Instanz erzeugen
  166. $client = new Zend_Http_Client('https://www.example.com', $config);
  167. // Jetzt wird der Request über eine verschlüsselte Verbindung verschickt
  168. $response = $client->request();
  169. ]]></programlisting>
  170. </example>
  171. <para>
  172. Ein ähnliches Ergebnis erzielt man mit folgendem Code:
  173. </para>
  174. <para>
  175. <methodname>fsockopen('tls://www.example.com', 443)</methodname>
  176. </para>
  177. <sect3 id="zend.http.client.adapters.socket.streamcontext">
  178. <title>Anpassen und Zugreifen auf den Socket Adapter Stream Kontext</title>
  179. <para>
  180. Beginnend mit Zend Framework 1.9 bietet
  181. <classname>Zend_Http_Client_Adapter_Socket</classname> direkten Zugriff auf den
  182. darunterliegenden <ulink
  183. url="http://php.net/manual/de/stream.contexts.php">Stream Kontext</ulink> der
  184. für die Verbindung zum entfernten Server verwendet wird. Das erlaubt es
  185. Benutzern spezielle Optionen und Parameter an den <acronym>TCP</acronym>-Stream zu
  186. übergeben und an den <acronym>SSL</acronym>-Wrapper im Falle einer
  187. <acronym>HTTPS</acronym>-Verbindung.
  188. </para>
  189. <para>
  190. Man kann auf den Stream Kontext zugreifen indem die folgenden Methoden von
  191. <classname>Zend_Http_Client_Adapter_Socket</classname> verwendet werden:
  192. <itemizedlist>
  193. <listitem>
  194. <para>
  195. <firstterm><methodname>setStreamContext($context)</methodname></firstterm>
  196. Setzt den Stream Kontext der vom Adapter verwendet werden soll.
  197. Akzeptiert entweder eine Stream Kontext Ressource von durch die
  198. Verwendung der <acronym>PHP</acronym> Funktion <ulink
  199. url="http://php.net/manual/de/function.stream-context-create.php"><methodname>stream_context_create()</methodname></ulink>
  200. erstellt wurde, oder ein Array von Stream Kontext Optionen im
  201. gleichen Format wie es an diese Funktion übergeben wird. Wenn ein
  202. Array übergeben wird, dann wird ein neuer Stream Kontext mit Hilfe
  203. dieser Optionen erstellt, und gesetzt.
  204. </para>
  205. </listitem>
  206. <listitem>
  207. <para>
  208. <firstterm><methodname>getStreamContext()</methodname></firstterm>
  209. Empfängt den Stream Kontext des Adapters. Wenn kein Stream Kontext
  210. gesetzt ist, wird ein standardmäßiger Stream Kontext erstellt und
  211. zurückgegeben. Man kann anschließend den Wert verschiedener Kontext
  212. Optionen setzen oder empfangen indem die regulären
  213. <acronym>PHP</acronym> Stream Kontext Funktionen verwendet werden.
  214. </para>
  215. </listitem>
  216. </itemizedlist>
  217. </para>
  218. <example id="zend.http.client.adapters.socket.streamcontext.example-1">
  219. <title>Setzen von Stream Kontext Optionen für den Socket Adapter</title>
  220. <programlisting language="php"><![CDATA[
  221. // Array von Optionen
  222. $options = array(
  223. 'socket' => array(
  224. // Bindet die lokale Socket Seite an ein spezifisches Interface
  225. 'bindto' => '10.1.2.3:50505'
  226. ),
  227. 'ssl' => array(
  228. // Prüft das Server Side Zertifikat, akzeptiert keine
  229. // ungültigen oder selbst-signierten SSL Zertifikate
  230. 'verify_peer' => true,
  231. 'allow_self_signed' => false,
  232. // Holt das Peer Zertifikat
  233. 'capture_peer_cert' => true
  234. )
  235. );
  236. // Erstellt ein Adapter Objekt und hängt es an den HTTP Client
  237. $adapter = new Zend_Http_Client_Adapter_Socket();
  238. $client = new Zend_Http_Client();
  239. $client->setAdapter($adapter);
  240. // Methode 1: Ein Options Array an setStreamContext() übergeben
  241. $adapter->setStreamContext($options);
  242. // Methode 2: Einen Stream Kontext erstellen und an setStreamContext() übergeben
  243. $context = stream_context_create($options);
  244. $adapter->setStreamContext($context);
  245. // Methode 3: Den Standardmäßigen Stream Kontext holen und Optionen auf Ihm setzen
  246. $context = $adapter->getStreamContext();
  247. stream_context_set_option($context, $options);
  248. // Jetzt die Anfrage durchführen
  249. $response = $client->request();
  250. // Wenn alles gut ging, kann auf den Kontext jetzt zugegriffen werden
  251. $opts = stream_context_get_options($adapter->getStreamContext());
  252. echo $opts['ssl']['peer_certificate'];
  253. ]]></programlisting>
  254. </example>
  255. <note>
  256. <para>
  257. Es ist zu beachten das alle Stream Kontext Optionen gesetzt sein müssen, bevor
  258. der Adapter Anfragen durchführt. Wenn kein Kontext gesetzt ist bevor
  259. <acronym>HTTP</acronym>-Anfragen mit dem Socket Adapter durchgeführt werden,
  260. wird ein standardmäßiger Stream Kontext erstellt. Auf diese Kontext Ressource
  261. kann zugegriffen werden, nachdem Anfragen durchgeführt werden, indem die
  262. <methodname>getStreamContext()</methodname> Methode verwendet wird.
  263. </para>
  264. </note>
  265. </sect3>
  266. </sect2>
  267. <sect2 id="zend.http.client.adapters.proxy">
  268. <title>Der Proxy Adapter</title>
  269. <para>
  270. Der Proxy Adapter <classname>Zend_Http_Client_Adapter_Proxy</classname> verhält sich wie
  271. der Standard-<classname>Zend_Http_Client_Adapter_Socket</classname>, mit dem
  272. Unterschied, dass die Verbindung über einen <acronym>HTTP</acronym>-Proxy-Server
  273. aufgebaut wird statt den Server direkt zu kontaktieren. Das erlaubt die Verwendung von
  274. <classname>Zend_Http_Client</classname> hinter Proxy Servern - was manchmal wegen der
  275. Sicherheit und Geschwindigkeit notwendig ist.
  276. </para>
  277. <para>
  278. Der Proxy Adapter benötigt zusätzliche Konfigurationsvariablen, die
  279. nachfolgend gelistet sind.
  280. <table id="zend.http.client.adapters.proxy.table">
  281. <title>Zend_Http_Client Konfigurationsparameter</title>
  282. <tgroup cols="4">
  283. <thead>
  284. <row>
  285. <entry>Parameter</entry>
  286. <entry>Beschreibung</entry>
  287. <entry>Datentyp</entry>
  288. <entry>Beispielwert</entry>
  289. </row>
  290. </thead>
  291. <tbody>
  292. <row>
  293. <entry>proxy_host</entry>
  294. <entry>Proxy Server Adresse</entry>
  295. <entry>string</entry>
  296. <entry>zum Beispiel 'proxy.myhost.com' oder '10.1.2.3'</entry>
  297. </row>
  298. <row>
  299. <entry>proxy_port</entry>
  300. <entry><acronym>TCP</acronym> Port des Proxy-Servers</entry>
  301. <entry>integer</entry>
  302. <entry>8080 (Standardwert) oder 81</entry>
  303. </row>
  304. <row>
  305. <entry>proxy_user</entry>
  306. <entry>Benutzername für die Proxynutzung, falls nötig</entry>
  307. <entry>string</entry>
  308. <entry>'wulli' oder '' für keinen Namen (Standardwert)</entry>
  309. </row>
  310. <row>
  311. <entry>proxy_pass</entry>
  312. <entry>Passwort für die Proxynutzung, falls nötig</entry>
  313. <entry>string</entry>
  314. <entry>'geheim' oder '' für kein Passwort (Standardwert)</entry>
  315. </row>
  316. <row>
  317. <entry>proxy_auth</entry>
  318. <entry>Proxy <acronym>HTTP</acronym> Authentifizierungs-Typ</entry>
  319. <entry>string</entry>
  320. <entry>Zend_Http_Client::AUTH_BASIC (Standardwert)</entry>
  321. </row>
  322. </tbody>
  323. </tgroup>
  324. </table>
  325. </para>
  326. <para>
  327. proxy_host muss immer gesetzt werden, ansonsten wird der Proxy-Adapter auf
  328. <classname>Zend_Http_Client_Adapter_Socket</classname> zurückgreifen und keinen Proxy
  329. Server benutzen. Wird kein Prot mit übergeben, so versucht der Proxy-Adapter sich auf
  330. den Standardport '8080' zu verbinden.
  331. </para>
  332. <para>
  333. proxy_user und proxy_pass werden nur dann benötigt, wenn der Proxy-Server
  334. tatsächlich eine Authentifizierung erwartet. Werden diese Parameter mit
  335. übergeben, setzt der Proxy-Adapter zusätzlich den 'Proxy-Authentication'
  336. Header bei Anfragen. Wird keine Authentifizierung benötigt, sollten die
  337. beiden Parameter weggelassen werden.
  338. </para>
  339. <para>
  340. proxy_auth setzt den Authentifizierungs-Typ. Dies ist nur nötig, wenn der
  341. Proxy-Server eine Authentifizierung erwartet.
  342. Mögliche Werte entsprechen denen der Zend_Http_Client::setAuth() Methode.
  343. Zur Zeit wird nur die BASIC-Authentifizierung
  344. (Zend_Http_Client::AUTH_BASIC) unterstützt.
  345. </para>
  346. <example id="zend.http.client.adapters.proxy.example-1">
  347. <title>Zend_Http_Client hinter einem Proxy-Server nutzen</title>
  348. <programlisting language="php"><![CDATA[
  349. // Konfigurationsparameter setzen
  350. $config = array(
  351. 'adapter' => 'Zend_Http_Client_Adapter_Proxy',
  352. 'proxy_host' => 'proxy.int.zend.com',
  353. 'proxy_port' => 8000,
  354. 'proxy_user' => 'shahar.e',
  355. 'proxy_pass' => 'bananashaped'
  356. );
  357. // Client-Objekt instanziieren
  358. $client = new Zend_Http_Client('http://www.example.com', $config);
  359. // $client kann jetzt wie gewohnt benutzt werden
  360. ]]></programlisting>
  361. </example>
  362. <para>
  363. Wie vorher erwähnt, nutzt der Proxy-Adapter eine einfache Socket-Verbindung,
  364. wenn proxy_host nicht gesetzt oder leer gelassen wurde. Dies ermöglicht
  365. die optionale Nutzung eines Proxy-Servers, abhängig von dem proxy_host Parameter.
  366. </para>
  367. <note>
  368. <para>
  369. Da der Proxy Adapter von <classname>Zend_Http_Client_Adapter_Socket</classname>
  370. abgeleitet ist, kann die Stream Kontext Zugriffsmethode verwendet werden
  371. (siehe <link linkend="zend.http.client.adapters.socket.streamcontext">den Abschnitt
  372. für Konfiguration</link>) um Stream Kontext Optionen auf Proxy Verbindungen zu
  373. setzen wie es oben demonstriert wurde.
  374. </para>
  375. </note>
  376. </sect2>
  377. <sect2 id="zend.http.client.adapters.curl">
  378. <title>Der cURL Adapter</title>
  379. <para>
  380. cURL ist eine Standard <acronym>HTTP</acronym> Client Bibliothek die mit vielen
  381. Betriebssystemen ausgeliefert wird, und kann in <acronym>PHP</acronym> über die cURL
  382. Erweiterung verwendet werden. Sie bietet Funktionalitäten für viele spezielle Fälle, die
  383. für einen <acronym>HTTP</acronym>-Client auftreten können und machen sie zu einer
  384. perfekten Wahl für einen <acronym>HTTP</acronym>-Adapter. Sie unterstützt sichere
  385. Verbindungen, Proxies, alle Arten von Authentifizierungsmechanismen und glänzt in
  386. Anwendungen, die große Dateien zwischen Servern bewegen müssen.
  387. </para>
  388. <example id="zend.http.client.adapters.curl.example-1">
  389. <title>Setzen von cURL Optionen</title>
  390. <programlisting language="php"><![CDATA[
  391. $config = array(
  392. 'adapter' => 'Zend_Http_Client_Adapter_Curl',
  393. 'curloptions' => array(CURLOPT_FOLLOWLOCATION => true),
  394. );
  395. $client = new Zend_Http_Client($uri, $config);
  396. ]]></programlisting>
  397. </example>
  398. <para>
  399. Standardmäßig ist der cURL Adapter so konfiguriert, dass er sich genauso wie der
  400. Socket Adapter verhält und er akzeptiert auch die gleichen Konfigurationsparameter wie
  401. die Socket und Proxy Adapter. Man kann die cURL Optionen entweder durch den
  402. 'curloptions' Schlüssel im Konstruktor des Adapters, oder durch den Aufruf von
  403. <methodname>setCurlOption($name, $value)</methodname>, verändern. Der
  404. <varname>$name</varname> Schlüssel entspricht den CURL_* Konstanten der cURL
  405. Erweiterung. Man kann auf den CURL Handler durch den Aufruf von
  406. <command>$adapter->getHandle();</command> Zugriff erhalten.
  407. </para>
  408. <example id="zend.http.client.adapters.curl.example-2">
  409. <title>Dateien von Hand übertragen</title>
  410. <para>
  411. Man kan cURL verwenden um große Dateien über <acronym>HTTP</acronym> durch einen
  412. Dateihandle zu übertragen.
  413. </para>
  414. <programlisting language="php"><![CDATA[
  415. $putFileSize = filesize("filepath");
  416. $putFileHandle = fopen("filepath", "r");
  417. $adapter = new Zend_Http_Client_Adapter_Curl();
  418. $client = new Zend_Http_Client();
  419. $client->setAdapter($adapter);
  420. $adapter->setConfig(array(
  421. 'curloptions' => array(
  422. CURLOPT_INFILE => $putFileHandle,
  423. CURLOPT_INFILESIZE => $putFileSize
  424. )
  425. ));
  426. $client->request("PUT");
  427. ]]></programlisting>
  428. </example>
  429. </sect2>
  430. <sect2 id="zend.http.client.adapters.test">
  431. <title>Der Test Adapter</title>
  432. <para>
  433. Manchmal ist es sehr schwer Code zu testen, der von <acronym>HTTP</acronym>-Verbindungen
  434. abhängig ist. Zum Beispiel verlangt das Testen einer Applikation, die einen
  435. <acronym>RSS</acronym>-Feed von einem fremden Server anfordert, eine Netzwerkverbindung,
  436. die nicht immer verfügbar ist.
  437. </para>
  438. <para>
  439. Aus diesem Grund wird der <classname>Zend_Http_Client_Adapter_Test</classname>-Adapter
  440. bereit gestellt. Man kann seine eigenen Applikationen schreiben, um
  441. <classname>Zend_Http_Client</classname> zu verwenden, und nur zu Testzwecken, z.B. in
  442. der UnitTest-Suite, den Standardadapter durch den Testadapter (ein Mock-Objekt)
  443. austauschen, um Tests ohne direkte Serverbindungen auszuführen.
  444. </para>
  445. <para>
  446. Der <classname>Zend_Http_Client_Adapter_Test</classname>-Adapter stellt die zusätzliche
  447. Methode setResponse() bereit. Diese Methode nimmt einen Parameter entgegen, der eine
  448. <acronym>HTTP</acronym>-Antwort entweder als Text oder als
  449. <classname>Zend_Http_Response</classname>-Objekt repräsentiert. Einmal eingerichtet,
  450. wird der Testadapter immer diese Antwort zurückgeben, ohne tatsächlich eine
  451. <acronym>HTTP</acronym>-Anfrage auszuführen.
  452. </para>
  453. <example id="zend.http.client.adapters.test.example-1">
  454. <title>Testen gegen einen einfachen HTTP Response Stumpf</title>
  455. <programlisting language="php"><![CDATA[
  456. // Instanziere einen neuen Adapter und Client
  457. $adapter = new Zend_Http_Client_Adapter_Test();
  458. $client = new Zend_Http_Client('http://www.example.com', array(
  459. 'adapter' => $adapter
  460. ));
  461. // Setze die erwartete Antwort
  462. $adapter->setResponse(
  463. "HTTP/1.1 200 OK" . "\r\n" .
  464. "Content-type: text/xml" . "\r\n" .
  465. "\r\n" .
  466. '<?xml version="1.0" encoding="UTF-8"?>' .
  467. '<rss version="2.0" ' .
  468. ' xmlns:content="http://purl.org/rss/1.0/modules/content/"' .
  469. ' xmlns:wfw="http://wellformedweb.org/CommentAPI/"' .
  470. ' xmlns:dc="http://purl.org/dc/elements/1.1/">' .
  471. ' <channel>' .
  472. ' <title>Premature Optimization</title>' .
  473. // und so weiter...
  474. '</rss>');
  475. $response = $client->request('GET');
  476. // .. setze die Verarbeitung von $response fort...
  477. ]]></programlisting>
  478. </example>
  479. <para>
  480. Das obige Beispiel zeigt, wie man einen <acronym>HTTP</acronym>-Client voreinstellen
  481. kann, damit er die benötigte Antwort zurückgibt. Danach kann man mit den Testen des
  482. eigenen Codes weiter machen, ohne von einer Netzwerkverbindung, der Serverantwort, etc.
  483. abhängig zu sein. In diesem Fall würde der Test mit der Prüfung fortfahren, wie die
  484. Applikation das <acronym>XML</acronym> aus der Antwort verarbeitet..
  485. </para>
  486. <para>
  487. Manchmal erfordert ein einziger Methoden-Aufruf mehrere <acronym>HTTP</acronym>
  488. Übertragungen. In diesem Fall ist es nicht möglich, setResponse() alleine zu verwenden
  489. weil es keine Möglichkeit gibt, die nächste Antwort zu setzen, die das Programm benötigt,
  490. bevor es zum Aufrufer zurückkommt.
  491. </para>
  492. <example id="zend.http.client.adapters.test.example-2">
  493. <title>Test mit mehreren HTTP-Antworten</title>
  494. <programlisting language="php"><![CDATA[
  495. // Instanzen vom Adapter und Client erzeugen
  496. $adapter = new Zend_Http_Client_Adapter_Test();
  497. $client = new Zend_Http_Client('http://www.example.com', array(
  498. 'adapter' => $adapter
  499. ));
  500. // mit setResponse() die erste Antwort setzen
  501. $adapter->setResponse(
  502. "HTTP/1.1 302 Found" . "\r\n" .
  503. "Location: /" . "\r\n" .
  504. "Content-Type: text/html" . "\r\n" .
  505. "\r\n" .
  506. '<html>' .
  507. ' <head><title>Moved</title></head>' .
  508. ' <body><p>This page has moved.</p></body>' .
  509. '</html>');
  510. // mit addResponse() nachfolgende Antworten setzen
  511. $adapter->addResponse(
  512. "HTTP/1.1 200 OK" . "\r\n" .
  513. "Content-Type: text/html" . "\r\n" .
  514. "\r\n" .
  515. '<html>' .
  516. ' <head><title>Meine Haustierseite</title></head>' .
  517. ' <body><p>...</p></body>' .
  518. '</html>');
  519. // Das $client Objekt kann jetzt zu Testzwecken herangezogen werden,
  520. // indem es wie ein normales Client-Objekt benutzt wird.
  521. ]]></programlisting>
  522. </example>
  523. <para>
  524. Die Methode setResponse() löscht alle Antworten im Buffer von
  525. <classname>Zend_Http_Client_Adapter_Test</classname> und setzt die erste Antwort,
  526. die zurückgegeben wird. Die Methode addResponse() fügt dann weitere Antworten
  527. sukzessiv hinzu.
  528. </para>
  529. <para>
  530. Die HTTP-Antworten werden in der Reihenfolge zurückgegeben,
  531. in der sie angelegt worden sind. Gibt es mehr Anfragen als
  532. Antworten, so wird wieder bei der ersten Antwort angefangen.
  533. </para>
  534. <para>
  535. Das oben angeführte Beispiel kann dazu benutzt werden, um die Reaktion
  536. der eigenen Anwendung auf einen 302 Redirect (Weiterleitung) zu testen.
  537. Abhängig von Ihrer Anwendung, kann es gewollt oder nicht gewollt sein,
  538. dass dem Redirect gefolgt wird. In unserem Beispiel erwarten wir, dass der
  539. Umleitung gefolgt wird und wir konfigurieren den Test-Adapter um uns zu helfen das
  540. zu Testen. Die ursprüngliche 302 Antwort wird mit der Methode setResponse() gesetzt
  541. und die 200 Antwort, welche als nächstes zurückzugeben ist, wird mit der
  542. Methode addResponse() hinzugefügt. Nachdem der Test-Adapter konfiguriert ist, wird
  543. der <acronym>HTTP</acronym>-Client, der den Adapter enthält unter test in das eigene
  544. Objekt injiziert und sein Verhalten getestet.
  545. </para>
  546. <para>
  547. Wenn man will, dass der Adapter auf Wunsch fehlschlägt, kann man
  548. <methodname>setNextRequestWillFail($flag)</methodname> verwenden. Diese Methode lässt
  549. den nächsten Aufruf von <methodname>connect()</methodname> eine
  550. <classname>Zend_Http_Client_Adapter_Exception</classname>-Exception werfen. Das kann
  551. dann nützlich sein, wenn die eigene Anwendung Inhalte von einer externen Seite cacht
  552. (im Falle, dass die Seite ausfällt) und man dieses Feature testen will.
  553. </para>
  554. <example id="zend.http.client.adapters.test.example-3">
  555. <title>Erzwingen das der Adapter fehlschlägt</title>
  556. <programlisting language="php"><![CDATA[
  557. // Einen neuen Adapter und Client instanziieren
  558. $adapter = new Zend_Http_Client_Adapter_Test();
  559. $client = new Zend_Http_Client('http://www.example.com', array(
  560. 'adapter' => $adapter
  561. ));
  562. // Erzwingen, dass die nächste Anfrage mit einer Exception fehlschlägt
  563. $adapter->setNextRequestWillFail(true);
  564. try {
  565. // Dieser Aufruf führt zu einer Zend_Http_Client_Adapter_Exception
  566. $client->request();
  567. } catch (Zend_Http_Client_Adapter_Exception $e) {
  568. // ...
  569. }
  570. // Weitere Aufrufe arbeiten wie erwartet bis man setNextRequestWillFail(true)
  571. // erneut aufruft
  572. ]]></programlisting>
  573. </example>
  574. </sect2>
  575. <sect2 id="zend.http.client.adapters.extending">
  576. <title>Einen eigenen Adapter erstellen</title>
  577. <para>
  578. Es ist möglich eigene Verbindungs-Adapter zu schreiben, die spezielle
  579. Bedürfnisse, wie persistente Sockets oder gecachte Verbindungen abdecken.
  580. Diese können dann wie gewohnt in der eigenen Anwendung benutzt werden.
  581. </para>
  582. <para>
  583. Um einen neuen Adapter zu erstellen, muss eine neue Klasse angelegt werden,
  584. die das <classname>Zend_Http_Client_Adapter_Interface</classname> implementiert.
  585. Nachfolgend finden Sie ein Gerüst für einen neuen Adapter. Die public-Methoden müssen
  586. unbedingt implementiert werden.
  587. </para>
  588. <example id="zend.http.client.adapters.extending.example-1">
  589. <title>Gerüst für einen eigenen Verbindungs-Adapter</title>
  590. <programlisting language="php"><![CDATA[
  591. class MyApp_Http_Client_Adapter_BananaProtocol
  592. implements Zend_Http_Client_Adapter_Interface
  593. {
  594. /**
  595. * Konfigurationsarray für den Adapter
  596. *
  597. * @param array $config
  598. */
  599. public function setConfig($config = array())
  600. {
  601. // in den meisten Fällen kann die Implementierung von
  602. // Zend_Http_Client_Adapter_Socket eins zu eins übernommen werden
  603. }
  604. /**
  605. * Zum Server verbinden
  606. *
  607. * @param string $host
  608. * @param int $port
  609. * @param boolean $secure
  610. */
  611. public function connect($host, $port = 80, $secure = false)
  612. {
  613. // Verbindung zum Server herstellen
  614. }
  615. /**
  616. * Anfrage / Request an den Server stellen
  617. *
  618. * @param string $method
  619. * @param Zend_Uri_Http $url
  620. * @param string $http_ver
  621. * @param array $headers
  622. * @param string $body
  623. * @return string Request as text
  624. */
  625. public function write($method,
  626. $url,
  627. $http_ver = '1.1',
  628. $headers = array(),
  629. $body = '')
  630. {
  631. // Anfrage stellen
  632. // Diese Methode muss die komplette Antwort zurückliefern,
  633. // inklusive aller Header
  634. }
  635. /**
  636. * Antwort des Servers auslesen
  637. *
  638. * @return string
  639. */
  640. public function read()
  641. {
  642. // Antwort des Servers lesen und als String zurückgeben
  643. }
  644. /**
  645. * Verbindung zum Server beenden
  646. *
  647. */
  648. public function close()
  649. {
  650. // Verbindung beenden - wird zum Schluss aufgerufen
  651. }
  652. }
  653. // Jetzt kann der Adapter benutzt werden:
  654. $client = new Zend_Http_Client(array(
  655. 'adapter' => 'MyApp_Http_Client_Adapter_BananaProtocol'
  656. ));
  657. ]]></programlisting>
  658. </example>
  659. </sect2>
  660. </sect1>