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