タイトル: APIを呼び出す方法
SEOタイトル: PHP で API を呼び出す方法 完全ガイド(cURL / file_get_contents / Guzzle / GET / POST / JSON / エラーハンドリング)
| この記事の要点 |
|
PHP から API を呼ぶ 3 つの方法
| 方式 | 長所 | 短所 |
|---|---|---|
cURL(curl_*) | 柔軟、高速、ヘッダや SSL を細かく制御 | コードがやや冗長 |
| file_get_contents + コンテキスト | 1 行で書ける | POST / ヘッダがやや書きにくい、allow_url_fopen 必要 |
| Guzzle(HTTP クライアントライブラリ) | API がモダン、非同期 / リトライ / ミドルウェア対応 | Composer 必須 |
方法 1: cURL で GET
$apiUrl = 'https://api.example.com/users/1';
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $apiUrl,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true, // 結果を文字列で返す
CURLOPT_TIMEOUT => 10, // タイムアウト 10 秒
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_FOLLOWLOCATION => true, // リダイレクト追従
CURLOPT_HTTPHEADER => [
'Accept: application/json',
'Authorization: Bearer ' . $token,
],
]);
$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$err = curl_error($curl);
curl_close($curl);
if ($response === false) {
throw new RuntimeException('cURL error: ' . $err);
}
if ($status >= 400) {
throw new RuntimeException("HTTP $status: $response");
}
$data = json_decode($response, true);
print_r($data);
方法 2: cURL で POST(JSON ボディ)
$apiUrl = 'https://api.example.com/users';
$payload = json_encode([
'name' => '山田太郎',
'email' => 'taro@example.com',
], JSON_UNESCAPED_UNICODE);
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $apiUrl,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
'Content-Length: ' . strlen($payload),
],
CURLOPT_TIMEOUT => 10,
]);
$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
方法 3: cURL で PUT / DELETE
// PUT
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
// DELETE
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
方法 4: file_get_contents で簡易呼び出し
// GET
$response = file_get_contents('https://api.example.com/items');
$data = json_decode($response, true);
// POST(ストリームコンテキスト)
$options = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n" .
"Accept: application/json\r\n",
'content' => json_encode(['name' => 'apple']),
'timeout' => 10,
'ignore_errors' => true, // 4xx / 5xx でも本文を取得
],
];
$ctx = stream_context_create($options);
$response = file_get_contents('https://api.example.com/items', false, $ctx);
// レスポンスヘッダは $http_response_header に自動で入る
print_r($http_response_header);
注意: file_get_contents での URL 取得は allow_url_fopen=On が必要です。本番サーバではセキュリティ上オフにする運用もあるため、その場合は cURL を使います。
方法 5: Guzzle(推奨・モダン)
composer require guzzlehttp/guzzleuse GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
$client = new Client([
'base_uri' => 'https://api.example.com/',
'timeout' => 10,
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json',
],
]);
try {
// GET
$res = $client->get('users/1');
$user = json_decode($res->getBody(), true);
// POST (json オプションが自動エンコード)
$res = $client->post('users', [
'json' => ['name' => '山田', 'email' => 'taro@example.com'],
]);
// クエリパラメータ
$res = $client->get('users', [
'query' => ['page' => 2, 'limit' => 20],
]);
} catch (RequestException $e) {
error_log('API error: ' . $e->getMessage());
if ($e->hasResponse()) {
error_log('Body: ' . $e->getResponse()->getBody());
}
}
クエリパラメータの組み立て
$params = ['q' => 'PHP cURL', 'lang' => 'ja', 'page' => 2];
$url = 'https://api.example.com/search?' . http_build_query($params);
// → https://api.example.com/search?q=PHP+cURL&lang=ja&page=2
SSL 証明書の扱い(重要)
古いサンプルでよくある CURLOPT_SSL_VERIFYPEER = false は本番投入禁止です。中間者攻撃(MITM)に対し丸腰になります。社内自己署名 CA を使う場合は明示的に CA バンドルを指定します。
// 正しい指定(公的 CA バンドル)
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($curl, CURLOPT_CAINFO, '/etc/ssl/certs/ca-certificates.crt');
// 自己署名 CA を使うケースのみ
curl_setopt($curl, CURLOPT_CAINFO, '/path/to/internal-ca.pem');
タイムアウトとリトライ
| オプション | 意味 | 推奨値 |
|---|---|---|
CURLOPT_CONNECTTIMEOUT | 接続確立までの上限 | 3〜5 秒 |
CURLOPT_TIMEOUT | 処理全体の上限 | 10〜30 秒 |
5xx / ネットワークエラー時のリトライは指数バックオフで 2〜3 回が目安。POST 系の非冪等なリクエストはリトライしない(同じ処理が二重実行される)。
ステータスコード別の処理
switch (true) {
case $status >= 200 && $status < 300:
// 成功
break;
case $status === 401 || $status === 403:
throw new AuthException('認証エラー');
case $status === 404:
throw new NotFoundException('リソース無し');
case $status === 429:
// レート制限 → Retry-After に従って待機
break;
case $status >= 500:
throw new ServerException('サーバ側エラー');
default:
throw new ApiException("Unexpected $status");
}
セキュリティのチェックリスト
- API キー / トークンは環境変数(
.env)に置き、コードに直書きしない SSL_VERIFYPEERはtrueのまま- レスポンスをそのままユーザーに出力する場合はエスケープ必須
- 外部 URL を動的に組み立てる場合は SSRF 対策(プライベート IP への接続禁止など)
- ログにトークンを出さない