File: Zend_Http_Client-Adapters.xml

package info (click to toggle)
zendframework 1.12.9%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie-kfreebsd
  • size: 133,584 kB
  • sloc: xml: 1,311,829; php: 570,173; sh: 170; makefile: 125; sql: 121
file content (776 lines) | stat: -rw-r--r-- 33,280 bytes parent folder | download | duplicates (2)
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>