Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b30f256

Browse files
[HttpFoundation] Add parse_str()-based methods for query strings normalization
1 parent b0facfe commit b30f256

File tree

2 files changed

+95
-2
lines changed

2 files changed

+95
-2
lines changed

src/Symfony/Component/HttpFoundation/Request.php

Lines 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

Lines 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)