タイトル: URLパラメータの配列化
SEOタイトル: PHP URL パラメータの配列化完全ガイド($_GET / http_build_query / parse_str)
| この記事の要点 |
|
基本: ?key[]=value で配列受取
PHP は URL クエリ文字列中の [] を配列要素として解釈します。
// URL: https://example.com/?ids[]=1&ids[]=2&ids[]=3
print_r($_GET);
/*
Array (
[ids] => Array (
[0] => 1
[1] => 2
[2] => 3
)
)
*/
// 利用
foreach ($_GET['ids'] as $id) {
echo $id;
}
連想配列([key] 形式)
// URL: ?user[name]=taro&user[age]=30&user[email]=taro@example.com
print_r($_GET);
/*
Array (
[user] => Array (
[name] => taro
[age] => 30
[email] => taro@example.com
)
)
*/
// アクセス
$_GET['user']['name']; // "taro"
$_GET['user']['age']; // "30" (文字列)
多次元配列
// URL: ?cart[0][id]=10&cart[0][qty]=2&cart[1][id]=20&cart[1][qty]=1
print_r($_GET);
/*
Array (
[cart] => Array (
[0] => Array (
[id] => 10
[qty] => 2
)
[1] => Array (
[id] => 20
[qty] => 1
)
)
)
*/
// 利用
foreach ($_GET['cart'] as $item) {
echo "ID: {$item['id']}, 数量: {$item['qty']}\n";
}
配列から URL クエリ生成: http_build_query()
$params = [
'ids' => [1, 2, 3],
'user' => [
'name' => 'taro',
'age' => 30,
],
'lang' => 'ja',
];
echo http_build_query($params);
// ids%5B0%5D=1&ids%5B1%5D=2&ids%5B2%5D=3&user%5Bname%5D=taro&user%5Bage%5D=30&lang=ja
// URL デコードして見ると
// ids[0]=1&ids[1]=2&ids[2]=3&user[name]=taro&user[age]=30&lang=ja
// インデックス番号を入れない(連想配列のみ)
echo http_build_query($params, '', '&', PHP_QUERY_RFC3986);
// 区切り文字を変更
echo http_build_query($params, '', '&'); // HTML 中で使う際の安全化
// プレフィックス(インデックスが必要な場合の名前付け)
echo http_build_query(['filter' => [1, 2]], 'arg_');
RFC3986 vs RFC1738
| エンコーディング | スペース | 用途 |
|---|---|---|
| PHP_QUERY_RFC1738(デフォルト) | + | application/x-www-form-urlencoded(フォーム送信) |
| PHP_QUERY_RFC3986 | %20 | URL 一般(パス / ハッシュ) |
http_build_query(['q' => 'hello world']);
// "q=hello+world" (RFC1738)
http_build_query(['q' => 'hello world'], '', '&', PHP_QUERY_RFC3986);
// "q=hello%20world" (RFC3986)
URL クエリ文字列 → 配列: parse_str()
$qs = 'ids[]=1&ids[]=2&user[name]=taro&user[age]=30';
parse_str($qs, $result);
print_r($result);
/*
Array (
[ids] => Array ( [0] => 1 [1] => 2 )
[user] => Array ( [name] => taro [age] => 30 )
)
*/
// ❌ 第 2 引数省略は PHP 7.2+ で非推奨(グローバル汚染)
parse_str($qs);
echo $ids[0]; // 動くが非推奨
JavaScript 側で同形式を送る
URLSearchParams
const params = new URLSearchParams();
[1, 2, 3].forEach(id => params.append('ids[]', id));
params.append('user[name]', 'taro');
params.append('user[age]', 30);
console.log(params.toString());
// ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3&user%5Bname%5D=taro&user%5Bage%5D=30
fetch('/api?' + params.toString());
jQuery $.param()
const data = {
ids: [1, 2, 3],
user: { name: 'taro', age: 30 }
};
console.log($.param(data));
// ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3&user%5Bname%5D=taro&user%5Bage%5D=30
$.get('/api', data);
axios
import axios from 'axios';
import qs from 'qs';
// デフォルトでは ids: [1,2,3] が ids[]=1&ids[]=2 にならない
axios.get('/api', {
params: { ids: [1, 2, 3] },
paramsSerializer: params => qs.stringify(params, { arrayFormat: 'brackets' })
});
// → /api?ids[]=1&ids[]=2&ids[]=3
// arrayFormat オプション:
// 'indices' → ids[0]=1&ids[1]=2
// 'brackets' → ids[]=1&ids[]=2
// 'repeat' → ids=1&ids=2
// 'comma' → ids=1,2
POST フォームでの配列送信
GET と同じ書式が POST でも使えます。
// 受信
print_r($_POST);
/*
Array (
[tags] => Array ( [0] => php [1] => js )
[langs] => Array ( [0] => ja )
[user] => Array ( [name] => taro [email] => taro@example.com )
)
*/
Laravel での扱い
use Illuminate\Http\Request;
public function index(Request $request) {
// GET /search?ids[]=1&ids[]=2&ids[]=3
$ids = $request->input('ids'); // [1, 2, 3]
$ids = $request->input('ids', []); // デフォルト空配列
// 連想配列
$userName = $request->input('user.name'); // ドット記法
$userAge = $request->input('user.age');
// バリデーション
$validated = $request->validate([
'ids' => 'array|min:1',
'ids.*' => 'integer', // 各要素のバリデーション
'user.name' => 'required|string',
'user.age' => 'integer|min:0',
]);
// クエリビルダで使う
$users = User::whereIn('id', $ids)->get();
}
Postman での配列送信
| 方法 | 記法 |
|---|---|
| Query Params タブ | キーに ids[]、値に 1。複数行追加 |
| URL に直接 | ?ids[]=1&ids[]=2&ids[]=3 |
| Body (form-data) | キー ids[] を複数行 |
| Body (raw JSON) | {"ids": [1, 2, 3]}(API がこちらを期待する場合) |
JSON 形式で送る代替案
API として設計するなら、クエリ配列より JSON が現代的で型情報も明確:
// JS
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
ids: [1, 2, 3],
user: { name: 'taro', age: 30 }
})
});// PHP 受信
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
print_r($data);
/*
Array (
[ids] => Array ( [0] => 1 [1] => 2 [2] => 3 )
[user] => Array ( [name] => taro [age] => 30 )
)
*/
// Laravel は自動で json デコード
$ids = $request->input('ids');
注意点・ハマりどころ
| 症状 | 原因 | 対処 |
|---|---|---|
| 配列が文字列で来る | ?ids=1,2,3 形式 | explode(',', $_GET['ids']) |
| URL が長すぎてエラー | GET の URL 長制限 (2KB 〜) | POST へ変更 |
max_input_vars 超過 | php.ini デフォルト 1000 | php.ini で増やす or 構造変更 |
| ネスト深すぎで取得不能 | 多次元配列の解釈 | JSON ボディに切替 |
?ids[]= 空文字 | 空配列ではなく [''] になる | array_filter() で除去 |
セキュリティの注意
- 受け取った配列は必ず型バリデーション(int / string / 範囲)
- SQL に直接使わない → プリペアドステートメント +
IN (?, ?, ?) array_map('intval', $ids)で整数強制もよくあるテクニック- 巨大配列でメモリ枯渇 DoS →
count()で件数上限チェック
// 安全な受け取り
$ids = $request->input('ids', []);
if (!is_array($ids) || count($ids) > 100) {
abort(400, 'ids は最大 100 件');
}
$ids = array_values(array_unique(array_map('intval', $ids)));
// IN 句で使う
$users = User::whereIn('id', $ids)->get();
FAQ
Q: ?ids=1&ids=2 ([] 無し)で配列にできる?
A: PHP では後勝ちで $_GET['ids'] = "2" になります。配列にするには [] 必須。Java/Spring 等は同名キーで自動配列化。
Q: URL が長くなりすぎる
A: 100 件超えるなら POST + JSON ボディに。またはカンマ区切り ?ids=1,2,3 + サーバ側で explode も実用的。
Q: max_input_vars 警告
A: 1000 個超のフォームフィールドで発生。php.ini の max_input_vars = 5000 で緩和、またはJSON 化で根本解決。