[CakePHP]$this->request->query() is URL decoded properly

Aug 28, 2020 PHP CakePHP url encoding get parameter url decoding

Validated environment

・CakePHP2 ・CakePHP3.8

Why I wrote this article

As the title says. I think it’s common to pass a GET parameter and get it in the controller with $this->request->query(). At that time, a URL encoded value may be passed to the GET parameter. And when I get that GET parameter with $this->request->query() in the controller, it becomes a URL-decoded value before I knew it.

// When you want to pass multiple user IDs separated by commas
// URL encode 1234,5678,9012 and pass it as a GET parameter.
https://sample.com/users/index?user_id=1234%2C5678%2C9012

// get user_id in controller
$user_id = $this->request->query('user_id');

// The content of the acquired user_id is "1234,5678,9012".
(URL decoded)

It may be common sense, but if you think “it can be acquired like this and it is such a specification”, “It’s better to check the official documentation or the source code. It’s something like this, so don’t do it with ~” I was pointed out, so I decided to confirm.

Check official documentation

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

In the “Query string parameters” section here, URL encoding/decoding is not particularly written.

Check source code

Look at the CakePHP source code and check if there is any URL decoding process. Here, it explains with the source code of CakePHP3 series.

According to the above document, request data is defined in Cake\Http\ServerRequest.

    public function __construct($config = [])
    {
        if (is_string($config)) {
            $config = ['url' => $config];
        }
        // omitted

        $this->_setConfig($config);
    }

First, receive the request data with __construct and pass it to the _setConfig function.

    protected function _setConfig($config)
    {
        // omitted

        $querystr = ``;
        if (strpos($config['url'],'?') !== false) {
            list($config['url'], $querystr) = explode('?', $config['url']);
        }
        // Here, put the URL separated by "?" in the array
        // Right side of "?" of url, that is, GET parameter is assigned to variable $querystr

        // omitted

        $this->data = $this->_processFiles($config['post'], $config['files']);
        $this->query = $this->_processGet($config['query'], $querystr);
        // Here, the value that can be used in $this->request->query() is entered
        $this->params = $config['params'];
        $this->session = $config['session'];
    }

In the _setConfig function, we put the GET parameter in the variable $querystr and pass it to the _processGet function. I put the value returned by the _processGet function in $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);
            // The URL-encoded value is URL-decoded and put into a variable by the parse_str function
            $query += $queryArgs;
        }

        return $query;
    }

The variable $queryString containing the GET parameter received as the second argument is processed by the parse_str function and put in the variable $queryArgs. With the parse_str function, the variable $queryArgs will contain the URL-decoded value. And it means returning it.

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

Note:
The values of all created variables (values that will be set in the array if the second argument is set) have already been urldecode()'ed.

So, as I said at the beginning, if you pass the URL encoded value with the GET parameter and get the GET parameter using $this->request->query() in the CakePHP controller, the URL is already It was confirmed that the process is to get the decoded value.

As you can see by outputting the value actually obtained, it is not “because it will be so”, but “is it really that kind of specification? It’s not in the official document, but really?” By confirming, I was able to know with a basis.