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 ee28ab3

Browse filesBrowse files
[HttpFoundation] Add parse_str()-based methods for query strings normalization
1 parent b0facfe commit ee28ab3
Copy full SHA for ee28ab3

File tree

2 files changed

+95
-2
lines changed
Filter options

2 files changed

+95
-2
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Request.php
+49-2Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,9 +524,11 @@ public function __toString()
524524
*/
525525
public function overrideGlobals()
526526
{
527-
$this->server->set('QUERY_STRING', static::normalizeQueryString(http_build_query($this->query->all(), null, '&')));
527+
$qs = $this->query->all();
528+
ksort($qs);
529+
$this->server->set('QUERY_STRING', http_build_query($qs, null, '&', PHP_QUERY_RFC3986));
528530

529-
$_GET = $this->query->all();
531+
$_GET = $qs;
530532
$_POST = $this->request->all();
531533
$_SERVER = $this->server->all();
532534
$_COOKIE = $this->cookies->all();
@@ -656,6 +658,24 @@ public static function normalizeQueryString($qs)
656658
return implode('&', $parts);
657659
}
658660

661+
/**
662+
* Normalizes a query string using `parse_str()`.
663+
*
664+
* It builds a normalized query string, where root-keys/value pairs are alphabetized,
665+
* have consistent escaping and unneeded delimiters are removed.
666+
*/
667+
public static function normalizeQueryStringForPhp(string $qs): string
668+
{
669+
if ('' == $qs) {
670+
return '';
671+
}
672+
673+
parse_str($qs, $qs);
674+
ksort($qs);
675+
676+
return http_build_query($qs, '', '&', PHP_QUERY_RFC3986);
677+
}
678+
659679
/**
660680
* Enables support for the _method request parameter to determine the intended HTTP method.
661681
*
@@ -1032,6 +1052,20 @@ public function getUri()
10321052
return $this->getSchemeAndHttpHost().$this->getBaseUrl().$this->getPathInfo().$qs;
10331053
}
10341054

1055+
/**
1056+
* Generates a `parse_str()`-normalized URI (URL) for the Request.
1057+
*
1058+
* @see getQueryStringForPhp()
1059+
*/
1060+
public function getUriForPhp(): string
1061+
{
1062+
if (null !== $qs = $this->getQueryStringForPhp()) {
1063+
$qs = '?'.$qs;
1064+
}
1065+
1066+
return $this->getSchemeAndHttpHost().$this->getBaseUrl().$this->getPathInfo().$qs;
1067+
}
1068+
10351069
/**
10361070
* Generates a normalized URI for the given path.
10371071
*
@@ -1114,6 +1148,19 @@ public function getQueryString()
11141148
return '' === $qs ? null : $qs;
11151149
}
11161150

1151+
/**
1152+
* Generates the query string for the Request, using `parse_str()` it value.
1153+
*
1154+
* It builds a normalized query string, where root-keys/value pairs are alphabetized
1155+
* and have consistent escaping.
1156+
*/
1157+
public function getQueryStringForPhp(): ?string
1158+
{
1159+
$qs = static::normalizeQueryStringForPhp($this->server->get('QUERY_STRING'));
1160+
1161+
return '' === $qs ? null : $qs;
1162+
}
1163+
11171164
/**
11181165
* Checks whether the request is secure or not.
11191166
*

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
+46Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,52 @@ public function getQueryStringNormalizationData()
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+
// Also reorder nested query string keys
701+
array('foo[]=Z&foo[]=A', 'foo%5B%5D=A&foo%5B%5D=Z', 'reorders values'),
702+
array('foo[Z]=B&foo[A]=B', 'foo%5BA%5D=B&foo%5BZ%5D=B', 'reorders keys'),
703+
);
704+
}
705+
706+
/**
707+
* @dataProvider getQueryStringNormalizationDataForPhp
708+
*/
709+
public function testGetQueryStringForPhp($query, $expectedQuery, $msg)
710+
{
711+
$request = new Request();
712+
713+
$request->server->set('QUERY_STRING', $query);
714+
$this->assertSame($expectedQuery, $request->getQueryStringForPhp(), $msg);
715+
}
716+
717+
public function getQueryStringNormalizationDataForPhp()
718+
{
719+
return array(
720+
array('foo', 'foo=', 'works with valueless parameters'),
721+
array('foo=', 'foo=', 'includes a dangling equal sign'),
722+
array('bar=&foo=bar', 'bar=&foo=bar', '->works with empty parameters'),
723+
array('foo=bar&bar=', 'bar=&foo=bar', 'sorts keys alphabetically'),
724+
725+
// GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded).
726+
// PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str.
727+
array('him=John%20Doe&her=Jane+Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes spaces in both encodings "%20" and "+"'),
728+
729+
array('foo[]=1&foo[]=2', 'foo%5B0%5D=1&foo%5B1%5D=2', 'allows array notation'),
730+
array('foo=1&foo=2', 'foo=2', 'merges repeated parameters'),
731+
array('pa%3Dram=foo%26bar%3Dbaz&test=test', 'pa%3Dram=foo%26bar%3Dbaz&test=test', 'works with encoded delimiters'),
732+
array('0', '0=', 'allows "0"'),
733+
array('Jane Doe&John%20Doe', 'Jane_Doe=&John_Doe=', 'normalizes encoding in keys'),
734+
array('her=Jane Doe&him=John%20Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes encoding in values'),
735+
array('foo=bar&&&test&&', 'foo=bar&test=', 'removes unneeded delimiters'),
736+
array('formula=e=m*c^2', 'formula=e%3Dm%2Ac%5E2', 'correctly treats only the first "=" as delimiter and the next as value'),
737+
738+
// Ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway.
739+
// PHP also does not include them when building _GET.
740+
array('foo=bar&=a=b&=x=y', 'foo=bar', 'removes params with empty key'),
741+
742+
// Don't reorder nested query string keys
743+
array('foo[]=Z&foo[]=A', 'foo%5B0%5D=Z&foo%5B1%5D=A', 'keeps order of values'),
744+
array('foo[Z]=B&foo[A]=B', 'foo%5BZ%5D=B&foo%5BA%5D=B', 'keeps order of keys'),
699745
);
700746
}
701747

0 commit comments

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