Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 54305d6

Browse filesBrowse files
committed
feature #26220 [HttpFoundation] Use parse_str() for query strings normalization (nicolas-grekas)
This PR was merged into the 4.1-dev branch. Discussion ---------- [HttpFoundation] Use parse_str() for query strings normalization | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Follow up of #26214 and #26202 The current normalization logic is both too loose and too broad: it changes the order of recursive data structures, while not normalizing keys. Since the normalization logic varies by query string parser, I'd like to propose a logic that exactly matches the native PHP one, which is exposed to userland via `parse_str()`. Using this, we accurately remove all useless information, while preserving all the meaningful one. (The change in `overrideGlobals()` is a bug fix to me btw, the current logic breaks the interpretation of legitimate query strings.) Commits ------- 5133536 [HttpFoundation] Use parse_str() for query strings normalization
2 parents e157ded + 5133536 commit 54305d6
Copy full SHA for 54305d6

File tree

3 files changed

+16
-30
lines changed
Filter options

3 files changed

+16
-30
lines changed

‎src/Symfony/Component/HttpFoundation/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
4.1.0
55
-----
66

7+
* Query string normalization uses `parse_str()` instead of custom parsing logic.
78
* Passing the file size to the constructor of the `UploadedFile` class is deprecated.
89
* The `getClientSize()` method of the `UploadedFile` class is deprecated. Use `getSize()` instead.
910
* added `RedisSessionHandler` to use Redis as a session storage

‎src/Symfony/Component/HttpFoundation/Request.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Request.php
+3-24Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -629,31 +629,10 @@ public static function normalizeQueryString($qs)
629629
return '';
630630
}
631631

632-
$parts = array();
633-
$order = array();
634-
635-
foreach (explode('&', $qs) as $param) {
636-
if ('' === $param || '=' === $param[0]) {
637-
// Ignore useless delimiters, e.g. "x=y&".
638-
// Also ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway.
639-
// PHP also does not include them when building _GET.
640-
continue;
641-
}
642-
643-
$keyValuePair = explode('=', $param, 2);
644-
645-
// GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded).
646-
// 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
647-
// RFC 3986 with rawurlencode.
648-
$parts[] = isset($keyValuePair[1]) ?
649-
rawurlencode(urldecode($keyValuePair[0])).'='.rawurlencode(urldecode($keyValuePair[1])) :
650-
rawurlencode(urldecode($keyValuePair[0]));
651-
$order[] = urldecode($keyValuePair[0]);
652-
}
653-
654-
array_multisort($order, SORT_ASC, $parts);
632+
parse_str($qs, $qs);
633+
ksort($qs);
655634

656-
return implode('&', $parts);
635+
return http_build_query($qs, '', '&', PHP_QUERY_RFC3986);
657636
}
658637

659638
/**

‎src/Symfony/Component/HttpFoundation/Tests/RequestTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
+12-6Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ public function testGetQueryString($query, $expectedQuery, $msg)
675675
public function getQueryStringNormalizationData()
676676
{
677677
return array(
678-
array('foo', 'foo', 'works with valueless parameters'),
678+
array('foo', 'foo=', 'works with valueless parameters'),
679679
array('foo=', 'foo=', 'includes a dangling equal sign'),
680680
array('bar=&foo=bar', 'bar=&foo=bar', '->works with empty parameters'),
681681
array('foo=bar&bar=', 'bar=&foo=bar', 'sorts keys alphabetically'),
@@ -684,18 +684,24 @@ public function getQueryStringNormalizationData()
684684
// PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str.
685685
array('him=John%20Doe&her=Jane+Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes spaces in both encodings "%20" and "+"'),
686686

687-
array('foo[]=1&foo[]=2', 'foo%5B%5D=1&foo%5B%5D=2', 'allows array notation'),
688-
array('foo=1&foo=2', 'foo=1&foo=2', 'allows repeated parameters'),
687+
array('foo[]=1&foo[]=2', 'foo%5B0%5D=1&foo%5B1%5D=2', 'allows array notation'),
688+
array('foo=1&foo=2', 'foo=2', 'merges repeated parameters'),
689689
array('pa%3Dram=foo%26bar%3Dbaz&test=test', 'pa%3Dram=foo%26bar%3Dbaz&test=test', 'works with encoded delimiters'),
690-
array('0', '0', 'allows "0"'),
691-
array('Jane Doe&John%20Doe', 'Jane%20Doe&John%20Doe', 'normalizes encoding in keys'),
690+
array('0', '0=', 'allows "0"'),
691+
array('Jane Doe&John%20Doe', 'Jane_Doe=&John_Doe=', 'normalizes encoding in keys'),
692692
array('her=Jane Doe&him=John%20Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes encoding in values'),
693-
array('foo=bar&&&test&&', 'foo=bar&test', 'removes unneeded delimiters'),
693+
array('foo=bar&&&test&&', 'foo=bar&test=', 'removes unneeded delimiters'),
694694
array('formula=e=m*c^2', 'formula=e%3Dm%2Ac%5E2', 'correctly treats only the first "=" as delimiter and the next as value'),
695695

696696
// Ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway.
697697
// PHP also does not include them when building _GET.
698698
array('foo=bar&=a=b&=x=y', 'foo=bar', 'removes params with empty key'),
699+
700+
// Don't reorder nested query string keys
701+
array('foo[]=Z&foo[]=A', 'foo%5B0%5D=Z&foo%5B1%5D=A', 'keeps order of values'),
702+
array('foo[Z]=B&foo[A]=B', 'foo%5BZ%5D=B&foo%5BA%5D=B', 'keeps order of keys'),
703+
704+
array('utf8=✓', 'utf8=%E2%9C%93', 'encodes UTF-8'),
699705
);
700706
}
701707

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.