「クエリ文字列を配列化」で何をしたいのか
まず、ゴールのイメージからいきます。
"?q=php&sort=desc&page=2"
→ ['q' => 'php', 'sort' => 'desc', 'page' => '2']
"?tag[]=php&tag[]=laravel&tag[]=symfony"
→ ['tag' => ['php', 'laravel', 'symfony']]
"foo=1&foo=2"
→ ['foo' => ['1', '2']](扱い方次第)
やりたいことはシンプルです。
URL の
?以降(クエリ文字列)を、
「キーと値の配列」として扱いたい。
業務だと、ログ解析、API の署名生成、リダイレクト URL の検証、自前ルーターの実装などでよく出てきます。
PHP には、これをやるための便利な関数がすでに用意されています。
PHP の基本:parse_str でクエリ文字列を配列にする
parse_str の基本形
クエリ文字列を配列にする標準関数は parse_str です。
parse_str(string $string, array &$result): void
PHP第二引数に「結果を入れる配列変数」を渡すと、
そこにキー・値が展開されます。
$query = "q=php&sort=desc&page=2";
$result = [];
parse_str($query, $result);
var_dump($result);
PHP出力イメージはこうです。
array(3) {
["q"] => "php"
["sort"] => "desc"
["page"] => "2"
}
PHPこれで、クエリ文字列を「連想配列」として扱えるようになります。
URL 全体からクエリ部分だけを取り出す
parse_str は「クエリ部分だけ」を渡す前提なので、
URL 全体からクエリだけを取り出したいときは parse_url と組み合わせます。
$url = "https://example.com/search?q=php&sort=desc&page=2";
$query = parse_url($url, PHP_URL_QUERY); // "q=php&sort=desc&page=2"
$params = [];
parse_str($query ?? '', $params);
var_dump($params);
PHPPHP_URL_QUERY を指定すると、? の右側だけを取ってきてくれます。
実務ユーティリティとして関数にまとめる
URL からクエリ配列を取得する関数
毎回 parse_url と parse_str を書くのは面倒なので、
ユーティリティ関数にしてしまうとスッキリします。
/**
* URL からクエリ文字列を配列化して返す
* クエリがない場合は空配列
*/
function getQueryParams(string $url): array
{
$query = parse_url($url, PHP_URL_QUERY);
if ($query === null || $query === false || $query === '') {
return [];
}
$params = [];
parse_str($query, $params);
return $params;
}
PHP使い方の例です。
$url = "https://example.com/search?q=php&sort=desc&page=2";
$params = getQueryParams($url);
echo $params['q']; // php
echo $params['sort']; // desc
echo $params['page']; // 2
PHP「クエリがないときは空配列を返す」という仕様にしておくと、
呼び出し側が扱いやすくなります。
配列パラメータ・重複キーの扱いを理解する
tag[]=php&tag[]=laravel のような配列パラメータ
PHP のクエリ文字列は、[] を付けると配列として解釈されます。
$query = "tag[]=php&tag[]=laravel&tag[]=symfony";
$params = [];
parse_str($query, $params);
var_dump($params);
PHP結果はこうなります。
array(1) {
["tag"] => array(3) {
[0] => "php"
[1] => "laravel"
[2] => "symfony"
}
}
PHPフォームから送られてくる「チェックボックスの複数選択」などは、
だいたいこの形式です。
getQueryParams() を使っても同じです。
$url = "https://example.com/search?tag[]=php&tag[]=laravel";
$params = getQueryParams($url);
var_dump($params['tag']); // ['php', 'laravel']
PHP同じキーが複数ある場合
$query = "foo=1&foo=2";
$params = [];
parse_str($query, $params);
var_dump($params);
PHP結果はこうなります。
array(1) {
["foo"] => "2"
}
PHP最後の値で上書きされます。
もし「全部の値を配列として取りたい」なら、
クエリ側を foo[]=1&foo[]=2 のように設計する必要があります。
ここは「クエリの設計」とセットで考えるポイントです。
実務での使いどころのイメージ
ログに残っている URL からパラメータを抜き出す
アクセスログなどに URL がそのまま残っているとき、
特定のパラメータだけを集計したいことがあります。
$line = 'GET /search?q=php&sort=desc&page=2 HTTP/1.1';
$parts = explode(' ', $line);
$path = $parts[1] ?? '';
$params = getQueryParams('http://dummy' . $path);
if (isset($params['q'])) {
// 検索キーワードを集計する、など
}
PHPhttp://dummy のような適当なスキーム+ホストを付けてから parse_url させるテクニックは、
「パス+クエリだけ」の文字列を扱うときに便利です。
リダイレクト先 URL の検証に使う
例えば、「リダイレクト先 URL のクエリに含まれる token を検証したい」ケース。
$url = $_GET['redirect'] ?? '';
$params = getQueryParams($url);
$token = $params['token'] ?? null;
if ($token === null) {
// token がない → 拒否
}
// token の妥当性をチェック…
PHPURL 全体を文字列でゴリゴリ処理するより、
「クエリは配列にして扱う」と決めた方が、コードが読みやすくなります。
注意ポイント:parse_str の「第1引数だけ」の使い方は避ける
parse_str には、第二引数なしでこういう使い方もあります。
parse_str("a=1&b=2");
// $a と $b という変数が勝手に作られる
PHPこれは「クエリのキー名を、そのまま変数名として展開する」動きです。
便利そうに見えますが、
- どんな変数が増えるかコードから見えない
- 既存の変数を上書きしてしまう可能性がある
- セキュリティ的にも危険
という理由で、実務ではほぼ「使ってはいけない」部類です。
必ず第二引数に配列を渡して、
$params = [];
parse_str($query, $params);
PHPという形で使うようにしてください。
まとめ:今日からの「クエリ文字列を配列化」ユーティリティ
押さえておきたいポイントはこれです。
クエリ文字列 → 配列は parse_str 一択でよい。
URL 全体からクエリを取りたいときは parse_url($url, PHP_URL_QUERY) と組み合わせる。
ユーティリティとしては getQueryParams(string $url): array のようにまとめておくと、呼び出し側がスッキリする。
配列パラメータ(tag[]=...)や重複キーの扱いは、クエリ設計とセットで考える。parse_str を第二引数なしで使って「変数をばらまく」書き方は避ける。
核になるコードは、これだけです。
function getQueryParams(string $url): array
{
$query = parse_url($url, PHP_URL_QUERY);
if ($query === null || $query === false || $query === '') {
return [];
}
$params = [];
parse_str($query, $params);
return $params;
}
PHPもし、あなたのコードの中で「? 以降を explode('&') してゴリゴリ処理しているところ」があれば、そこがこのユーティリティの差し替えポイントです。
