今時のPHP HTTPクライアントのGuzzleを使ってみた

More than 1 year has passed since last update.


はじめに

LaravelでHTTPリクエストを投げたかったのでGuzzleを使ってみました。

以前ですとPEARのHTTP_Request2を使っていましたが、あまり最近使われていないようなので新しいパッケージを使ってみました。

HTTP_Request2は長年使ってまして、使いやすくて好きです。cURLも悪くはないのですが…。

Laravelで使いましたが、もちろん生のPHPでも使えます。


インストール

今回はLaravelで使ってみました。生のPHPでもOKです。

$ laravel new hogeproject

$ cd hogeproject
$ composer require guzzlehttp/guzzle
Using version ^6.2 for guzzlehttp/guzzle
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)

コントローラの作成

$ php artisan make:controller HogeController


リクエストの作成

$ php artisan make:controller HogeController


routes/web.php

Route::get('/basic_request', 'HogeController@basic_request');

Route::get('/with_headers', 'HogeController@with_headers');


GET

GETリクエスト


app/Http/Controllers/HogeController.php

public function basic_request() {

$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );
$path = '/index.html';
$response = $client->request( 'GET', $path,
[
'allow_redirects' => true,
] );
$response_body = (string) $response->getBody();
echo $response_body;
}


ステータスコード取得


public function get_http_status_code() {
$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );

$path = '/index.html';
$response = $client->request( 'GET', $path,
[
'allow_redirects' => true,
] );
$response_body = (string) $response->getStatusCode();
echo $response_body;
}


JSONで送る

$response = $client->request('PUT', '/put', ['json' => ['foo' => 'bar']]);

requestのオプション引数にjsonで配列を渡すと良い感じにしてくれます。

(おそらく)json_encode(), Conent-Type: application/jsonの指定を行ってくれます。


http://docs.guzzlephp.org/en/latest/request-options.html#json



リクエストヘッダー指定

リファラーなどのリクエストヘッダーを指定する場合には配列を渡します。


app/Http/Controllers/HogeController.php

public function with_headers() {

$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );

$path = '/index.html';
$headers = [
'Origin' => 'http://www.example.com',
'Accept-Encoding' => 'gzip, deflate, br',
'Accept-Language' => 'ja,en-US;q=0.8,en;q=0.6',
'Upgrade-Insecure-Requests' => '1',
'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36',
'Content-Type' => 'application/x-www-form-urlencoded',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Cache-Control' => 'max-age=0',
'Referer' => 'http://www.example.com',
'Connection' => 'keep-alive'
];
$response = $client->request( 'GET', $path,
[
'allow_redirects' => true,
'headers' => $headers,
//'form_params' => $form_params,
] );
$response_body = (string) $response->getBody();
echo $response_body;
}



GETでクエリストリングを指定

http://docs.guzzlephp.org/en/latest/quickstart.html#query-string-parameters

queryに配列を指定するとクエリストリングを指定できるようです。

public function get_with_params() {

$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );

$path = '/index.html';
$dev_null = $client->get($path,
[
'query' => ['foo' => 'bar'],
'on_stats' => function (\GuzzleHttp\TransferStats $stats) use (&$url) {
$url = $stats->getEffectiveUri();
}
] )->getBody()->getContents();
echo $url;
}


404を許容する書き方

404の場合には例外を投げられてしまいます。

この例外を回避する方法です。


404だったときのエラーメッセージ

 [GuzzleHttp\Exception\ClientException]

Client error: `GET http://www.l2tp.org/index.html` resulted in a `404 Not Foun
d`
response:
<!DOCTYPE html>
<html lang="ja" class="no-js no-svg">
<head>
<meta charset="
UTF-8">
<meta name="
viewport" content="width (truncated...)


http_errorsをfalseにする

@bootjp さんに教えてもらいました。ありがとうございます!

リクエストを投げる際にhttp_errorsというオプションをfalseにすると例外を投げられないようです。

$client->request('GET', '/status/500');

// Throws a GuzzleHttp\Exception\ServerException

$res = $client->request('GET', '/status/500', ['http_errors' => false]);
echo $res->getStatusCode();
// 500


falseに設定すると400番台、500番台などのHTTPエラーを無効化します。デフォルトでは例外が飛ばされます。



Set to false to disable throwing exceptions on an HTTP protocol errors (i.e., 4xx and 5xx responses). Exceptions are thrown by default when HTTP protocol errors are encountered.


http://docs.guzzlephp.org/en/stable/request-options.html#http-errors


例外を拾う

もう一つの方法はClientExceptionで例外を拾います。

投げられる例外のClientExceptionはResponseと同じような使い方ができます。

try {

$client->request('GET', 'https://github.com/_abc_123_404');
} catch (ClientException $e) {
echo Psr7\str($e->getRequest());
echo Psr7\str($e->getResponse());
}

http://docs.guzzlephp.org/en/latest/quickstart.html

もしくはレスポンスを使う場合、getResponseを受けて渡すと良いようです。

try {

$client->request('GET', 'https://github.com/_abc_123_404');
} catch (ClientException $e) {
$response = $e->getResponse();
}
echo $response->getStatusCode();


リクエストを確認する

デバッグを行うときにそもそも思った通りのリクエストが投げれているか、ということを確認したい場合があります。

そういう場合の確認方法です。


リクエストしたbodyの確認

上記とは変わってbodyの確認を行います。

どういったリクエストが送られているか確認するときに使います。

public function send_request_with_dump() {

$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );

$path = '/index.html';

$stack = HandlerStack::create();
// my middleware
$stack->push(Middleware::mapRequest(function (RequestInterface $request) use (&$contentsRequest) {
$contentsRequest = (string) $request->getBody();
var_dump($contentsRequest);
return $request;
}));

$dev_null = $client->request( 'GET', $path,
[
'handler' => $stack,
] )->getBody()->getContents();
echo $url;
}


How do I get the body of SENT data with Guzzle PHP?

http://stackoverflow.com/a/34911017/2405335


ミドルウェアの機構を使ってリクエスト時に関数を実行します。戻り値でのとり方はわからなかったので参考先通りにvar_dump()しています。


リクエストヘッダの確認

リクエストしたヘッダの確認です。レスポンスヘッダじゃなくてリクエストしたヘッダです。

$YourGuzzleclient=new Client();

$YourGuzzleclient->request('POST', '{Your url}',
['debug'=>true,'otheroptions'=>array()]
);


http://stackoverflow.com/a/39239978/2405335



リクエストしたURLの確認

ちょっと書き方が新しいですね。on_statsTransferStatusを受けるクロージャを渡すと、その中でurlを取得できるようです。

useと参照渡しで外側でも参照できます。JavaScriptっぽいですね。

PHPの内部で変数などを実行した際にちゃんと送れているか、というデバッグに使いました。

public function get_requested_url() {

$base_url = 'http://example.com';
$client = new \GuzzleHttp\Client( [
'base_uri' => $base_url,
] );

$path = '/index.html';
$dev_null = $client->request( 'GET', $path,
[
'on_stats' => function (\GuzzleHttp\TransferStats $stats) use (&$url) {
$url = $stats->getEffectiveUri();
}
] )->getBody()->getContents();
echo $url; // http://example.com/index.html
}

参考: How to read the response effective URL in Guzzle ~6.0


参考

Using GuzzleHttp with Laravel

Guzzle で Twitter REST API を叩く