Guzzle

By | 30 novembre 2013

Guzzle est un client HTTP développé en PHP. Je pense qu’aujourd’hui n’importe quel développeur s’est déjà retrouvé face à un web services. Les web services, ont beaucoup évolué, passant par des trams XML, SOAP et maintenant RESTful ! Guzzle permet donc d’attaquer facilement ce genre de web services, en utilisant le module cURL.

Installation

On ne change pas les bonnes habitudes concernant l’installation, Composer reste notre meilleur ami 🙂

{
   "require": {
      "guzzle/guzzle": "3.7.*"
   }
}

Composer n’est pas la seule façon de l’installer, vous pouvez passer par PEAR (petite pensé pour les sysAdmins):

$ pear channel-discover guzzlephp.org/pear
$ pear install guzzle/guzzle

Dans l’exemple ci-dessus, nous installons l’ensemble des paquets Guzzle, mais il est possible de n’installer que les paquets dont vous avez besoin. Par exemple si vous souhaitez installer uniquement le paquet http, il suffira de remplacer guzzle/guzzle par guzzle/http. Tout simplement 🙂

Premier test

Notre première requête:

define('ROOT_DIR', realpath(__DIR__).'/');
require ROOT_DIR.'vendor/autoload.php';

use Guzzle\Http\Client;

$client = new Client('http://google.com');

$request = $client->get('/');

$response = $request->send();
echo $response->getHeader('Date');

Reprenons l’exemple ci-dessus, nous pouvons distinguer 3 briques utilisées (le client, la requête et la réponse).

Client

Nous commençons par créer le client. L’URL passée en paramètre à l’instanciation sera utilisée par défaut par l’ensemble de nos requêtes. Cette URL est facultative, nous aurions pu la passer à la méthode $client->get(‘http://google.com/’);.

Le client va nous permettre de définir la configuration par défaut de nos requêtes (user_agent, basic_auth, timeout, proxy …). Les options de configuration peuvent aussi être défini et/ou redéfini lors de la préparation de la requête, nous reviendrons dessus.

La requête est créée par le client, toutes les médhodes HTTP peuvent être utilisées (get, post, put, delete, head …).

Requête

La requête est le résultat obtenu par le client. C’est depuis cette brique que la requête sera exécutée. Elle permet aussi de redéfinir les options par défaut du client avant l’exécution.

Réponse

La dernière brique, la réponse va nous permettre d’extraite l’ensemble des informations de la requête. L’entête, le corps, le code retour …

Configuration par défaut du client

Comme nous l’avons vu dans l’exemple précédent, il est possible de définir un ensemble d’options par défaut à l’instanciation du client.

URL

La première option, est l’URL. Si elle est définit lors de l’instanciation, elle sera utilisée pour toutes les requêtes faisant appel à un chemin relatif (/mon/chemin). Mais rien ne vous empêche d’appeler une autre URL depuis ce même client.

Exemple:

define('ROOT_DIR', realpath(__DIR__).'/');
require ROOT_DIR.'vendor/autoload.php';

use Guzzle\Http\Client;

$client = new Client('http://google.com');

$requests[] = $client->get('/');
$requests[] = $client->get('http://google.fr/');
$requests[] = $client->get('search/php');
$requests[] = $client->get('search/php/../test');
foreach($requests as $request) {
    echo $request->getUrl()."\n";   
}

# http://google.com/
# http://google.fr/
# http://google.com/search/php
# http://google.com/search/test

 Options Client

Il est possible de définir un comportement par défaut du client. Ce comportement sera déterminé par les options passées en arguments à l’instanciation. Il existe plusieurs type d’options configurable, les options de requêtes, les options cURL et les variables d’URL.

Options de requête

Dans l’exemple ci-dessous, 3 options ont été définies.

La première headers, est certainement la plus importante, car il s’agit l’entête HTTP qui sera envoyée au serveur. headers attend un tableau en valeur.

La seconde, query, va ajouter à toutes les requêtes une variable ts contenant un timestamp. Ce type d’option peut être très utile, par exemple pour activer dans un environ de développement le profiling de requête via la variable XDEBUG_PROFILE.

La troisième option parle d’elle même, il s’agit du timeout de réponse qui sera appliqué à toutes les requêtes.

$opts = array(
    'request.options' => array(
        'headers' => array('Foo' => 'Bar'),
        'query'   => array('ts' => time()),
        'timeout' => 1
    )
); 
$client = new Client('http://google.com', $opts);

$requests[] = $client->get('/');
foreach($requests as $request) {
    echo $request->getUrl()."\n";   
}

# http://google.com/?ts=138581351

Une autre option très intéressante est la gestion d’événements. Il est possible de mettre en place des écouteurs sur les différentes actions d’une requête (before_send, sent, clone).

$opts = array(
    'request.options' => array(
        'events' => array(
            'request.before_send' => function (\Guzzle\Common\Event $e) {
                echo "before\n";
            },
            'request.sent' => function (\Guzzle\Common\Event $e) {
                echo "sent\n";
            },
        )
    )
); 
$client = new Client('http://google.com', $opts);

La semaine dernière je vous ai présenté Monolog, nous pourrions ici l’utiliser afin de journaliser les URL « crawlées ».

Variable d’URL

Les variables d’URL permettent de définir des valeurs par défaut de chemin.

$opts = array(
    'date' => date('Y-m-d'),
    'request.options' => array(
        'query'   => array('ts' => time()),
        'timeout' => 1
    )
); 
$client = new Client('http://google.com', $opts);

$requests[] = $client->get('/{date}');
foreach($requests as $request) {
    echo $request->getUrl()."\n";   
}

# http://google.com/2013-11-30?ts=1385820766

Options cURL

Il est aussi possible de définir les options cURL à utiliser par défaut via curl.options.

$opts = array(
    'date' => date('Y-m-d'),
    'request.options' => array(
        'query'   => array('ts' => time()),
        'timeout' => 1
    ),
    'curl.options' => array(
        'CURLOPT_PROXY' => 'http://127.0.0.1'
    )
); 
$client = new Client('http://google.com', $opts);

Redéfinir les options par défaut

Jusqu’à présent nous avons vu les options par défaut que nous pouvons définir au niveau du client. Ces options peuvent être redéfinies lors de la création de la requête. A l’appel d’une méthode (get, post, put …), nous pouvons passer en second paramètre des informations d’entête HTTP et en troisième paramètre les options de request.options.

Dans l’exemple suivant, nous allons redéfinir les variables à passer à la requête (query).

$opts = array(
'request.options' => array(
'query'   => array('ts' => time()),
)
);
$client = new Client('http://google.com', $opts);

$requests[] = $client->get(
    '/',
    array(),
    array(
        'query' => array('ts' => date('YmdHis', time()))
    )
);
foreach($requests as $request) {
    echo $request->getUrl()."\n";
}
$response = $requests[0]->send();

# http://google.com/?ts=20131130160416

Paralléliser les requêtes

Guzzle permet de paralléliser les requêtes HTTP, via l’utilisation de curl_multi.

$responses = $client->send(array(
    $client->get('http://www.google.com/'),
    $client->get('http://www.google.fr/'),
    $client->get('http://www.google.es/'),
));

Son utilisation est extrêmement simple, il suffit de passer en arguments de la méthode Client::send() un tableau contenant un ensemble de requêtes à exécuter.

Le temps total de ces 3 requêtes devrait être le temps de la requête la plus lente.

google.com ---->    |
google.fr  -------->|
google.es  ------>  |
           .........! La réponse est renvoyée quand google.fr a répondu.

Traitement de la réponse

Lors de l’exécution d’une requête, le client Guzzle retourne une instance de Guzzle\Http\Message\Response. Cet objet va nous permettre d’obtenir facilement toutes les informations de la requête.

Récupérer les informations de statut de la réponse.

$response = $client->get('/')->send();

echo $response->getStatusCode()."\n";
echo $response->getReasonPhrase()."\n";
echo $response->getProtocol()."\n";
echo $response->getProtocolVersion()."\n";

$response->isSuccessful();
$response->isInformational();
$response->isRedirect();
$response->isClientError();
$response->isServerError();

Pour récupérer les informations provenant de l’entête HTTP, il nous suffit de faire appel à la méthode Response::getHeader(), en passant en paramètre la directive qui nous intéresse.

$response = $client->get('/')->send();
echo $response->getHeader('Content-Type')."\n";
echo $response->getHeader('Content-Length')."\n";

Pour récupérer le corps de la requête, nous pouvons soit faire appel à la méthode Response::getBody() ou caster Response.

$response = $client->get('/')->send();
echo $response->getBody()."\n";
echo $response."\n";

Si vous attendez en réponse du Json ou du XML, vous pouvez appeler respectivement les méthodes Response::json et Response::xml (Retourne un objet SimpleXMLElement).

Plugins

Il existe un système de plugins dont le rôle est d’exécuter certaines actions suivant les événements de la requête. Leur mise en place est très simple, en voici un exemple avec le PluginHistory.

use Guzzle\Http\Client;
use Guzzle\Plugin\History\HistoryPlugin;

$client = new Client();

$client->addSubscriber(new HistoryPlugin());
$client->get('http://www.google.com/')->send();

foreach ($history as $request) {
    echo $request."\n";
}

#GET /?ts=1385835012 HTTP/1.1
#Host: www.google.com
#User-Agent: Guzzle/3.7.4 curl/7.29.0 PHP/5.4.9-4ubuntu2.3

#GET /?gws_rd=cr&ei=BSqaUur9DcOo0QX0qoDAAQ HTTP/1.1
#Host: www.google.fr
#User-Agent: Guzzle/3.7.4 curl/7.29.0 PHP/5.4.9-4ubuntu2.3

Guzzle\Plugin\Async\AsyncPlugin

Permet de faire du traitement de réponse de manière asynchrone.

Guzzle\Plugin\Backoff\BackoffPlugin

Permet de réexécuter automatiquement une requête ayant échouée.

Guzzle\Plugin\Cache\CachePlugin

Permet de mettre en place un système de cache en s’appuyant sur plusieurs valeurs, comme expires, Etag, last-modified …

Guzzle\Plugin\Cookie\CookiePlugin

Ce plugin, permet de conserver les cookie d’une requête à une autre sur un même client Guzzle.

Guzzle\Plugin\History\HistoryPlugin

Permet d’obtenir l’historique de la requête.

Guzzle\Plugin\Log\LogPlugin

Permet de journaliser les requêtes envoyées, les redirections effectuées …

Guzzle\Plugin\Md5\Md5ValidatorPlugin

Permet de vérifier que la réponse HTTP est complète via l’entête Content-MD5.

Guzzle\Plugin\Mock\MockPlugin

Un Mock pour tester le client.

Guzzle\Plugin\Oauth\OauthPlugin

Permet d’utiliser le système d’authentification OAuth.

Conclusion

Guzzle est un client HTTP très complet. et simple à mettre en place que je vais très certainement intégrer à mes projets personnels.

Lien: https://github.com/guzzle/guzzle , http://docs.guzzlephp.org/en/latest/index.html

Category: Php