PHP Tips | 文字列処理:URL・パス系 – クエリ文字列を配列化

PHP PHP
スポンサーリンク

「クエリ文字列を配列化」で何をしたいのか

まず、ゴールのイメージからいきます。

"?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);
PHP

PHP_URL_QUERY を指定すると、? の右側だけを取ってきてくれます。


実務ユーティリティとして関数にまとめる

URL からクエリ配列を取得する関数

毎回 parse_urlparse_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'])) {
    // 検索キーワードを集計する、など
}
PHP

http://dummy のような適当なスキーム+ホストを付けてから parse_url させるテクニックは、
「パス+クエリだけ」の文字列を扱うときに便利です。

リダイレクト先 URL の検証に使う

例えば、「リダイレクト先 URL のクエリに含まれる token を検証したい」ケース。

$url    = $_GET['redirect'] ?? '';
$params = getQueryParams($url);

$token = $params['token'] ?? null;

if ($token === null) {
    // token がない → 拒否
}

// token の妥当性をチェック…
PHP

URL 全体を文字列でゴリゴリ処理するより、
「クエリは配列にして扱う」と決めた方が、コードが読みやすくなります。


注意ポイント: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('&') してゴリゴリ処理しているところ」があれば、そこがこのユーティリティの差し替えポイントです。

タイトルとURLをコピーしました