diff --git a/core/lib/Drupal/Component/Utility/UrlHelper.php b/core/lib/Drupal/Component/Utility/UrlHelper.php index 77bac32bdb..6782d6bce4 100644 --- a/core/lib/Drupal/Component/Utility/UrlHelper.php +++ b/core/lib/Drupal/Component/Utility/UrlHelper.php @@ -174,7 +174,7 @@ public static function parse($url) { // Strip the leading slash that was just added. $options['path'] = substr($parts['path'], 1); if (isset($parts['query'])) { - parse_str($parts['query'], $options['query']); + $options['query'] = static::parseQueryString($parts['query']); } if (isset($parts['fragment'])) { $options['fragment'] = $parts['fragment']; @@ -185,30 +185,36 @@ public static function parse($url) { } /** - * Convert an url query string to an array. + * A wrapper for parse_str() that restores original parameter names. * - * The parse_str method contains an issue with query parameter names - * containing a dot. Having a dot in a query parameter name is valid, so - * we hex encode the parameter names to work around this. + * The parse_str() function can be used to set variables in the current scope, + * 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. * - * @param string $query_string - * The url parameters as a string. + * @param string $query + * A query string to parse. * * @return array - * The url parameters as an array. - * - * @see https://www.drupal.org/project/drupal/issues/2984272 + * The result of parse_str() with original parameter names restored. */ - public static function parseQueryString($query_string = '') { - $query_options = []; - if ($query_string) { - $encoded_string = preg_replace_callback('/(?:^|(?<=&))[^=[]+/', function ($match) { - return bin2hex(urldecode($match[0])); - }, $query_string); - parse_str($encoded_string, $query_array); - $query_options = array_combine(array_map('hex2bin', array_keys($query_array)), $query_array); + public static function parseQueryString($query) { + // Create an array to map parsed parameter names to original names. + $names = []; + foreach (explode('&', $query) as $param) { + list($name) = explode('=', $param, 2); + 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]); } - return $query_options; + return $query; } /**