diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 07ea4bd..e2836f8 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -6,7 +6,7 @@
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Timer;
use Drupal\Component\Utility\Unicode;
-use Drupal\Component\Utility\UrlValidator;
+use Drupal\Component\Utility\Url;
use Drupal\Core\DrupalKernel;
use Drupal\Core\Database\Database;
use Drupal\Core\DependencyInjection\ContainerBuilder;
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 54dc70c..fb0abac 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -4,7 +4,7 @@
use Drupal\Component\Utility\Json;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Tags;
-use Drupal\Component\Utility\UrlValidator;
+use Drupal\Component\Utility\Url;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Language\Language;
@@ -440,56 +440,14 @@ function drupal_get_feeds($delimiter = "\n") {
*
* @return
* An array containing query parameters, which can be used for url().
+ *
+ * @deprecated as of Drupal 8.0. Use Url::filterQueryParameters() instead.
*/
function drupal_get_query_parameters(array $query = NULL, array $exclude = array(), $parent = '') {
- // Set defaults, if none given.
if (!isset($query)) {
- $query = $_GET;
- }
- // If $exclude is empty, there is nothing to filter.
- if (empty($exclude)) {
- return $query;
- }
- elseif (!$parent) {
- $exclude = array_flip($exclude);
- }
-
- $params = array();
- foreach ($query as $key => $value) {
- $string_key = ($parent ? $parent . '[' . $key . ']' : $key);
- if (isset($exclude[$string_key])) {
- continue;
- }
-
- if (is_array($value)) {
- $params[$key] = drupal_get_query_parameters($value, $exclude, $string_key);
- }
- else {
- $params[$key] = $value;
- }
- }
-
- return $params;
-}
-
-/**
- * Splits a URL-encoded query string into an array.
- *
- * @param $query
- * The query string to split.
- *
- * @return
- * An array of URL decoded couples $param_name => $value.
- */
-function drupal_get_query_array($query) {
- $result = array();
- if (!empty($query)) {
- foreach (explode('&', $query) as $param) {
- $param = explode('=', $param);
- $result[$param[0]] = isset($param[1]) ? rawurldecode($param[1]) : '';
- }
+ $query = Drupal::request()->query->all();
}
- return $result;
+ return Url::filterQueryParameters($query, $exclude, $parent);
}
/**
@@ -497,12 +455,13 @@ function drupal_get_query_array($query) {
*
* @see \Drupal\Core\Routing\PathBasedGeneratorInterface::httpBuildQuery()
* @see drupal_get_query_parameters()
- * @deprecated as of Drupal 8.0. Use
- * Drupal::urlGenerator()->httpBuildQuery() instead.
+ * @deprecated as of Drupal 8.0. Use Url::buildQuery() instead.
* @ingroup php_wrappers
+ *
+ * @deprecated as of Drupal 8.0. Use Url::buildQuery() instead.
*/
function drupal_http_build_query(array $query, $parent = '') {
- return Drupal::urlGenerator()->httpBuildQuery($query, $parent);
+ return Url::buildQuery($query, $parent);
}
/**
@@ -527,12 +486,13 @@ function drupal_get_destination() {
return $destination;
}
- if (isset($_GET['destination'])) {
- $destination = array('destination' => $_GET['destination']);
+ $query = Drupal::request()->query;
+ if ($query->has('destination')) {
+ $destination = array('destination' => $query->get('destination'));
}
else {
$path = current_path();
- $query = Drupal::urlGenerator()->httpBuildQuery(drupal_get_query_parameters());
+ $query = Url::buildQuery(Url::filterQueryParameters($query->all()));
if ($query != '') {
$path .= '?' . $query;
}
@@ -573,46 +533,11 @@ function drupal_get_destination() {
*
* @see url()
* @ingroup php_wrappers
+ *
+ * @deprecated as of Drupal 8.0. Use Url::parse() instead.
*/
function drupal_parse_url($url) {
- $options = array(
- 'path' => NULL,
- 'query' => array(),
- 'fragment' => '',
- );
-
- // External URLs: not using parse_url() here, so we do not have to rebuild
- // the scheme, host, and path without having any use for it.
- if (strpos($url, '://') !== FALSE) {
- // Split off everything before the query string into 'path'.
- $parts = explode('?', $url);
- $options['path'] = $parts[0];
- // If there is a query string, transform it into keyed query parameters.
- if (isset($parts[1])) {
- $query_parts = explode('#', $parts[1]);
- parse_str($query_parts[0], $options['query']);
- // Take over the fragment, if there is any.
- if (isset($query_parts[1])) {
- $options['fragment'] = $query_parts[1];
- }
- }
- }
- // Internal URLs.
- else {
- // parse_url() does not support relative URLs, so make it absolute. E.g. the
- // relative URL "foo/bar:1" isn't properly parsed.
- $parts = parse_url('http://example.com/' . $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']);
- }
- if (isset($parts['fragment'])) {
- $options['fragment'] = $parts['fragment'];
- }
- }
-
- return $options;
+ return Url::parse($url);
}
/**
@@ -625,9 +550,11 @@ function drupal_parse_url($url) {
*
* @param $path
* The Drupal path to encode.
+ *
+ * @deprecated as of Drupal 8.0. Use Url::encodePath() instead.
*/
function drupal_encode_path($path) {
- return str_replace('%2F', '/', rawurlencode($path));
+ return Url::encodePath($path);
}
/**
@@ -638,20 +565,11 @@ function drupal_encode_path($path) {
*
* @return
* TRUE if the URL has the same domain and base path.
+ *
+ * @deprecated as of Drupal 8.0. Use Url::externalIsLocal() instead.
*/
function _external_url_is_local($url) {
- $url_parts = parse_url($url);
- $base_host = parse_url($GLOBALS['base_url'], PHP_URL_HOST);
-
- if (!isset($url_parts['path'])) {
- return ($url_parts['host'] == $base_host);
- }
- else {
- // When comparing base paths, we need a trailing slash to make sure a
- // partial URL match isn't occuring. Since base_path() always returns with
- // a trailing slash, we don't need to add the trailing slash here.
- return ($url_parts['host'] == $base_host && stripos($url_parts['path'], base_path()) === 0);
- }
+ return Url::externalIsLocal($url, base_path());
}
/**
@@ -705,12 +623,12 @@ function valid_email_address($mail) {
* @return
* TRUE if the URL is in a valid format.
*
- * @see \Drupal\Component\Utility\UrlValidator::isValid()
+ * @see \Drupal\Component\Utility\Url::isValid()
*
- * @deprecated as of Drupal 8.0. Use UrlValidator::isValid() instead.
+ * @deprecated as of Drupal 8.0. Use Url::isValid() instead.
*/
function valid_url($url, $absolute = FALSE) {
- return UrlValidator::isValid($url, $absolute);
+ return Url::isValid($url, $absolute);
}
/**
@@ -795,7 +713,7 @@ function valid_number_step($value, $step, $offset = 0.0) {
* @see \Drupal\Component\Utility\Url::stripDangerousProtocols()
*/
function drupal_strip_dangerous_protocols($uri) {
- return UrlValidator::stripDangerousProtocols($uri);
+ return Url::stripDangerousProtocols($uri);
}
/**
@@ -817,7 +735,7 @@ function drupal_strip_dangerous_protocols($uri) {
* @see \Drupal\Component\Utility\String::checkPlain()
*/
function check_url($uri) {
- return String::checkPlain(UrlValidator::stripDangerousProtocols($uri));
+ return String::checkPlain(Url::stripDangerousProtocols($uri));
}
/**
@@ -885,7 +803,7 @@ function filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite',
* @see \Drupal\Component\Utility\Url::filterBadProtocol()
*/
function filter_xss_bad_protocol($string) {
- return UrlValidator::filterBadProtocol($string);
+ return Url::filterBadProtocol($string);
}
/**
@@ -1313,11 +1231,7 @@ function url($path = NULL, array $options = array()) {
* Boolean TRUE or FALSE, where TRUE indicates an external path.
*/
function url_is_external($path) {
- $colonpos = strpos($path, ':');
- // Avoid calling drupal_strip_dangerous_protocols() if there is any
- // slash (/), hash (#) or question_mark (?) before the colon (:)
- // occurrence - if any - as this would clearly mean it is not a URL.
- return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path;
+ return Url::isExternal($path);
}
/**
@@ -4019,7 +3933,7 @@ function _drupal_bootstrap_code() {
// of allowed protocols for these cases.
$allowed_protocols = array('http', 'https');
}
- UrlValidator::setAllowedProtocols($allowed_protocols);
+ Url::setAllowedProtocols($allowed_protocols);
}
/**
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index a396619..7b46693 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -2215,27 +2215,6 @@ function template_preprocess_tablesort_indicator(&$variables) {
}
/**
- * Returns HTML for a marker for new or updated content.
- *
- * @param $variables
- * An associative array containing:
- * - type: Number representing the marker type to display. See MARK_NEW,
- * MARK_UPDATED, MARK_READ.
- */
-function theme_mark($variables) {
- $type = $variables['status'];
- global $user;
- if ($user->uid) {
- if ($type == MARK_NEW) {
- return ' ' . t('new') . '';
- }
- elseif ($type == MARK_UPDATED) {
- return ' ' . t('updated') . '';
- }
- }
-}
-
-/**
* Preprocesses variables for theme_item_list().
*
* @param array $variables
@@ -3114,6 +3093,7 @@ function drupal_common_theme() {
),
'mark' => array(
'variables' => array('status' => MARK_NEW),
+ 'template' => 'mark',
),
'item_list' => array(
'variables' => array('items' => array(), 'title' => '', 'list_type' => 'ul', 'attributes' => array()),
diff --git a/core/lib/Drupal/Component/Utility/Url.php b/core/lib/Drupal/Component/Utility/Url.php
new file mode 100644
index 0000000..cdc01c8
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/Url.php
@@ -0,0 +1,353 @@
+ $value) {
+ $key = ($parent ? $parent . '[' . rawurlencode($key) . ']' : rawurlencode($key));
+
+ // Recurse into children.
+ if (is_array($value)) {
+ $params[] = static::buildQuery($value, $key);
+ }
+ // If a query parameter value is NULL, only append its key.
+ elseif (!isset($value)) {
+ $params[] = $key;
+ }
+ else {
+ // For better readability of paths in query strings, we decode slashes.
+ $params[] = $key . '=' . str_replace('%2F', '/', rawurlencode($value));
+ }
+ }
+
+ return implode('&', $params);
+ }
+
+ /**
+ * Filters a URL query parameter array to remove unwanted elements.
+ *
+ * @param array $query
+ * An array to be processed.
+ * @param array $exclude
+ * (optional) A list of $query array keys to remove. Use "parent[child]" to
+ * exclude nested items.
+ * @param string $parent
+ * Internal use only. Used to build the $query array key for nested items.
+ *
+ * @return
+ * An array containing query parameters.
+ */
+ public static function filterQueryParameters(array $query, array $exclude = array(), $parent = '') {
+ // If $exclude is empty, there is nothing to filter.
+ if (empty($exclude)) {
+ return $query;
+ }
+ elseif (!$parent) {
+ $exclude = array_flip($exclude);
+ }
+
+ $params = array();
+ foreach ($query as $key => $value) {
+ $string_key = ($parent ? $parent . '[' . $key . ']' : $key);
+ if (isset($exclude[$string_key])) {
+ continue;
+ }
+
+ if (is_array($value)) {
+ $params[$key] = static::filterQueryParameters($value, $exclude, $string_key);
+ }
+ else {
+ $params[$key] = $value;
+ }
+ }
+
+ return $params;
+ }
+
+ /**
+ * Parses a system URL string into an associative array.
+ *
+ * This function should only be used for URLs that have been generated by the
+ * system. It should not be used for URLs that come from external sources, or
+ * URLs that link to external resources.
+ *
+ * The returned array contains a 'path' that may be passed separately to url().
+ * For example:
+ * @code
+ * $options = Url::parse($_GET['destination']);
+ * $my_url = url($options['path'], $options);
+ * $my_link = l('Example link', $options['path'], $options);
+ * @endcode
+ *
+ * @param string $url
+ * The URL string to parse, f.e. $_GET['destination'].
+ *
+ * @return
+ * An associative array containing the keys:
+ * - 'path': The path of the URL. If the given $url is external, this includes
+ * the scheme and host.
+ * - 'query': An array of query parameters of $url, if existent.
+ * - 'fragment': The fragment of $url, if existent.
+ *
+ * @ingroup php_wrappers
+ */
+ public static function parse($url) {
+ $options = array(
+ 'path' => NULL,
+ 'query' => array(),
+ 'fragment' => '',
+ );
+
+ // External URLs: not using parse_url() here, so we do not have to rebuild
+ // the scheme, host, and path without having any use for it.
+ if (strpos($url, '://') !== FALSE) {
+ // Split off everything before the query string into 'path'.
+ $parts = explode('?', $url);
+ $options['path'] = $parts[0];
+ // If there is a query string, transform it into keyed query parameters.
+ if (isset($parts[1])) {
+ $query_parts = explode('#', $parts[1]);
+ parse_str($query_parts[0], $options['query']);
+ // Take over the fragment, if there is any.
+ if (isset($query_parts[1])) {
+ $options['fragment'] = $query_parts[1];
+ }
+ }
+ }
+ // Internal URLs.
+ else {
+ // parse_url() does not support relative URLs, so make it absolute. E.g. the
+ // relative URL "foo/bar:1" isn't properly parsed.
+ $parts = parse_url('http://example.com/' . $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']);
+ }
+ if (isset($parts['fragment'])) {
+ $options['fragment'] = $parts['fragment'];
+ }
+ }
+
+ return $options;
+ }
+
+ /**
+ * Encodes a Drupal path for use in a URL.
+ *
+ * For aesthetic reasons slashes are not escaped.
+ *
+ * @param string $path
+ * The Drupal path to encode.
+ *
+ * @return string
+ * The encoded path.
+ */
+ public static function encodePath($path) {
+ return str_replace('%2F', '/', rawurlencode($path));
+ }
+
+ /**
+ * Returns whether a path is external to Drupal (e.g. http://example.com).
+ *
+ * If a path cannot be assessed by Drupal's menu handler, then we must
+ * treat it as potentially insecure.
+ *
+ * @param string $path
+ * The internal path or external URL being linked to, such as "node/34" or
+ * "http://example.com/foo".
+ *
+ * @return bool
+ * TRUE or FALSE, where TRUE indicates an external path.
+ */
+ public static function isExternal($path) {
+ $colonpos = strpos($path, ':');
+ // Avoid calling stripDangerousProtocols() if there is any
+ // slash (/), hash (#) or question_mark (?) before the colon (:)
+ // occurrence - if any - as this would clearly mean it is not a URL.
+ return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && static::stripDangerousProtocols($path) == $path;
+ }
+
+ /**
+ * Determines if an external URL points to this installation.
+ *
+ * @param string $url
+ * A string containing an external URL, such as "http://example.com/foo".
+ * @param string $base_url
+ * The base URL string to check against, such as "http://example.com/"
+ *
+ * @return
+ * TRUE if the URL has the same domain and base path.
+ */
+ public static function externalIsLocal($url, $base_url) {
+ $url_parts = parse_url($url);
+ $base_host = parse_url($base_url, PHP_URL_HOST);
+
+ if (!isset($url_parts['path'])) {
+ return ($url_parts['host'] == $base_host);
+ }
+ else {
+ // When comparing base paths, we need a trailing slash to make sure a
+ // partial URL match isn't occuring. Since base_path() always returns with
+ // a trailing slash, we don't need to add the trailing slash here.
+ return ($url_parts['host'] == $base_host && stripos($url_parts['path'], $base_url) === 0);
+ }
+ }
+
+ /**
+ * Processes an HTML attribute value and strips dangerous protocols from URLs.
+ *
+ * @param string $string
+ * The string with the attribute value.
+ *
+ * @return string
+ * Cleaned up and HTML-escaped version of $string.
+ */
+ public static function filterBadProtocol($string) {
+ // Get the plain text representation of the attribute value (i.e. its
+ // meaning).
+ $string = String::decodeEntities($string);
+ return String::checkPlain(static::stripDangerousProtocols($string));
+ }
+
+ /**
+ * Sets the allowed protocols.
+ *
+ * @param array $protocols
+ * An array of protocols, for example http, https and irc.
+ */
+ public static function setAllowedProtocols(array $protocols = array()) {
+ static::$allowedProtocols = $protocols;
+ }
+
+ /**
+ * Strips dangerous protocols (e.g. 'javascript:') from a URI.
+ *
+ * This function must be called for all URIs within user-entered input prior
+ * to being output to an HTML attribute value. It is often called as part of
+ * check_url() or Drupal\Component\Utility\Xss::filter(), but those functions
+ * return an HTML-encoded string, so this function can be called independently
+ * when the output needs to be a plain-text string for passing to t(), l(),
+ * Drupal\Core\Template\Attribute, or another function that will call
+ * \Drupal\Component\Utility\String::checkPlain() separately.
+ *
+ * @param string $uri
+ * A plain-text URI that might contain dangerous protocols.
+ *
+ * @return string
+ * A plain-text URI stripped of dangerous protocols. As with all plain-text
+ * strings, this return value must not be output to an HTML page without
+ * being sanitized first. However, it can be passed to functions
+ * expecting plain-text strings.
+ */
+ public static function stripDangerousProtocols($uri) {
+ $allowed_protocols = array_flip(static::$allowedProtocols);
+
+ // Iteratively remove any invalid protocol found.
+ do {
+ $before = $uri;
+ $colonpos = strpos($uri, ':');
+ if ($colonpos > 0) {
+ // We found a colon, possibly a protocol. Verify.
+ $protocol = substr($uri, 0, $colonpos);
+ // If a colon is preceded by a slash, question mark or hash, it cannot
+ // possibly be part of the URL scheme. This must be a relative URL, which
+ // inherits the (safe) protocol of the base document.
+ if (preg_match('![/?#]!', $protocol)) {
+ break;
+ }
+ // Check if this is a disallowed protocol. Per RFC2616, section 3.2.3
+ // (URI Comparison) scheme comparison must be case-insensitive.
+ if (!isset($allowed_protocols[strtolower($protocol)])) {
+ $uri = substr($uri, $colonpos + 1);
+ }
+ }
+ } while ($before != $uri);
+
+ return $uri;
+ }
+
+ /**
+ * Verifies the syntax of the given URL.
+ *
+ * This function should only be used on actual URLs. It should not be used for
+ * Drupal menu paths, which can contain arbitrary characters.
+ * Valid values per RFC 3986.
+ *
+ * @param string $url
+ * The URL to verify.
+ * @param bool $absolute
+ * Whether the URL is absolute (beginning with a scheme such as "http:").
+ *
+ * @return bool
+ * TRUE if the URL is in a valid format, FALSE otherwise.
+ */
+ public static function isValid($url, $absolute = FALSE) {
+ if ($absolute) {
+ return (bool) preg_match("
+ /^ # Start at the beginning of the text
+ (?:ftp|https?|feed):\/\/ # Look for ftp, http, https or feed schemes
+ (?: # Userinfo (optional) which is typically
+ (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)* # a username or a username and password
+ (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@ # combination
+ )?
+ (?:
+ (?:[a-z0-9\-\.]|%[0-9a-f]{2})+ # A domain name or a IPv4 address
+ |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\]) # or a well formed IPv6 address
+ )
+ (?::[0-9]+)? # Server port number (optional)
+ (?:[\/|\?]
+ (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
+ *)?
+ $/xi", $url);
+ }
+ else {
+ return (bool) preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url);
+ }
+ }
+
+}
diff --git a/core/lib/Drupal/Component/Utility/UrlValidator.php b/core/lib/Drupal/Component/Utility/UrlValidator.php
deleted file mode 100644
index 4772373..0000000
--- a/core/lib/Drupal/Component/Utility/UrlValidator.php
+++ /dev/null
@@ -1,136 +0,0 @@
- 0) {
- // We found a colon, possibly a protocol. Verify.
- $protocol = substr($uri, 0, $colonpos);
- // If a colon is preceded by a slash, question mark or hash, it cannot
- // possibly be part of the URL scheme. This must be a relative URL, which
- // inherits the (safe) protocol of the base document.
- if (preg_match('![/?#]!', $protocol)) {
- break;
- }
- // Check if this is a disallowed protocol. Per RFC2616, section 3.2.3
- // (URI Comparison) scheme comparison must be case-insensitive.
- if (!isset($allowed_protocols[strtolower($protocol)])) {
- $uri = substr($uri, $colonpos + 1);
- }
- }
- } while ($before != $uri);
-
- return $uri;
- }
-
- /**
- * Verifies the syntax of the given URL.
- *
- * This function should only be used on actual URLs. It should not be used for
- * Drupal menu paths, which can contain arbitrary characters.
- * Valid values per RFC 3986.
- *
- * @param string $url
- * The URL to verify.
- * @param bool $absolute
- * Whether the URL is absolute (beginning with a scheme such as "http:").
- *
- * @return bool
- * TRUE if the URL is in a valid format.
- */
- public static function isValid($url, $absolute = FALSE) {
- if ($absolute) {
- return (bool) preg_match("
- /^ # Start at the beginning of the text
- (?:ftp|https?|feed):\/\/ # Look for ftp, http, https or feed schemes
- (?: # Userinfo (optional) which is typically
- (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)* # a username or a username and password
- (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@ # combination
- )?
- (?:
- (?:[a-z0-9\-\.]|%[0-9a-f]{2})+ # A domain name or a IPv4 address
- |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\]) # or a well formed IPv6 address
- )
- (?::[0-9]+)? # Server port number (optional)
- (?:[\/|\?]
- (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
- *)?
- $/xi", $url);
- }
- else {
- return (bool) preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url);
- }
- }
-
-}
diff --git a/core/lib/Drupal/Component/Utility/Xss.php b/core/lib/Drupal/Component/Utility/Xss.php
index a1f1956..8d0d257 100644
--- a/core/lib/Drupal/Component/Utility/Xss.php
+++ b/core/lib/Drupal/Component/Utility/Xss.php
@@ -225,7 +225,7 @@ protected static function attributes($attributes) {
case 2:
// Attribute value, a URL after href= for instance.
if (preg_match('/^"([^"]*)"(\s+|$)/', $attributes, $match)) {
- $thisval = UrlValidator::filterBadProtocol($match[1]);
+ $thisval = Url::filterBadProtocol($match[1]);
if (!$skip) {
$attributes_array[] = "$attribute_name=\"$thisval\"";
@@ -237,7 +237,7 @@ protected static function attributes($attributes) {
}
if (preg_match("/^'([^']*)'(\s+|$)/", $attributes, $match)) {
- $thisval = UrlValidator::filterBadProtocol($match[1]);
+ $thisval = Url::filterBadProtocol($match[1]);
if (!$skip) {
$attributes_array[] = "$attribute_name='$thisval'";
@@ -248,7 +248,7 @@ protected static function attributes($attributes) {
}
if (preg_match("%^([^\s\"']+)(\s+|$)%", $attributes, $match)) {
- $thisval = UrlValidator::filterBadProtocol($match[1]);
+ $thisval = Url::filterBadProtocol($match[1]);
if (!$skip) {
$attributes_array[] = "$attribute_name=\"$thisval\"";
diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php
index 04c2c17..972058a 100644
--- a/core/lib/Drupal/Core/Routing/UrlGenerator.php
+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -16,7 +16,7 @@
use Symfony\Cmf\Component\Routing\ProviderBasedGenerator;
use Drupal\Component\Utility\Settings;
-use Drupal\Component\Utility\UrlValidator;
+use Drupal\Component\Utility\Url;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
@@ -83,7 +83,7 @@ public function __construct(RouteProviderInterface $provider, OutboundPathProces
$this->pathProcessor = $path_processor;
$this->mixedModeSessions = $settings->get('mixed_mode_sessions', FALSE);
$allowed_protocols = $config->get('system.filter')->get('protocols') ?: array('http', 'https');
- UrlValidator::setAllowedProtocols($allowed_protocols);
+ Url::setAllowedProtocols($allowed_protocols);
}
/**
@@ -112,7 +112,7 @@ public function generate($name, $parameters = array(), $absolute = FALSE) {
if ($name instanceof SymfonyRoute) {
$route = $name;
}
- elseif (null === $route = $this->provider->getRouteByName($name, $parameters)) {
+ elseif (NULL === $route = $this->provider->getRouteByName($name, $parameters)) {
throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name));
}
@@ -239,7 +239,7 @@ public function generateFromPath($path = NULL, $options = array()) {
// that would require another function call, and performance inside url() is
// critical.
$colonpos = strpos($path, ':');
- $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && UrlValidator::stripDangerousProtocols($path) == $path);
+ $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && Url::stripDangerousProtocols($path) == $path);
}
if (isset($options['fragment']) && $options['fragment'] !== '') {
@@ -257,7 +257,7 @@ public function generateFromPath($path = NULL, $options = array()) {
}
// Append the query.
if ($options['query']) {
- $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . $this->httpBuildQuery($options['query']);
+ $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . Url::buildQuery($options['query']);
}
if (isset($options['https']) && $this->mixedModeSessions) {
if ($options['https'] === TRUE) {
@@ -300,7 +300,7 @@ public function generateFromPath($path = NULL, $options = array()) {
$prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix'];
$path = str_replace('%2F', '/', rawurlencode($prefix . $path));
- $query = $options['query'] ? ('?' . $this->httpBuildQuery($options['query'])) : '';
+ $query = $options['query'] ? ('?' . Url::buildQuery($options['query'])) : '';
return $base . $options['script'] . $path . $query . $options['fragment'];
}
@@ -326,47 +326,6 @@ public function setScriptPath($path) {
}
/**
- * Parses an array into a valid, rawurlencoded query string.
- *
- * This differs from http_build_query() as we need to rawurlencode() (instead of
- * urlencode()) all query parameters.
- *
- * @param $query
- * The query parameter array to be processed, e.g. $_GET.
- * @param $parent
- * Internal use only. Used to build the $query array key for nested items.
- *
- * @return
- * A rawurlencoded string which can be used as or appended to the URL query
- * string.
- *
- * @see drupal_get_query_parameters()
- * @ingroup php_wrappers
- */
- public function httpBuildQuery(array $query, $parent = '') {
- $params = array();
-
- foreach ($query as $key => $value) {
- $key = ($parent ? $parent . '[' . rawurlencode($key) . ']' : rawurlencode($key));
-
- // Recurse into children.
- if (is_array($value)) {
- $params[] = $this->httpBuildQuery($value, $key);
- }
- // If a query parameter value is NULL, only append its key.
- elseif (!isset($value)) {
- $params[] = $key;
- }
- else {
- // For better readability of paths in query strings, we decode slashes.
- $params[] = $key . '=' . str_replace('%2F', '/', rawurlencode($value));
- }
- }
-
- return implode('&', $params);
- }
-
- /**
* Passes the path to a processor manager to allow alterations.
*/
protected function processPath($path, &$options = array()) {
diff --git a/core/modules/contextual/contextual.module b/core/modules/contextual/contextual.module
index 75e3ed2..9280a7b 100644
--- a/core/modules/contextual/contextual.module
+++ b/core/modules/contextual/contextual.module
@@ -347,7 +347,8 @@ function _contextual_id_to_links($id) {
foreach ($contexts as $context) {
list($module, $parent_path, $path_args, $metadata_raw) = explode(':', $context);
$path_args = explode('/', $path_args);
- $metadata = drupal_get_query_array($metadata_raw);
+ $metadata = array();
+ parse_str($metadata_raw, $metadata);
$contextual_links[$module] = array($parent_path, $path_args, $metadata);
}
return $contextual_links;
diff --git a/core/modules/language/language.negotiation.inc b/core/modules/language/language.negotiation.inc
index 126ec5a..c4e97b3 100644
--- a/core/modules/language/language.negotiation.inc
+++ b/core/modules/language/language.negotiation.inc
@@ -500,7 +500,9 @@ function language_url_rewrite_session(&$path, &$options) {
// user language preference even with cookies disabled.
if ($query_rewrite) {
if (is_string($options['query'])) {
- $options['query'] = drupal_get_query_array($options['query']);
+ $query = array();
+ parse_str($options['query'], $query);
+ $options['query'] = $query;
}
if (!isset($options['query'][$query_param])) {
$options['query'][$query_param] = $query_value;
diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php
index 6064108..8eb4458 100644
--- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php
+++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php
@@ -227,7 +227,8 @@ public function validate(array $form, array &$form_state) {
if (!url_is_external($menu_link->link_path)) {
$parsed_link = parse_url($menu_link->link_path);
if (isset($parsed_link['query'])) {
- $menu_link->options['query'] = drupal_get_query_array($parsed_link['query']);
+ $menu_link->options['query'] = array();
+ parse_str($parsed_link['query'], $menu_link->options['query']);
}
else {
// Use unset() rather than setting to empty string
diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/UrlTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/UrlTest.php
index b6e1ae7..249afd4 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Common/UrlTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/UrlTest.php
@@ -197,16 +197,6 @@ function testDrupalGetQueryParameters() {
}
/**
- * Tests drupal_http_build_query().
- */
- function testDrupalHttpBuildQuery() {
- $this->assertEqual(drupal_http_build_query(array('a' => ' //+%20@۞')), 'a=%20%26%23//%2B%2520%40%DB%9E', 'Value was properly encoded.');
- $this->assertEqual(drupal_http_build_query(array(' //+%20@۞' => 'a')), '%20%26%23%2F%2F%2B%2520%40%DB%9E=a', 'Key was properly encoded.');
- $this->assertEqual(drupal_http_build_query(array('a' => '1', 'b' => '2', 'c' => '3')), 'a=1&b=2&c=3', 'Multiple values were properly concatenated.');
- $this->assertEqual(drupal_http_build_query(array('a' => array('b' => '2', 'c' => '3'), 'd' => 'foo')), 'a[b]=2&a[c]=3&d=foo', 'Nested array was properly encoded.');
- }
-
- /**
* Tests drupal_parse_url().
*/
function testDrupalParseUrl() {
diff --git a/core/modules/system/templates/mark.html.twig b/core/modules/system/templates/mark.html.twig
new file mode 100644
index 0000000..2798bb0
--- /dev/null
+++ b/core/modules/system/templates/mark.html.twig
@@ -0,0 +1,22 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a marker for new or updated content.
+ *
+ * Available variables:
+ * - status: Number representing the marker status to display. Use the constants
+ * below for comparison:
+ * - MARK_NEW
+ * - MARK_UPDATED
+ * - MARK_READ
+ *
+ * @ingroup themeable
+ */
+#}
+{% if logged_in %}
+ {% if status is constant('MARK_NEW') %}
+ {{ 'new'|t }}
+ {% elseif status is constant('MARK_UPDATED') %}
+ {{ 'updated'|t }}
+ {% endif %}
+{% endif %}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
index b07d763..ac95d5b 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
@@ -9,7 +9,7 @@
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
-use Drupal\Component\Utility\UrlValidator;
+use Drupal\Component\Utility\Url;
use Drupal\Component\Utility\Xss;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Plugin\views\PluginBase;
@@ -221,7 +221,7 @@ public function sanitizeValue($value, $type = NULL) {
$value = Xss::filterAdmin($value);
break;
case 'url':
- $value = String::checkPlain(UrlValidator::stripDangerousProtocols($value));
+ $value = String::checkPlain(Url::stripDangerousProtocols($value));
break;
default:
$value = String::checkPlain($value);
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
index 386eda0..fda023a 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
@@ -1365,7 +1365,8 @@ protected function renderAsLink($alter, $text, $tokens) {
if (isset($url['query'])) {
$path = strtr($path, array('?' . $url['query'] => ''));
- $query = drupal_get_query_array($url['query']);
+ $query = array();
+ parse_str($url['query'], $query);
// Remove query parameters that were assigned a query string replacement
// token for which there is no value available.
foreach ($query as $param => $val) {
@@ -1421,7 +1422,9 @@ protected function renderAsLink($alter, $text, $tokens) {
// convert back to an array form for l().
$options['query'] = drupal_http_build_query($alter['query']);
$options['query'] = strtr($options['query'], $tokens);
- $options['query'] = drupal_get_query_array($options['query']);
+ $query = array();
+ parse_str($options['query'], $query);
+ $options['query'] = $query;
}
if (isset($alter['alias'])) {
// Alias is a boolean field, so no token.
diff --git a/core/tests/Drupal/Tests/Core/Common/UrlValidatorTest.php b/core/tests/Drupal/Tests/Component/Utility/UrlTest.php
similarity index 70%
rename from core/tests/Drupal/Tests/Core/Common/UrlValidatorTest.php
rename to core/tests/Drupal/Tests/Component/Utility/UrlTest.php
index 105d716..769a10d 100644
--- a/core/tests/Drupal/Tests/Core/Common/UrlValidatorTest.php
+++ b/core/tests/Drupal/Tests/Component/Utility/UrlTest.php
@@ -2,30 +2,63 @@
/**
* @file
- * Contains \Drupal\Tests\Core\Common\UrlValidatorTest.
+ * Contains \Drupal\Tests\Component\Utility\UrlTest.
*/
-namespace Drupal\Tests\Core\Common;
+namespace Drupal\Tests\Component\Utility;
+
+use Drupal\Component\Utility\Url;
use Drupal\Component\Utility\String;
-use Drupal\Component\Utility\UrlValidator;
use Drupal\Tests\UnitTestCase;
/**
- * Tests URL validation by valid_url().
+ * Tests the http query methods.
+ *
+ * @see \Drupal\Component\Utility\Url
*/
-class UrlValidatorTest extends UnitTestCase {
+class UrlTest extends UnitTestCase {
public static function getInfo() {
return array(
- 'name' => 'URL validation',
- 'description' => 'Tests URL validation by valid_url()',
- 'group' => 'Common',
+ 'name' => t('Url Tests'),
+ 'description' => t('Tests the Url utility class.'),
+ 'group' => t('Path API'),
+ );
+ }
+
+ /**
+ * Provides test data for testBuildQuery().
+ *
+ * @return array
+ */
+ public function providerTestBuildQuery() {
+ return array(
+ array(array('a' => ' //+%20@۞'), 'a=%20%26%23//%2B%2520%40%DB%9E', 'Value was properly encoded.'),
+ array(array(' //+%20@۞' => 'a'), '%20%26%23%2F%2F%2B%2520%40%DB%9E=a', 'Key was properly encoded.'),
+ array(array('a' => '1', 'b' => '2', 'c' => '3'), 'a=1&b=2&c=3', 'Multiple values were properly concatenated.'),
+ array(array('a' => array('b' => '2', 'c' => '3'), 'd' => 'foo'), 'a[b]=2&a[c]=3&d=foo', 'Nested array was properly encoded.'),
);
}
/**
- * Data provider for absolute URLs.
+ * Tests Url::buildQuery().
+ *
+ * @param array $query
+ * The array of query parameters.
+ * @param string $expected
+ * The expected query string.
+ * @param string $message
+ * The assertion message.
+ *
+ * @dataProvider providerTestBuildQuery
+ */
+ public function testBuildQuery($query, $expected, $message) {
+ $this->assertEquals(Url::buildQuery($query), $expected, $message);
+ }
+
+ /**
+ * Data provider for testValidAbsolute().
*/
public function providerTestValidAbsoluteData() {
$urls = array(
@@ -64,12 +97,12 @@ public function providerTestValidAbsoluteData() {
*/
public function testValidAbsolute($url, $scheme) {
$test_url = $scheme . '://' . $url;
- $valid_url = UrlValidator::isValid($test_url, TRUE);
+ $valid_url = Url::isValid($test_url, TRUE);
$this->assertTrue($valid_url, String::format('@url is a valid URL.', array('@url' => $test_url)));
}
/**
- * Provides invalid absolute URLs.
+ * Provides data for testInvalidAbsolute().
*/
public function providerTestInvalidAbsolute() {
$data = array(
@@ -92,12 +125,12 @@ public function providerTestInvalidAbsolute() {
*/
public function testInvalidAbsolute($url, $scheme) {
$test_url = $scheme . '://' . $url;
- $valid_url = UrlValidator::isValid($test_url, TRUE);
+ $valid_url = Url::isValid($test_url, TRUE);
$this->assertFalse($valid_url, String::format('@url is NOT a valid URL.', array('@url' => $test_url)));
}
/**
- * Provides valid relative URLs
+ * Provides data for testValidRelative().
*/
public function providerTestValidRelativeData() {
$data = array(
@@ -123,12 +156,12 @@ public function providerTestValidRelativeData() {
*/
public function testValidRelative($url, $prefix) {
$test_url = $prefix . $url;
- $valid_url = Urlvalidator::isValid($test_url);
+ $valid_url = Url::isValid($test_url);
$this->assertTrue($valid_url, String::format('@url is a valid URL.', array('@url' => $test_url)));
}
/**
- * Provides invalid relative URLs.
+ * Provides data for testInvalidRelative().
*/
public function providerTestInvalidRelativeData() {
$data = array(
@@ -151,7 +184,7 @@ public function providerTestInvalidRelativeData() {
*/
public function testInvalidRelative($url, $prefix) {
$test_url = $prefix . $url;
- $valid_url = UrlValidator::isValid($test_url);
+ $valid_url = Url::isValid($test_url);
$this->assertFalse($valid_url, String::format('@url is NOT a valid URL.', array('@url' => $test_url)));
}
@@ -195,5 +228,4 @@ protected function dataEnhanceWithPrefix(array $urls) {
return $data;
}
-
}
diff --git a/core/tests/Drupal/Tests/Component/Utility/XssTest.php b/core/tests/Drupal/Tests/Component/Utility/XssTest.php
index e87cd79..2614c5d 100644
--- a/core/tests/Drupal/Tests/Component/Utility/XssTest.php
+++ b/core/tests/Drupal/Tests/Component/Utility/XssTest.php
@@ -8,7 +8,7 @@
namespace Drupal\Tests\Component\Utility;
use Drupal\Component\Utility\String;
-use Drupal\Component\Utility\UrlValidator;
+use Drupal\Component\Utility\Url;
use Drupal\Component\Utility\Xss;
use Drupal\Tests\UnitTestCase;
@@ -53,7 +53,7 @@ protected function setUp() {
'webcal',
'rtsp',
);
- UrlValidator::setAllowedProtocols($allowed_protocols);
+ Url::setAllowedProtocols($allowed_protocols);
}
/**