タイトル: GET通信
SEOタイトル: PHP GET 通信完全ガイド(curl / Laravel HTTP / Guzzle / fetch / Postman)
| この記事の要点 |
|
GET 通信とは
HTTP の代表的なメソッドの一つで、サーバから情報を取得するのが本来の用途です。URL に ?key=value&key2=value2 形式でクエリ文字列を付与して送信し、サーバ側で読み取ります。
| 性質 | 説明 |
|---|---|
| 冪等性 | 何度同じリクエストを送っても結果が変わらない(基本) |
| キャッシュ可能 | ブラウザ / CDN がキャッシュする |
| ボディ無し(実質) | パラメータは URL に乗せる |
| URL 長制限 | サーバ・ブラウザによるが約 2000〜8000 文字 |
| 機密データ不向き | URL がブラウザ履歴 / アクセスログに残る |
PHP 側で受け取る
ctype_digit((string)$v));
// 全クエリを連想配列で
print_r($_GET);
// Array ( [q] => php [page] => 2 [ids] => Array ( [0] => 1 [1] => 2 ) )
// REQUEST_URI から自前パース
$urlParts = parse_url($_SERVER['REQUEST_URI']);
parse_str($urlParts['query'] ?? '', $params);
Laravel での受け取り
use Illuminate\Http\Request;
Route::get('/search', function (Request $request) {
// query() はクエリ文字列のみ、input() は POST/GET 両対応
$q = $request->query('q', '');
$page = (int) $request->query('page', 1);
// 検証付き
$validated = $request->validate([
'q' => 'nullable|string|max:100',
'page' => 'integer|min:1|max:1000',
'ids' => 'array',
'ids.*'=> 'integer',
]);
return view('search.index', compact('q', 'page'));
});
// FormRequest 化
class SearchRequest extends FormRequest {
public function rules(): array {
return [
'q' => 'nullable|string|max:100',
'page' => 'integer|min:1',
];
}
}
curl で GET 送信(PHP 内から)
true,
CURLOPT_TIMEOUT => 10,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 3,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_HTTPHEADER => array_merge([
'Accept: application/json',
'User-Agent: MyApp/1.0',
], $headers),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err = curl_error($ch);
curl_close($ch);
if ($body === false) {
throw new RuntimeException("curl error: $err");
}
return ['status' => $status, 'body' => $body];
}
// 利用
$resp = httpGet('https://api.example.com/users', ['page' => 1, 'per_page' => 20]);
$data = json_decode($resp['body'], true);
Laravel HTTP Client
Laravel 7+ には Guzzle ベースの Http ファサードが入っています。最も読みやすい書き方です:
use Illuminate\Support\Facades\Http;
// 基本
$response = Http::get('https://api.example.com/users', [
'page' => 1,
'per_page' => 20,
]);
if ($response->successful()) {
$data = $response->json();
}
// ヘッダ / タイムアウト / リトライ / 認証
$response = Http::withHeaders([
'Accept-Language' => 'ja',
])
->withToken($token) // Authorization: Bearer
->timeout(10)
->retry(3, 200) // 3 回、200ms 間隔
->get('https://api.example.com/users', ['q' => 'php']);
// マクロ / プール(並列)
$responses = Http::pool(fn ($pool) => [
$pool->get('https://api.example.com/a'),
$pool->get('https://api.example.com/b'),
]);
Guzzle 直接利用
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
$client = new Client([
'base_uri' => 'https://api.example.com',
'timeout' => 10,
'http_errors' => false, // 4xx/5xx で例外を投げない
]);
try {
$response = $client->get('/users', [
'query' => [
'page' => 1,
'ids' => [10, 20, 30], // ?ids[0]=10&ids[1]=20&ids[2]=30
],
'headers' => ['Accept' => 'application/json'],
]);
$data = json_decode((string)$response->getBody(), true);
} catch (GuzzleException $e) {
error_log($e->getMessage());
}
配列・ネストの送信
'php',
'ids' => [1, 2, 3],
'filter' => [
'category' => 'book',
'price' => ['min' => 100, 'max' => 5000],
],
];
$qs = http_build_query($params);
// q=php
// &ids%5B0%5D=1&ids%5B1%5D=2&ids%5B2%5D=3
// &filter%5Bcategory%5D=book
// &filter%5Bprice%5D%5Bmin%5D=100&filter%5Bprice%5D%5Bmax%5D=5000
// 区切りを「&」「&」のどちらにするか
http_build_query($params, '', '&', PHP_QUERY_RFC3986);
URL エンコードの違い
| 関数 | 挙動 | 用途 |
|---|---|---|
urlencode() | スペース → + | application/x-www-form-urlencoded |
rawurlencode() | スペース → %20 | RFC 3986 準拠(パスや一般的な URL) |
http_build_query() | 連想配列を一括変換(既定 PHP_QUERY_RFC1738) | クエリ文字列生成 |
CORS(クロスオリジン)の理解
ブラウザの JS から別オリジンの API を GET する場合、サーバ側でCORS ヘッダを返す必要があります:
JS との連携(fetch / axios)
// fetch API
const params = new URLSearchParams({ q: 'php', page: 2 });
fetch(`/api/search?${params}`, {
headers: { Accept: 'application/json' },
})
.then(r => r.json())
.then(data => console.log(data));
// axios
import axios from 'axios';
const { data } = await axios.get('/api/search', {
params: { q: 'php', page: 2, ids: [1, 2, 3] },
paramsSerializer: { indexes: false }, // ?ids=1&ids=2 形式
});
Postman / curl での検証
# curl で GET
curl -G https://api.example.com/users \
-H "Accept: application/json" \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode "q=php" \
--data-urlencode "page=2"
# ヘッダも表示
curl -i 'https://api.example.com/users?q=php'
# 詳細トレース
curl -v 'https://api.example.com/users?q=php'
# レスポンスを保存
curl -o out.json 'https://api.example.com/users'
Postman では Params タブにキー / バリューを追加すれば自動で URL にクエリが反映されます。Auth タブで Bearer Token、Headers タブでカスタムヘッダを設定。
注意点とアンチパターン
- パスワード / トークンを GET で送らない → アクセスログに残る
- 長い URL は 414 URI Too Long を引き起こす
- GET で副作用(DB 更新)を起こすとブラウザ プリフェッチで意図せず実行される
$_GET['param']を直接 SQL に埋め込まない → プリペアド文に渡す- XSS 防止のため、出力時は
htmlspecialchars()+ ホワイトリスト検証
FAQ
Q: GET の上限文字数は?
A: ブラウザは 2000〜8000 程度を保証、サーバは Nginx の large_client_header_buffers で調整。大きいデータは POST + body を使う。
Q: GET と POST どちらを使うべき?
A: 取得のみ → GET、状態変更 → POST/PUT/DELETE。RESTful 設計が API のキャッシュ性能を上げます。
Q: 同じパラメータ名を複数回送ると?
A: ?id=1&id=2 は $_GET['id'] に最後の値「2」だけが入ります。配列にするには ?id[]=1&id[]=2。