From 631060fb3988be00616d7ccbb1abf38f87c4b723 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Wed, 4 Dec 2024 14:45:36 +0100 Subject: [PATCH] Fix QueryString php variable extraction #146 --- QueryString.php | 20 ++++++++++++-------- QueryStringTest.php | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/QueryString.php b/QueryString.php index a887668..b350867 100644 --- a/QueryString.php +++ b/QueryString.php @@ -249,23 +249,27 @@ private static function extractPhpVariable(array $data, array|string $name, stri } $key = substr($name, 0, $leftBracketPosition); + if ('' === $key) { + $key = '0'; + } + if (!array_key_exists($key, $data) || !is_array($data[$key])) { $data[$key] = []; } - $index = substr($name, $leftBracketPosition + 1, $rightBracketPosition - $leftBracketPosition - 1); - if ('' === $index) { + $remaining = substr($name, $rightBracketPosition + 1); + if (!str_starts_with($remaining, '[') || !str_contains($remaining, ']')) { + $remaining = ''; + } + + $name = substr($name, $leftBracketPosition + 1, $rightBracketPosition - $leftBracketPosition - 1).$remaining; + if ('' === $name) { $data[$key][] = $value; return $data; } - $remaining = substr($name, $rightBracketPosition + 1); - if (!str_starts_with($remaining, '[') || false === strpos($remaining, ']', 1)) { - $remaining = ''; - } - - $data[$key] = self::extractPhpVariable($data[$key], $index.$remaining, $value); + $data[$key] = self::extractPhpVariable($data[$key], $name, $value); return $data; } diff --git a/QueryStringTest.php b/QueryStringTest.php index 504ec46..bb54c4a 100644 --- a/QueryStringTest.php +++ b/QueryStringTest.php @@ -15,6 +15,7 @@ use League\Uri\Components\Fragment; use League\Uri\Exceptions\SyntaxError; use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use Stringable; @@ -477,4 +478,43 @@ public static function queryProvider(): array 'Encoded unreserved chars are not decoded' => ['q=v%61lue', 'q=value'], ]; } + + #[Test] + #[DataProvider('queryWithInnerEmptyBracetsProvider')] + public function it_should_parse_empty_bracets_issue_146(string $query, string $expected): void + { + $data = QueryString::extract($query); + parse_str($query, $result); + + self::assertSame($data, $result); + self::assertSame($expected, http_build_query($data, '', '&', PHP_QUERY_RFC3986)); + } + + public static function queryWithInnerEmptyBracetsProvider(): iterable + { + yield 'query with on level empty bracets' => [ + 'query' => 'foo[]=bar', + 'expected' => 'foo%5B0%5D=bar', + ]; + + yield 'query with two level bracets' => [ + 'query' => 'key[][][foo][9]=bar', + 'expected' => 'key%5B0%5D%5B0%5D%5Bfoo%5D%5B9%5D=bar', + ]; + + yield 'query with invalid remaining; close bracet without an opening bracet' => [ + 'query' => 'key[][]foo][9]=bar', + 'expected' => 'key%5B0%5D%5B0%5D=bar', + ]; + + yield 'query with invalid remaining; no opening bracet' => [ + 'query' => 'key[]9=bar', + 'expected' => 'key%5B0%5D=bar', + ]; + + yield 'query with invalid remaining; opening bracet no at the start of the remaining string' => [ + 'query' => 'key[]9[]=bar', + 'expected' => 'key%5B0%5D=bar', + ]; + } }