diff --git a/core/lib/Drupal/Component/Utility/UrlHelper.php b/core/lib/Drupal/Component/Utility/UrlHelper.php index e8194c44f7..a9a4a68fa4 100644 --- a/core/lib/Drupal/Component/Utility/UrlHelper.php +++ b/core/lib/Drupal/Component/Utility/UrlHelper.php @@ -188,7 +188,7 @@ public static function parse($url) { * although this is deprecated. Because variables in PHP cannot have periods * and spaces in their names, parse_str() converts them to underscores. This * breaks external links and front end libraries that require specific - * parameter names. + * parameter names. It can also cause name collisions. * * @param string $query * A query string to parse. @@ -197,22 +197,22 @@ public static function parse($url) { * The result of parse_str() with original parameter names restored. */ public static function parseQueryString($query) { - // Create an array to map parsed parameter names to original names. - $names = []; + // Create an array to map parsed parameters to original names. + $parsed = []; foreach (explode('&', $query) as $param) { list($name) = explode('=', $param, 2); $name = strstr($name, '[', true) ?: $name; - parse_str($name, $parsed); - $names[key($parsed)] = $name; - } - // Parse the query string. - parse_str($query, $query); - // Replaced changed parameter names with original names. - foreach (array_diff($names, array_keys($query)) as $parsed => $name) { - $query[$name] = $query[$parsed]; - unset($query[$parsed]); + // Parse the query parameter. + parse_str($param, $param); + // Merge the parameter into the parsed array. + if (isset($parsed[$name])) { + $parsed[$name] = array_merge($parsed[$name], reset($param)); + } + else { + $parsed[$name] = reset($param); + } } - return $query; + return $parsed; } /** diff --git a/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php b/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php index 572c7dc48a..c446eeec93 100644 --- a/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php +++ b/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php @@ -269,26 +269,25 @@ public static function providerTestParse() { 'fragment' => 'footer', ], ], - [ - 'http://www.example.com/my/path?my.destination=my.home&my destination=my home&my_destination[]=my.home&my_destination[]=my_home&my_destination[]=home', + 'query parameters with characters not allowed in PHP variable names' => [ + 'http://www.example.com/my/path?single.value=&single value=&single_value=&multi.value[first]=&multi.value[second]=&multi value[third]=&multi value[fourth]=&multi_value[fifth]=&multi_value[sixth]=', [ 'path' => 'http://www.example.com/my/path', 'query' => [ - 'my_destination' => ['my.home', 'my_home', 'home'], - ], - 'fragment' => '', - ], - ], - [ - 'http://www.example.com/my/path?param[nested][0]=value¶m[nested][1]=2ndvalue', - [ - 'path' => 'http://www.example.com/my/path', - 'query' => [ - 'param' => [ - 'nested' => [ - 0 => 'value', - 1 => '2ndvalue', - ], + 'single.value' => '', + 'single value' => '', + 'single_value' => '', + 'multi.value' => [ + 'first' => '', + 'second' => '', + ], + 'multi value' => [ + 'third' => '', + 'fourth' => '', + ], + 'multi_value' => [ + 'fifth' => '', + 'sixth' => '', ], ], 'fragment' => '', diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php index 99603fffce..2e8442ab0e 100644 --- a/core/tests/Drupal/Tests/Core/UrlTest.php +++ b/core/tests/Drupal/Tests/Core/UrlTest.php @@ -339,8 +339,8 @@ public function testGetUriForExternalUrl() { * @covers ::getUri */ public function testGetUriForExternalUrlWithParameters() { - $url = Url::fromUri('http://www.example.com/my/path?my.destination=my.home&my destination=my home&my_destination[]=my.home&my_destination[]=my_home&my_destination[]=home'); - $this->assertEquals('http://www.example.com/my/path?my.destination=my.home&my destination=my home&my_destination[]=my.home&my_destination[]=my_home&my_destination[]=home', $url->getUri()); + $url = Url::fromUri('http://www.example.com/my/path?single.value=&single value=&single_value=&multi.value[first]=&multi.value[second]=&multi value[third]=&multi value[fourth]=&multi_value[fifth]=&multi_value[sixth]='); + $this->assertEquals('http://www.example.com/my/path?single.value=&single value=&single_value=&multi.value[first]=&multi.value[second]=&multi value[third]=&multi value[fourth]=&multi_value[fifth]=&multi_value[sixth]=', $url->getUri()); } /**