Chapitre 13. Zend_Http
Précédent |  | Suivant

## Chapitre 13. Zend_Http

## 13.1. Zend_Http_Client

### 13.1.1. Introduction

Zend_Http_Client provides an easy interface for preforming Hyper-Text Transfer Protocol (HTTP) requests. Zend_Http_Client supports most simple features expected from an HTTP client, as well as some more complex features such as HTTP authentication and file uploads. Successful requests (and most unsuccessful ones too) return a Zend_Http_Response object, which provides access to the response's headers and body (see Section 13.5, « Zend_Http_Response »).

The class constructor optionally accepts a URL as it's first parameter (can be either a string or a Zend_Uri_Http object), and an optional array of configuration parameters. Both can be left out, and set later using the setUri() and setConfig() methods.

Exemple 13.1. Instantiating a Zend_Http_Client object

    <?php
        require_once 'Zend/Http/Client.php';

        $client = new Zend_Http_Client('http://example.org', array(
            'maxredirects' => 0,
            'timeout'      => 30));

        // This is actually exactly the same:
        $client = new Zend_Http_Client();
        $client->setUri('http://example.org');
        $client->setConfig(array(
            'maxredirects' => 0,
            'timeout'      => 30));

    ?>

### 13.1.2. Configuration Parameters

The constructor and setConfig() method accept an associative array of configuration parameters. Setting these parameters is optional, as they all have default values.

Tableau 13.1. Zend_Http_Client configuration parameters

Parameter | Description | Expected Values | Default Value
--- | --- | --- | ---
maxredirects | Maximum number of redirections to follow (0 = none) | integer | 5
strictredirects | Whether to strictly follow the RFC when redirecting (see Section 13.1.5, « HTTP Redirections ») | boolean | false
useragent | User agent identifier string (sent in request headers) | string | 'Zend_Http_Client'
timeout | Connection timeout (seconds) | integer | 10
httpversion | HTTP protocol version | float (1.1 or 1.0) | 1.1
adapter | Connection adapter class to use (see Section 13.1.12, « Connection Adapters ») | mixed | 'Zend_Http_Client_Adapter_Socket'
keepalive | Whether to enable keep-alive connections with the server. Useful and might improve performance if several consecutive requests to the same server are performned. | boolean | false

### 13.1.3. Performing Basic HTTP Requests

Performing simple HTTP requests is very easily done using the request() method, and rarely needs more than three lines of code:

Exemple 13.2. Preforming a Simple GET Request

    <?php
        require_once 'Zend/Http/Client.php';

        $client = new Zend_Http_Client('http://example.org');
        $response = $client->request();
    ?>

The request() method takes one optional parameter - the request method. This can be either GET, POST, PUT, HEAD, DELETE, TRACE, OPTIONS or CONNECT as defined by the HTTP protocol [1]. For convenience, these are all defined as class constants: Zend_Http_Request::GET, Zend_Http_Request::POST and so on.

If no method is specified, the method set by the last setMethod() call is used. If setMethod() was never called, the default request method is GET (see the above example).

Exemple 13.3. Using Request Methods Other Than GET

    <?php
        // Preforming a POST request
        $response = $client->request('POST');

        // Yet another way of preforming a POST request
        $client->setMethod(Zend_Http_Client::POST);
        $response = $client->request();
    ?>

### 13.1.4. Adding GET and POST parameters

Adding GET parameters to an HTTP request is quite simple, and can be done either by specifying them as part of the URL, or by using the setParameterGet() method. This method takes the GET parameter's name as it's first parameter, and the GET parameter's value as it's second parameter. For convenience, the setParameterGet() method can also accept a single associative array of name => value GET variables - which may be more comfortable when several GET parameters need to be set.

Exemple 13.4. Setting GET Parameters

    <?php
        // Setting a get parameter using the setParameterGet method
        $client->setParameterGet('knight', 'lancelot');

        // This is equivalent to setting such URL:
        $client->setUri('http://example.com/index.php?knight=lancelot');

        // Adding several parameters with one call
        $client->setParameterGet(array(
            'first_name'  => 'Bender',
            'middle_name' => 'Bending'
            'made_in'     => 'Mexico',
        ));
    ?>

While GET parameters can be sent with every request method, POST parameters are only sent in the body of POST requests. Adding POST parameters to a request is very similar to adding GET parameters, and can be done with the setParameterPost() method, which is similar to the setParameterGet() method in structure.

Exemple 13.5. Setting POST Parameters

    <?php
        // Setting a POST parameter
        $client->setParameterPost('language', 'fr');

        // Setting several POST parameters, one of them with several values
        $client->setParameterPost(array(
            'language'  => 'es',
            'country'   => 'ar',
            'selection' => array(45, 32, 80)
        ));
    ?>

Note that when sending POST requests, you can set both GET and POST parameters. On the other hand, while setting POST parameters for a non-POST request will not trigger and error, it is useless. Unless the request is a POST request, POST parameters are simply ignored.

### 13.1.5. HTTP Redirections

By default, Zend_Http_Client automatically handles HTTP redirections, and will follow up to 5 redirections. This can be changed by setting the 'maxredirects' configuration parameter.

According to the HTTP/1.1 RFC, HTTP 301 and 302 responses should be treated by the client by resending the same request to the specified location - using the same request method. However, most clients to not implement this and always use a GET request when redirecting. By default, Zend_Http_Client does the same - when redirecting on a 301 or 302 response, all GET and POST parameters are reset, and a GET request is sent to the new location. This behavior can be changed by setting the 'strictredirects' configuration parameter to boolean TRUE:

Exemple 13.6. Forcing RFC 2616 Strict Redirections on 301 and 302 Responses

    <?php
        // Strict Redirections
        $client->setConfig(array('strictredirects' => true)

        // Non-strict Redirections
        $client->setConfig(array('strictredirects' => false)
    ?>

You can always get the number of redirections done after sending a request using the getRedirectionsCount() method.

### 13.1.6. Adding Cookies and Using Cookie Persistence

Zend_Http_Client provides an easy interface for adding cookies to your request, so that no direct header modification is required. This is done using the setCookie() method. This method can be used in several ways:

Exemple 13.7. Setting Cookies Using setCookie()

    <?php
        // Easy and simple: by providing a cookie name and cookie value
        $client->setCookie('flavor', 'chocolate chips');

        // By directly providing a raw cookie string (name=value)
        // Note that the value must be already URL encoded
        $client->setCookie('flavor=chocolate%20chips');

        // By providing a Zend_Http_Cookie object
        $cookie = Zend_Http_Cookie::factory('flavor=chocolate%20chips');
        $client->setCookie($cookie);
    ?>

For more information about Zend_Http_Cookie objects, see Section 13.4, « Zend_Http_Cookie and Zend_Http_CookieJar ».

Zend_Http_Client also provides the means for cookie stickiness - that is having the client internally store all sent and received cookies, and resend them automatically on subsequent requests. This is useful, for example when you need to log in to a remote site first and receive and authentication or session ID cookie before sending further requests.

Exemple 13.8. Enabling Cookie Stickiness

    <?php
        // To turn cookie stickiness on, set a Cookie Jar
        $client->setCookieJar();

        // First request: log in and start a session
        $client->setUri('http://example.com/login.php');
        $client->addParameterPost('user', 'h4x0r');
        $client->addParameterPost('password', '1337');
        $client->request('POST');

        // The Cookie Jar automatically stores the cookies set
        // in the response, like a session ID cookie.

        // Now we can send our next request - the stored cookies
        // will be automatically sent.
        $client->setUri('http://example.com/read_member_news.php');
        $client->request('GET');
    ?>

For more information about the Zend_Http_CookieJar class, see Section 13.4.5, « The Zend_Http_CookieJar Class: Instantiation ».

### 13.1.7. Setting Custom Request Headers

Setting custom headers can be done by using the setHeaders() method. This method is quite diverse and can be used in several ways, as the following example shows:

Exemple 13.9. Setting A Single Custom Request Header

    <?php
        // Setting a single header, overwriting any previous value
        $client->setHeaders('Host', 'www.example.com');

        // Another way of doing the exact same thing
        $client->setHeaders('Host: www.example.com');

        // Setting several values for the same header (useful mostly for Cookie headers):
        $client->setHeaders('Cookie', array(
            'PHPSESSID=1234567890abcdef1234567890abcdef',
            'language=he'
        ));
    ?>

setHeader() can also be easily used to set multiple headers in one call, by providing an array of headers as a single parameter:

Exemple 13.10. Setting Multiple Custom Request Headers

    <?php
        // Setting multiple headers, overwriting any previous value
        $client->setHeaders(array(
            'Host' => 'www.example.com',
            'Accept-encoding', 'gzip,deflate',
            'X-Powered-By' => 'Zend Framework'));

        // The array can also contain full array strings:
        $client->setHeaders(array(
            'Host: www.example.com',
            'Accept-encoding: gzip,deflate',
            'X-Powered-By: Zend Framework'));
    ?>

### 13.1.8. File Uploads

You can upload files through HTTP using the setFileUpload method. This method takes a file name as the first parameter, a form name as the second parameter, and data as a third optional parameter. If the third data parameter is null, the first file name parameter is considered to be a real file on disk, and Zend_Http_Client will try to read this file and upload it. If the data parameter is not null, the first file name parameter will be sent as the file name, but no actual file needs to exist on the disk. The second form name parameter is always required, and is equivalent to the "name" attribute of an >input< tag, if the file was to be uploaded through an HTML form. A fourth optional parameter provides the file's content-type. If not specified, and Zend_Http_Client reads the file from the disk, the mime_content_type function will be used to guess the file's content type, if it is available. In any case, the default MIME type will be application/octet-stream.

Exemple 13.11. Using setFileUpload to Upload Files

    <?php
        // Uploading arbitrary data as a file
        $text = 'this is some plain text';
        $client->setFileUpload('some_text.txt', 'upload', $text, 'text/plain');

        // Uploading an existing file
        $client->setFileUpload('/tmp/Backup.tar.gz', 'bufile');

        // Send the files
        $client->submit('POST');
    ?>

In the first example, the $text variable is uploaded and will be available as $_FILES['upload'] on the server side. In the second example, the existing file /tmp/Backup.tar.gz is uploaded to the server and will be available as $_FILES['bufile']. The content type will be guesses automatically if possible - and if not, the content type will be set to 'application/octet-stream'.

| Uploading files
When uploading files, the HTTP request content-type is automatically set to multipart/form-data. Keep in mind that you must send a POST or PUT request in order to upload files. Most servers will ignore the requests body on other request methods.

### 13.1.9. Sending Raw POST Data

You can use a Zend_Http_Client to send raw POST data using the setRawData() method. This method takes two parameters: the first is the data to send in the request body. The second optional parameter is the content-type of the data. While this parameter is optional, you should usually set it before sending the request - either using setRawData(), or with another method: setEncType().

Exemple 13.12. Sending Raw POST Data

    <?php
        $xml = '<book>' .
               '  <title>Islands in the Stream</title>' .
               '  <author>Ernest Hemingway</author>' .
               '  <year>1970</year>' .
               '</book>';

        $client->setRawData($xml, 'text/xml')->request('POST');

        // Another way to do the same thing:
        $client->setRawData($xml)->setEncType('text/xml')->request('POST');
    ?>

The data should be available on the server side through PHP's $HTTP_RAW_POST_DATA variable or through the php://input stream.

| Using raw POST data
Setting raw POST data for a request will override any POST parameters or file uploads. You should not try to use both on the same request. Keep in mind that most servers will ignore the request body unless you send a POST request.

### 13.1.10. HTTP Authentication

Currently, Zend_Http_Client only supports basic HTTP authentication. This feature is utilized using the setAuth() method. The method takes 3 parameters: The user name, the password and an optional authentication type parameter. As mentioned, currently only basic authentication is supported (digest authentication support is planned).

Exemple 13.13. Setting HTTP Authentication User and Password

    <?php
        // Using basic authentication
        $client->setAuth('shahar', 'myPassword!', Zend_Http_Client::AUTH_BASIC);

        // Since basic auth is default, you can just do this:
        $client->setAuth('shahar', 'myPassword!');
    ?>

### 13.1.11. Sending Multiple Requests With the Same Client

Zend_Http_Client was also designed specifically to handle several consecutive requests with the same object. This is useful in cases where a script requires data to be fetched from several places, or when accessing a specific HTTP resource requires logging in and obtaining a session cookie, for example.

When performing several requests to the same host, it is highly recommended to enable the 'keepalive' configuration flag. This way, if the server supports keep-alive connections, the connection to the server will only be closed once all requests are done and the Client object is destroyed. This prevents the overhead of opening and closing TCP connections to the server.

When you perform several requests with the same client, but want to make sure all the request-specific parameters are cleared, you should use the resetParameters() method. This ensures that GET and POST parameters, request body and request-specific headers are reset and are not reused in the next request.

| Reseting parameters
Note that non-request specific headers are not reset when the resetParameters method is used. As a matter of fact, only the 'Content-length' and 'Content-type' headers are reset. This allows you to set-and-forget headers like 'Accept-language' and 'Accept-encoding'

Another feature designed specifically for consecutive requests is the Cookie Jar object. Cookie Jars allow you to automatically save cookies set by the server in the first request, and send them on consecutive requests transparently. This allows, for example, going through an authentication request before sending the actual data fetching request.

If your application requires one authentication request per user, and consecutive requests might be performed in more than one script in your application, it might be a good idea to store the Cookie Jar object in the user's session. This way, you will only need to authenticate the user once every session.

Exemple 13.14. Performing consecutive requests with one client

    <?php
        // First, instantiate the client
        $client = new Zend_Http_Client('http://www.example.com/fetchdata.php', array(
            'keepalive' => true
        ));

        // Do we have the cookies stored in our session?
        if (isset($_SESSION['cookiejar']) &&
            $_SESSION['cookiejar'] instanceof Zend_Http_CookieJar)) {

            $client->setCookieJar($_SESSION['cookiejar']);
        } else {
            // If we don't, authenticate and store cookies
            $client->setCookieJar();
            $client->setUri('http://www.example.com/login.php');
            $client->setParameterPost(array(
                'user' => 'shahar',
                'pass' => 'somesecret'
            ));
            $client->request(Zend_Http_Client::POST);

            // Now, clear parameters and set the URI to the original one
            // (note that the cookies that were set by the server are now
            // stored in the jar)
            $client->resetParameters();
            $client->setUri('http://www.example.com/fetchdata.php');
        }

        $response = $client->request(Zend_Http_Client::GET);

        // Store cookies in session, for next page
        $_SESSION['cookiejar'] = $client->getCookieJar();
    ?>

### 13.1.12. Connection Adapters

Zend_Http_Client is based on a connection adapter design. The connection adapter is the object in charge of performing the actual connection to the server, as well as writing requests and writing responses. This connection adapter can be replaced, and you can create and extend the default connection adapter to suite your special needs, without the need to extend or replace the entire HTTP client class, and with the same interface.

Currently, the Zend_Http_Client class provides two built-in connection adapters:

- `Zend_Http_Client_Adapter_Socket`: The default adapter, which is a plain socket based adapter, and does not require any special PHP extension to use.

- `Zend_Http_Client_Adapter_Test`: This is a dummy adapter, that should be used for testing purposes only. It does not perform any real connections, and returns a predefined response.

The Zend_Http_Client object's adapter connection adapter is set using the 'adapter' configuartion option. When instantiating the client object, you can set the 'adapter' configuration option to a string containing the adapter's name (eg. 'Zend_Http_Client_Adapter_Socket') or to a variable holding an adapter object (eg `new Zend_Http_Client_Adapter_test`). You can also set the adapter later, using the Zend_Http_Client->setConfig() method.

You can create your own connection adapters and use them. In order to do so, you must create your own class that implements the Zend_Http_Client_Adapter_Interface interface. You could, for example, create a connection adapter that uses persistent sockets, or a connection adapter with caching abilities, and use them as needed in your application.

### 13.1.13. Writing Tests With Zend_Http_Client Objects

Sometimes, it is very hard to test code that relys on HTTP connections. For example, testing an application that pulls an RSS feed from a remote server will require a network connection, which is not always available.

For this reason, the Zend_Http_Client_Adapter_Test adapter is provided. You can write your application to use Zend_Http_Client, and just for testing purposes, for example in your unit testing suite, you can replace the default adapter with a Test adapter, allowing you to run tests without actually performing server connections.

The Zend_Http_Client_Adapter_Test adapter provides an additional method, setResponse() method. This method takes one parameter, which represents an HTTP response as either text or a Zend_Http_Response object. Once set, your Test adapter will always return this response, without even performing an actual HTTP request.

Exemple 13.15. Testing Your Code Without Accessing The Network

    <?php
        // Instantiate a new adapter and client
        $adapter = new Zend_Http_Client_Adapter_Test();
        $client = Zend_Http_Client('http://www.example.com', array(
            'adapter' => $adapter
        ));

        // Set the expected response
        $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>' .
            // and so on...
            '</rss>');

        $response = $client->request('GET');
        // .. continue parsing $response..
    ?>

The above example shows how you can preset your HTTP client to return the response you need. Then, you can continue testing your own code, without being dependent on a network connection, the server's response, etc. In this case, the test would continue to check how the application parses the XML in the response body.

[1] See RFC 2616 - http://www.w3.org/Protocols/rfc2616/rfc2616.html.

Précédent |  | Suivant
12.9. Catching Gdata Exceptions | Sommaire | 13.2. Zend_Http_Client - Utilisation avancée