LoginSignup
7
4

More than 3 years have passed since last update.

【CakePHP】$this->request->query()はちゃんとURLデコードされている

Last updated at Posted at 2020-08-28

検証した環境

・CakePHP2
・CakePHP3.8

なぜこの記事を書いたか

タイトルの通りです。
GETパラメーターを渡し、コントローラーで$this->request->query()で受け取ること、良くあると思います。
その際、GETパラメーターにURLエンコードされた値を渡すことがあります。
そしてそのGETパラメーターを、コントローラーで$this->request->query()で取得すると、いつの間にかURLデコードされた値になっています。

// ユーザーIDをカンマ区切りで複数渡したい時
// 1234,5678,9012 をURLエンコードしてGETパラメーターで渡す。
https://sample.com/users/index?user_id=1234%2C5678%2C9012

// コントローラーでuser_idを取得
$user_id = $this->request->query('user_id');

// 取得したuser_idの中身は、「1234,5678,9012」になっている。
 (URLデコードされている)

そんなの常識なのかもしれませんが、「実際こうなって取得できるし、そういう仕様なんだろう」と思っていたら、
「ちゃんと公式ドキュメントかソースコードで確認したほうが良い。なんとなくこうだから〜で済ませてはダメ」
と指摘されたので、確認することにしました。

公式ドキュメントを確認

Cookbook
https://book.cakephp.org/3/ja/controllers/request-response.html#cake-request

ここの「クエリー文字列パラメーター」の項目では、特にURLエンコード・デコードについては書かれていません。

ソースコードを確認

CakePHPのソースコードを見て、URLデコードしている処理があるか確認します。
ここではCakePHP3系のソースコードで説明します。

上記のドキュメントによるとCake\Http\ServerRequestでリクエストデータが定義されているとのこと。

Cake\Http\ServerRequest
    public function __construct($config = [])
    {
        if (is_string($config)) {
            $config = ['url' => $config];
        }
        // 省略

        $this->_setConfig($config);
    }

まず、__constructでリクエストデータを受け取り、_setConfig関数に渡します。

Cake\Http\ServerRequest
    protected function _setConfig($config)
    {
        // 省略

        $querystr = '';
        if (strpos($config['url'], '?') !== false) {
            list($config['url'], $querystr) = explode('?', $config['url']);
        }
        // ここでURLを「?」で区切ったものを配列にいれている
        // urlの「?」の右側、つまりGETパラメーターが変数$querystrに代入される

        // 省略

        $this->data = $this->_processFiles($config['post'], $config['files']);
        $this->query = $this->_processGet($config['query'], $querystr);
        // ここで$this->request->query()で使える値が入る
        $this->params = $config['params'];
        $this->session = $config['session'];
    }

_setConfig関数の中で、GETパラメーターを変数$querystrに入れ、_processGet関数に渡しています。
_processGet関数が返す値を$this->queryに入れています。

Cake\Http\ServerRequest
    protected function _processGet($query, $queryString = '')
    {
        $unsetUrl = '/' . str_replace(['.', ' '], '_', urldecode($this->url));
        unset($query[$unsetUrl], $query[$this->base . $unsetUrl]);
        if (strlen($queryString)) {
            parse_str($queryString, $queryArgs);
            // parse_str関数によりURLエンコードされた値がURLデコードされて変数に入れられる
            $query += $queryArgs;
        }

        return $query;
    }

第二引数で受け取ったGETパラメーターの入った変数$queryStringparse_str関数で処理し、変数$queryArgsに入れています。
parse_str関数により、変数$queryArgsにはURLデコードされた値が入ります。
そしてそれを返しているということになります。

parse_str関数
https://www.php.net/manual/ja/function.parse-str

注意:
全ての作成された変数 (第二引数が設定された場合は配列に設定される値) の値は、既に urldecode() されています。

ということで、冒頭でも話したように、GETパラメーターでURLエンコードされた値を渡し、CakePHPのコントローラーで$this->request->query()を使ってGETパラメーターを取得した場合、すでにURLデコードされた値を取得する処理になっているということが確認できました。

実際に取得した値を出力してみればわかることではありますが、「実際そうなるから」ではなく、「本当にそういう仕様なのか?公式ドキュメントにないけど本当に?」というのを、フレームワークのソースコードを確認することにより、根拠を持って知ることができました。

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4