検証した環境
・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
でリクエストデータが定義されているとのこと。
public function __construct($config = [])
{
if (is_string($config)) {
$config = ['url' => $config];
}
// 省略
$this->_setConfig($config);
}
まず、__construct
でリクエストデータを受け取り、_setConfig
関数に渡します。
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
に入れています。
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パラメーターの入った変数$queryString
をparse_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デコードされた値を取得する処理になっているということが確認できました。
実際に取得した値を出力してみればわかることではありますが、「実際そうなるから」ではなく、「本当にそういう仕様なのか?公式ドキュメントにないけど本当に?」というのを、フレームワークのソースコードを確認することにより、根拠を持って知ることができました。