19.

PHP cURL の使い方総まとめ — GET / POST / ヘッダ / タイムアウト / エラー処理

編集
この記事の要点
  • 4 ステップ: curl_init()curl_setopt()curl_exec()curl_close()
  • 必須オプション: CURLOPT_RETURNTRANSFER=true(戻り値で受け取る)と CURLOPT_TIMEOUT(無限待ち防止)
  • POST は CURLOPT_POST=true + CURLOPT_POSTFIELDS。JSON 送信時は Content-Type: application/json ヘッダを忘れない
  • エラー検知は curl_errno() / curl_error() と HTTP ステータス curl_getinfo($ch, CURLINFO_HTTP_CODE)
  • Laravel なら Http::get() / Guzzle なら new Client; ->request() の方がコードが激減

最小の GET リクエスト

$ch = curl_init('https://api.example.com/users/1');

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);   // 戻り値で受け取る (echo しない)
curl_setopt($ch, CURLOPT_TIMEOUT, 10);            // 全体 10 秒で中断
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);      // 接続段階 5 秒

$body = curl_exec($ch);

if ($body === false) {
    $err = curl_error($ch);
    $errno = curl_errno($ch);
    error_log("cURL error ($errno): $err");
    curl_close($ch);
    throw new RuntimeException("通信失敗: $err");
}

$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new RuntimeException("HTTP $status: $body");
}

$data = json_decode($body, true);

POST リクエスト(フォーム送信)

$ch = curl_init('https://api.example.com/login');

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'email'    => 'taro@example.com',
    'password' => 'secret',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/x-www-form-urlencoded',
    'Accept: application/json',
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

JSON を POST する

$payload = json_encode([
    'title' => 'Hello',
    'body'  => 'World',
    'tags'  => ['php', 'curl'],
], JSON_UNESCAPED_UNICODE);

$ch = curl_init('https://api.example.com/posts');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 10,
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $payload,
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        'Authorization: Bearer ' . $token,
        'Accept: application/json',
    ],
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

主要オプション一覧

オプション意味推奨値
CURLOPT_RETURNTRANSFER戻り値で受け取るtrue 必須
CURLOPT_TIMEOUT全体タイムアウト10〜30 秒
CURLOPT_CONNECTTIMEOUT接続タイムアウト5 秒
CURLOPT_FOLLOWLOCATION3xx リダイレクト追従true
CURLOPT_MAXREDIRSリダイレクト最大回数5
CURLOPT_HTTPHEADERリクエストヘッダ配列
CURLOPT_USERAGENTUA 文字列サービス名 + URL
CURLOPT_SSL_VERIFYPEERSSL 証明書検証true(本番)
CURLOPT_HEADERレスポンスヘッダ込で取得必要時 true
CURLOPT_POSTPOST モードtrue
CURLOPT_POSTFIELDSPOST 本文文字列 or 配列
CURLOPT_CUSTOMREQUESTPUT / DELETE 等の指定'PUT'

レスポンスヘッダを取得する

$ch = curl_init('https://example.com/');

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HEADER         => true,        // ヘッダもボディに含めて返す
]);

$response = curl_exec($ch);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$rawHeader  = substr($response, 0, $headerSize);
$body       = substr($response, $headerSize);
curl_close($ch);

// ヘッダを連想配列に
$headers = [];
foreach (explode("\r\n", trim($rawHeader)) as $line) {
    if (strpos($line, ':') !== false) {
        [$k, $v] = explode(':', $line, 2);
        $headers[strtolower(trim($k))] = trim($v);
    }
}
$contentType = $headers['content-type'] ?? null;

エラー処理の網羅版

function httpGet(string $url): array
{
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 15,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS      => 5,
        CURLOPT_USERAGENT      => 'MyApp/1.0',
    ]);

    $body = curl_exec($ch);
    if ($body === false) {
        $msg = sprintf('cURL %d: %s', curl_errno($ch), curl_error($ch));
        curl_close($ch);
        throw new RuntimeException($msg);
    }
    $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($status >= 400) {
        throw new RuntimeException("HTTP $status returned");
    }
    return ['status' => $status, 'body' => $body];
}

リトライロジック

function httpGetWithRetry(string $url, int $maxRetry = 3): string
{
    $attempt = 0;
    while (true) {
        $attempt++;
        try {
            return httpGet($url)['body'];
        } catch (RuntimeException $e) {
            if ($attempt >= $maxRetry) throw $e;
            usleep(min(2 ** $attempt, 8) * 1_000_000);  // 指数バックオフ
        }
    }
}

Guzzle / Http ファサードとの比較

// === 同じことを Guzzle で ===
use GuzzleHttp\Client;

$client = new Client(['timeout' => 10]);
$res = $client->post('https://api.example.com/posts', [
    'json' => ['title' => 'Hello'],
    'headers' => ['Authorization' => "Bearer $token"],
]);
$body = (string) $res->getBody();
$status = $res->getStatusCode();

// === Laravel の Http ファサード ===
use Illuminate\Support\Facades\Http;

$res = Http::withToken($token)
    ->timeout(10)
    ->retry(3, 100)
    ->post('https://api.example.com/posts', ['title' => 'Hello']);

$res->json();        // 配列化
$res->status();      // 200
$res->successful();  // true/false

FAQ

Q: PUT / DELETE はどう送る?
A: CURLOPT_CUSTOMREQUEST => 'PUT'(または DELETE)。PUT で本文を送りたい場合は CURLOPT_POSTFIELDS も併用。

Q: HTTPS 検証エラー(cURL error 60)
A: 古い CA バンドル。CURLOPT_CAINFO最新の cacert.pem のパスを指定するか、PHP の curl.cainfo を設定。verify=false にしての回避は本番では絶対やらない

Q: マルチパート(ファイル)送信
A: CURLOPT_POSTFIELDS['file' => new CURLFile('/path/to/x.png')] を渡す。Content-Type ヘッダは自動付与に任せる。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. ls ファイル/ディレクトリ一覧表示
  2. sudo ユーザー指定
  3. cron/crontab ジョブの自動実行と登録方法
  4. wget http通信によるファイルダウンロード
  5. rm ファイル/ディレクトリ削除
  6. pwd カレントディレクトリの表示
  7. cd ディレクトリの移動
  8. ./configure
  9. make
  10. make install
  11. unzip ファイルの解凍
  12. mv ファイル/ディレクトリの移動および名称変更
  13. mkdir ディレクトリの作成
  14. touch 空ファイルの新規作成
  15. vi テキストディタの使用
  16. find ファイル/ディレクトリ検索
  17. grep 文字列の検索
  18. tail ファイルの末尾表示
  19. curl HTTP通信によるリクエスト
  20. nslookup ドメインのIP解決
  21. apt update パッケージリストの情報を更新
  22. apt upgrade パッケージの更新
  23. ln リンク/ショートカットの作成と削除
  24. rsync ファイル/ディレクトリの同期
  25. ssh リモートとの暗号化通信
  26. scp sshを利用したファイルのコピー
  27. unzip zip ファイルを解凍する
  28. cp ファイル/ディレクトリのコピー
  29. diffファイルの差分抽出
  30. fdisk ハードディスクに対する操作
  31. lsblk デバイスをツリー状で表示する
  32. kill プロセスを終了させる
  33. zip ファイルやディレクトリをzip形式に圧縮する
  34. host ドメインからIPアドレスを確認
  35. chmod 権限の変更
  36. ip IPアドレスの確認
  37. chown ファイル/ディレクトリ所有者の変更
  38. chgrp ファイル/ディレクトリのグループ情報の変更
  39. nohupと'&' プログラムのバックグラウンド実行(ssh接続時)
  40. lsof 開いているポート番号の確認
  41. tar ファイルの圧縮と解凍
  42. file ファイルの種類を表示
  43. cat ファイルの中身を表示
  44. head ファイルの先頭部分を表示
  45. wc 行数/単語数/文字数を確認
  46. shutdown システムのシャットダウンと再起動
  47. ps プロセスの確認
  48. which コマンドの絶対パスを調べる
  49. yum RedHat系ディストリビューションの管理
  50. mount ファイルシステムのマウント
  51. 特定フォルダ以下の特定拡張子のファイルを再帰的に削除する方法
  52. 特定のフォルダとそのサブフォルダ内にある特定のファイル名のファイルを再帰的に削除