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

Skip to content

Commit 915a6c4

Browse files
[HttpFoundation] add HeaderUtils::parseQuery(): it does the same as parse_str() but preserves dots in variable names
1 parent 1b41bde commit 915a6c4

File tree

5 files changed

+85
-3
lines changed

5 files changed

+85
-3
lines changed

src/Symfony/Component/HttpFoundation/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.2.0
5+
-----
6+
7+
* added `HeaderUtils::parseQuery()`: it does the same as `parse_str()` but preserves dots in variable names
8+
49
5.1.0
510
-----
611

src/Symfony/Component/HttpFoundation/HeaderUtils.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,54 @@ public static function makeDisposition(string $disposition, string $filename, st
193193
return $disposition.'; '.self::toString($params, ';');
194194
}
195195

196+
/**
197+
* Like parse_str(), but preserves dots in variable names.
198+
*/
199+
public static function parseQuery(string $query, string $separator = '&'): array
200+
{
201+
$q = [];
202+
203+
foreach (explode($separator, $query) as $v) {
204+
if (false !== $i = strpos($v, "\0")) {
205+
$v = substr($v, 0, $i);
206+
}
207+
208+
if (false === $i = strpos($v, '=')) {
209+
$k = urldecode($v);
210+
$v = '';
211+
} else {
212+
$k = urldecode(substr($v, 0, $i));
213+
$v = substr($v, $i);
214+
}
215+
216+
if (false !== $i = strpos($k, "\0")) {
217+
$k = substr($k, 0, $i);
218+
}
219+
220+
$k = ltrim($k, ' ');
221+
222+
if (false === $i = strpos($k, '[')) {
223+
$q[] = bin2hex($k).$v;
224+
} else {
225+
$q[] = substr_replace($k, bin2hex(substr($k, 0, $i)), 0, $i).$v;
226+
}
227+
}
228+
229+
parse_str(implode('&', $q), $q);
230+
231+
$query = [];
232+
233+
foreach ($q as $k => $v) {
234+
if (false !== $i = strpos($k, '_')) {
235+
$query[substr_replace($k, hex2bin(substr($k, 0, $i)).'[', 0, 1 + $i)] = $v;
236+
} else {
237+
$query[hex2bin($k)] = $v;
238+
}
239+
}
240+
241+
return $query;
242+
}
243+
196244
private static function groupParts(array $matches, string $separators): array
197245
{
198246
$separator = $separators[0];

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ public static function create(string $uri, string $method = 'GET', array $parame
397397

398398
$queryString = '';
399399
if (isset($components['query'])) {
400-
parse_str(html_entity_decode($components['query']), $qs);
400+
$qs = HeaderUtils::parseQuery(html_entity_decode($components['query']));
401401

402402
if ($query) {
403403
$query = array_replace($qs, $query);
@@ -658,7 +658,7 @@ public static function normalizeQueryString(?string $qs)
658658
return '';
659659
}
660660

661-
parse_str($qs, $qs);
661+
$qs = HeaderUtils::parseQuery($qs);
662662
ksort($qs);
663663

664664
return http_build_query($qs, '', '&', PHP_QUERY_RFC3986);

src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,33 @@ public function provideMakeDispositionFail()
129129
['attachment', 'föö.html'],
130130
];
131131
}
132+
133+
/**
134+
* @dataProvider provideParseQuery
135+
*/
136+
public function testParseQuery(string $query, string $expected = null)
137+
{
138+
$this->assertSame($expected ?? $query, http_build_query(HeaderUtils::parseQuery($query), '', '&'));
139+
}
140+
141+
public function provideParseQuery()
142+
{
143+
return [
144+
['a=b&c=d'],
145+
['a.b=c'],
146+
['a+b=c'],
147+
["a\0b=c", 'a='],
148+
['a%00b=c', 'a=c'],
149+
['a[b=c', 'a%5Bb=c'],
150+
['a]b=c', 'a%5Db=c'],
151+
['a[b]=c', 'a%5Bb%5D=c'],
152+
['a[b][c.d]=c', 'a%5Bb%5D%5Bc.d%5D=c'],
153+
];
154+
}
155+
156+
public function testParseCookie()
157+
{
158+
$query = 'a.b=c; def%5Bg%5D=h';
159+
$this->assertSame($query, http_build_query(HeaderUtils::parseQuery($query, ';'), '', '; '));
160+
}
132161
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ public function getQueryStringNormalizationData()
805805
['foo=1&foo=2', 'foo=2', 'merges repeated parameters'],
806806
['pa%3Dram=foo%26bar%3Dbaz&test=test', 'pa%3Dram=foo%26bar%3Dbaz&test=test', 'works with encoded delimiters'],
807807
['0', '0=', 'allows "0"'],
808-
['Foo Bar&Foo%20Baz', 'Foo_Bar=&Foo_Baz=', 'normalizes encoding in keys'],
808+
['Foo Bar&Foo%20Baz', 'Foo%20Bar=&Foo%20Baz=', 'normalizes encoding in keys'],
809809
['bar=Foo Bar&baz=Foo%20Baz', 'bar=Foo%20Bar&baz=Foo%20Baz', 'normalizes encoding in values'],
810810
['foo=bar&&&test&&', 'foo=bar&test=', 'removes unneeded delimiters'],
811811
['formula=e=m*c^2', 'formula=e%3Dm%2Ac%5E2', 'correctly treats only the first "=" as delimiter and the next as value'],

0 commit comments

Comments
 (0)