Symfony Component Advent Calendar 2022の17日目の記事です。
最初に
SymfonyはPHPのフレームワークのひとつです。しかし、公式サイトの説明文には
Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community — all working together in harmony.
(SymfonyはPHPコンポーネントのセットで、Webアプリケーションフレームワークで、哲学、そしてコミュニティです。それらがハーモニーを奏でながら動作しています。)
と書かれている通り、PHPコンポーネントのセットで、たくさんのコンポーネントを提供しており、それらを組み合わせてひとつのフレームワークとして動作しています。Symfonyのコンポーネントは、Symfony上だけで動作するのではなく、他のPHPフレームワークやアプリケーションでも動作している強力なものが揃っています。
今回はそれらの中から、役立ちそうなもの・お薦めしたいものを紹介していきたいと思います。
※記事内ではautoloadのインポートは省略します。
HTTP通信クライアント、"HttpClient"
HttpClientは、その名の通りHTTP通信のクライアントを扱うコンポーネントです。通常のHTTP通信に加え、SSRF対策、HTTP/2通信、ストリーム通信などに対応しています。
インストール
composer require symfony/http-client
HTTP通信する
HttpClient
オブジェクトを使って通信を行います。Symfonyの場合は、いつも通りオートワイヤリングでDIできます。
GET
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\HttpClient;
// Symfony以外の場合
$client = HttpClient::create();
$response = $client->request('GET', 'https://qiita.com/api/v2/items?query=Symfony', [
'headers' => [
'Authorization' => 'Bear: ......'
],
]);
// ステータスコード
$statusCode = $response->getStatusCode();
// レスポンスヘッダ
$headers = $response->getHeaders();
// レスポンスを文字列で
$response->getContent();
// レスポンスを配列で
$response->toArray();
// Symfonyの場合
class SomeService
{
public function __construct(private readonly HttpClientInterface $client)
{
}
public function someMethod()
{
$response = $client->request('GET', 'https://qiita.com/api/v2/items?query=Symfony', [
'headers' => [
'Authorization' => 'Bear: ......'
],
]);
// 以下同様
}
}
POST
POSTデータを送る場合は、request()
メソッドの第3引数にbody
というキーで設定します。JSONを送信する場合はbody
ではなく、json
を使うと、Content-Type: application/json
を勝手にヘッダに追加してくれます。
$client = HttpClient::create();
$response = $client->request('POST', 'https://qiita.com/api/v2/items', [
'body' => '{"titie": "Symfonyすき"}', // 生データの場合
'body' => ['title' => 'Symfonyすき'], // 配列の場合
'json' => ['title' => 'Symfonyすき'], // JSONで送る場合
]);
// レスポンスはGETと同じように扱えます
SSRF(Server-side Request forgery)対策
HttpClientでは、SSRF対策として、NoPrivateNetworkHttpClient
クラスが用意されています。
NoPrivateNetworkHttpClient
を使うと、内部サーバへのHTTP通信ができないようになります。
$url = $request->request->get('your_url');
try {
$client = new NoPrivateNetworkHttpClient(HttpClient::create());
$response = $client->request('GET', $url);
...
} catch (TransportException $e) {
// 内部サーバへのHTTP通信の場合、TransportExceptionを吐きます。
...
}
HTTP/2対応
以下の条件をクリアしていれば自動的にHTTP/2通信となります。
- httpsにアクセス
- libcurl 7.36以上 もしくは、amphp/http-client 4.2以上インストール済み
ストリーム通信対応
アクセス先がストリーミング配信の場合、stream()
メソッドを使うことで対応可能です。
$response = $client->request('GET', $url);
foreach ($client->stream($response) as $chunk) {
print_r($chunk->getContent()); // ストリーム配信されたデータを受け取るたびに出力
}
また、非同期で複数のリクエストも受け取ることができます。
$responses = [];
$images = [
'a.png',
'b.png',
'c.png',
];
foreach($images as $image) {
$url = sprintf("https://some-domain/%s", $image);
$responses[] = $client->request('GET', $url);
}
foreach ($client->stream($responses) as $response => $chunk) {
// $responseはそれぞれのレスポンスオブジェクト
// $chunkはそれぞれの配信されたデータ
}
まとめ
今回はHttpClient
について紹介しました。PHPでHTTP通信といえばGuzzleですが、Symfony公式が用意してくれてるので、せっかくならこちらを使っていきたいところです。