diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index afab299767..756f6b7f6c 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -466,32 +466,41 @@ class Request /** * Normalizes a query string. * - * It builds a normalized query string, where keys/value pairs are alphabetized - * and have consistent escaping. + * It builds a normalized query string, where keys/value pairs are alphabetized, + * have consistent escaping and unneeded delimiters are removed. * * @param string $qs Query string * - * @return string|null A normalized query string for the Request + * @return string A normalized query string for the Request */ - static public function normalizeQueryString($qs = null) + static public function normalizeQueryString($qs) { - if (!$qs) { - return null; + if ('' == $qs) { + return ''; } $parts = array(); $order = array(); - foreach (explode('&', $qs) as $segment) { - if (false === strpos($segment, '=')) { - $parts[] = $segment; - $order[] = $segment; - } else { - $tmp = explode('=', rawurldecode($segment), 2); - $parts[] = rawurlencode($tmp[0]).'='.rawurlencode($tmp[1]); - $order[] = $tmp[0]; + foreach (explode('&', $qs) as $param) { + if ('' === $param || '=' === $param[0]) { + // Ignore useless delimiters, e.g. "x=y&". + // Also ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway. + // PHP also does not include them when building _GET. + continue; } + + $keyValuePair = explode('=', $param, 2); + + // GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded). + // PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str. This is why we use urldecode and then normalize to + // RFC 3986 with rawurlencode. + $parts[] = isset($keyValuePair[1]) ? + rawurlencode(urldecode($keyValuePair[0])).'='.rawurlencode(urldecode($keyValuePair[1])) : + rawurlencode(urldecode($keyValuePair[0])); + $order[] = urldecode($keyValuePair[0]); } + array_multisort($order, SORT_ASC, $parts); return implode('&', $parts); @@ -843,7 +852,8 @@ class Request */ public function getQueryString() { - return static::normalizeQueryString($this->server->get('QUERY_STRING')); + $qs = static::normalizeQueryString($this->server->get('QUERY_STRING')); + return '' === $qs ? null : $qs; } /**