Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663

This commit is contained in:
Greg Anderson 2015-10-08 11:40:12 -07:00
parent eb34d130a8
commit f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions

View file

@ -78,12 +78,24 @@ class Html {
public static function cleanCssIdentifier($identifier, array $filter = array(
' ' => '-',
'_' => '-',
'__' => '__',
'/' => '-',
'[' => '-',
']' => ''
']' => '',
)) {
$identifier = strtr($identifier, $filter);
// We could also use strtr() here but its much slower than str_replace(). In
// order to keep '__' to stay '__' we first replace it with a different
// placeholder after checking that it is not defined as a filter.
$double_underscore_replacements = 0;
if (!isset($filter['__'])) {
$identifier = str_replace('__', '##', $identifier, $double_underscore_replacements);
}
$identifier = str_replace(array_keys($filter), array_values($filter), $identifier);
// Replace temporary placeholder '##' with '__' only if the original
// $identifier contained '__'.
if ($double_underscore_replacements > 0) {
$identifier = str_replace('##', '__', $identifier);
}
// Valid characters in a CSS identifier are:
// - the hyphen (U+002D)
// - a-z (U+0030 - U+0039)
@ -250,9 +262,9 @@ class Html {
<body>!html</body>
</html>
EOD;
// PHP's \DOMDocument serialization adds straw whitespace in case the markup
// of the wrapping document contains newlines, so ensure to remove all
// newlines before injecting the actual HTML body to process.
// PHP's \DOMDocument serialization adds extra whitespace when the markup
// of the wrapping document contains newlines, so ensure we remove all
// newlines before injecting the actual HTML body to be processed.
$document = strtr($document, array("\n" => '', '!html' => $html));
$dom = new \DOMDocument();
@ -280,14 +292,16 @@ EOD;
$body_node = $document->getElementsByTagName('body')->item(0);
$html = '';
foreach ($body_node->getElementsByTagName('script') as $node) {
static::escapeCdataElement($node);
}
foreach ($body_node->getElementsByTagName('style') as $node) {
static::escapeCdataElement($node, '/*', '*/');
}
foreach ($body_node->childNodes as $node) {
$html .= $document->saveXML($node);
if ($body_node !== NULL) {
foreach ($body_node->getElementsByTagName('script') as $node) {
static::escapeCdataElement($node);
}
foreach ($body_node->getElementsByTagName('style') as $node) {
static::escapeCdataElement($node, '/*', '*/');
}
foreach ($body_node->childNodes as $node) {
$html .= $document->saveXML($node);
}
}
return $html;
}

View file

@ -7,23 +7,16 @@
namespace Drupal\Component\Utility;
use Drupal\Component\Render\HtmlEscapedText;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Render\MarkupInterface;
/**
* Manages known safe strings for rendering at the theme layer.
* Contains deprecated functionality related to sanitization of markup.
*
* The Twig theme engine autoescapes string variables in the template, so it
* is possible for a string of markup to become double-escaped. SafeMarkup
* provides a store for known safe strings and methods to manage them
* throughout the page request.
*
* Strings sanitized by self::checkPlain() and self::escape() are automatically
* marked safe, as are markup strings created from @link theme_render render
* arrays @endlink via drupal_render().
*
* This class should be limited to internal use only. Module developers should
* instead use the appropriate
* @link sanitization sanitization functions @endlink or the
* @link theme_render theme and render systems @endlink so that the output can
* can be themed, escaped, and altered properly.
* @deprecated Will be removed before Drupal 9.0.0. Use the appropriate
* @link sanitization sanitization functions @endlink or the @link theme_render theme and render systems @endlink
* so that the output can can be themed, escaped, and altered properly.
*
* @see TwigExtension::escapeFilter()
* @see twig_render_template()
@ -32,100 +25,23 @@ namespace Drupal\Component\Utility;
*/
class SafeMarkup {
/**
* The list of safe strings.
*
* Strings in this list are marked as secure for the entire page render, not
* just the code or element that set it. Therefore, only valid HTML should be
* marked as safe (never partial markup). For example, you should never mark
* string such as '<' or '<script>' safe.
*
* @var array
*/
protected static $safeStrings = array();
/**
* Checks if a string is safe to output.
*
* @param string|\Drupal\Component\Utility\SafeStringInterface $string
* @param string|\Drupal\Component\Render\MarkupInterface $string
* The content to be checked.
* @param string $strategy
* The escaping strategy. Defaults to 'html'. Two escaping strategies are
* supported by default:
* - 'html': (default) The string is safe for use in HTML code.
* - 'all': The string is safe for all use cases.
* See the
* @link http://twig.sensiolabs.org/doc/filters/escape.html Twig escape documentation @endlink
* for more information on escaping strategies in Twig.
* (optional) This value is ignored.
*
* @return bool
* TRUE if the string has been marked secure, FALSE otherwise.
*
* @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0.
* Instead, you should just check if a variable is an instance of
* \Drupal\Component\Render\MarkupInterface.
*/
public static function isSafe($string, $strategy = 'html') {
// Do the instanceof checks first to save unnecessarily casting the object
// to a string.
return $string instanceOf SafeStringInterface || isset(static::$safeStrings[(string) $string][$strategy]) ||
isset(static::$safeStrings[(string) $string]['all']);
}
/**
* Adds previously retrieved known safe strings to the safe string list.
*
* This method is for internal use. Do not use it to prevent escaping of
* markup; instead, use the appropriate
* @link sanitization sanitization functions @endlink or the
* @link theme_render theme and render systems @endlink so that the output
* can be themed, escaped, and altered properly.
*
* This marks strings as secure for the entire page render, not just the code
* or element that set it. Therefore, only valid HTML should be
* marked as safe (never partial markup). For example, you should never do:
* @code
* SafeMarkup::setMultiple(['<' => ['html' => TRUE]]);
* @endcode
* or:
* @code
* SafeMarkup::setMultiple(['<script>' => ['all' => TRUE]]);
* @endcode
* @param array $safe_strings
* A list of safe strings as previously retrieved by self::getAll().
* Every string in this list will be represented by a multidimensional
* array in which the keys are the string and the escaping strategy used for
* this string, and in which the value is the boolean TRUE.
* See self::isSafe() for the list of supported escaping strategies.
*
* @throws \UnexpectedValueException
*
* @internal This is called by FormCache, StringTranslation and the Batch API.
* It should not be used anywhere else.
*/
public static function setMultiple(array $safe_strings) {
foreach ($safe_strings as $string => $strategies) {
foreach ($strategies as $strategy => $value) {
$string = (string) $string;
if ($value === TRUE) {
static::$safeStrings[$string][$strategy] = TRUE;
}
else {
// Danger - something is very wrong.
throw new \UnexpectedValueException('Only the value TRUE is accepted for safe strings');
}
}
}
}
/**
* Gets all strings currently marked as safe.
*
* This is useful for the batch and form APIs, where it is important to
* preserve the safe markup state across page requests.
*
* @return array
* An array of strings currently marked safe.
*/
public static function getAll() {
return static::$safeStrings;
return $string instanceOf MarkupInterface;
}
/**
@ -137,13 +53,10 @@ class SafeMarkup {
* @param string $text
* The text to be checked or processed.
*
* @return string
* An HTML safe version of $text, or an empty string if $text is not valid
* UTF-8.
* @return \Drupal\Component\Render\HtmlEscapedText
* An HtmlEscapedText object that escapes when rendered to string.
*
* @ingroup sanitization
*
* @deprecated Will be removed before Drupal 8.0.0. Rely on Twig's
* @deprecated Will be removed before Drupal 9.0.0. Rely on Twig's
* auto-escaping feature, or use the @link theme_render #plain_text @endlink
* key when constructing a render array that contains plain text in order to
* use the renderer's auto-escaping feature. If neither of these are
@ -153,91 +66,32 @@ class SafeMarkup {
* @see drupal_validate_utf8()
*/
public static function checkPlain($text) {
$string = Html::escape($text);
static::$safeStrings[$string]['html'] = TRUE;
return $string;
return new HtmlEscapedText($text);
}
/**
* Formats a string for HTML display by replacing variable placeholders.
*
* This function replaces variable placeholders in a string with the requested
* values and escapes the values so they can be safely displayed as HTML. It
* should be used on any unknown text that is intended to be printed to an
* HTML page (especially text that may have come from untrusted users, since
* in that case it prevents cross-site scripting and other security problems).
*
* In most cases, you should use t() rather than calling this function
* directly, since it will translate the text (on non-English-only sites) in
* addition to formatting it.
*
* @param string $string
* A string containing placeholders. The string itself is not escaped, any
* unsafe content must be in $args and inserted via placeholders.
* A string containing placeholders. The string itself will not be escaped,
* any unsafe content must be in $args and inserted via placeholders.
* @param array $args
* An associative array of replacements to make. Occurrences in $string of
* any key in $args are replaced with the corresponding value, after
* optional sanitization and formatting. The type of sanitization and
* formatting depends on the first character of the key:
* - @variable: Escaped to HTML using self::escape(). Use this as the
* default choice for anything displayed on a page on the site.
* - %variable: Escaped to HTML wrapped in <em> tags, which makes the
* following HTML code:
* @code
* <em class="placeholder">text output here.</em>
* @endcode
* - !variable: Inserted as is, with no sanitization or formatting. Only
* use this when the resulting string is being generated for one of:
* - Non-HTML usage, such as a plain-text email.
* - Non-direct HTML output, such as a plain-text variable that will be
* printed as an HTML attribute value and therefore formatted with
* self::checkPlain() as part of that.
* - Some other special reason for suppressing sanitization.
* An array with placeholder replacements, keyed by placeholder. See
* \Drupal\Component\Render\FormattableMarkup::placeholderFormat() for
* additional information about placeholders.
*
* @return string
* The formatted string, which is marked as safe unless sanitization of an
* unsafe argument was suppressed (see above).
* @return string|\Drupal\Component\Render\MarkupInterface
* The formatted string, which is an instance of MarkupInterface unless
* sanitization of an unsafe argument was suppressed (see above).
*
* @ingroup sanitization
* @see \Drupal\Component\Render\FormattableMarkup::placeholderFormat()
* @see \Drupal\Component\Render\FormattableMarkup
*
* @see t()
* @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Component\Render\FormattableMarkup.
*/
public static function format($string, array $args) {
$safe = TRUE;
// Transform arguments before inserting them.
foreach ($args as $key => $value) {
switch ($key[0]) {
case '@':
// Escaped only.
if (!SafeMarkup::isSafe($value)) {
$args[$key] = Html::escape($value);
}
break;
case '%':
default:
// Escaped and placeholder.
if (!SafeMarkup::isSafe($value)) {
$value = Html::escape($value);
}
$args[$key] = '<em class="placeholder">' . $value . '</em>';
break;
case '!':
// Pass-through.
if (!static::isSafe($value)) {
$safe = FALSE;
}
}
}
$output = strtr($string, $args);
if ($safe) {
static::$safeStrings[$output]['html'] = TRUE;
}
return $output;
return new FormattableMarkup($string, $args);
}
}

View file

@ -1,45 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\Component\Utility\SafeStringInterface.
*/
namespace Drupal\Component\Utility;
/**
* Marks an object's __toString() method as returning safe markup.
*
* All objects that implement this interface should be marked @internal.
*
* This interface should only be used on objects that emit known safe strings
* from their __toString() method. If there is any risk of the method returning
* user-entered data that has not been filtered first, it must not be used.
*
* If the object is going to be used directly in Twig templates it should
* implement \Countable so it can be used in if statements.
*
* @internal
* This interface is marked as internal because it should only be used by
* objects used during rendering. This interface should be used by modules if
* they interrupt the render pipeline and explicitly deal with SafeString
* objects created by the render system. Additionally, if a module reuses the
* regular render pipeline internally and passes processed data into it. For
* example, Views implements a custom render pipeline in order to render JSON
* and to fast render fields.
*
* @see \Drupal\Component\Utility\SafeStringTrait
* @see \Drupal\Component\Utility\SafeMarkup::isSafe()
* @see \Drupal\Core\Template\TwigExtension::escapeFilter()
*/
interface SafeStringInterface extends \JsonSerializable {
/**
* Returns a safe string.
*
* @return string
* The safe string.
*/
public function __toString();
}

View file

@ -1,80 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\Component\Utility\SafeStringTrait.
*/
namespace Drupal\Component\Utility;
/**
* Implements SafeStringInterface and Countable for rendered objects.
*
* @see \Drupal\Component\Utility\SafeStringInterface
*/
trait SafeStringTrait {
/**
* The safe string.
*
* @var string
*/
protected $string;
/**
* Creates a SafeString object if necessary.
*
* If $string is equal to a blank string then it is not necessary to create a
* SafeString object. If $string is an object that implements
* SafeStringInterface it is returned unchanged.
*
* @param mixed $string
* The string to mark as safe. This value will be cast to a string.
*
* @return string|\Drupal\Component\Utility\SafeStringInterface
* A safe string.
*/
public static function create($string) {
if ($string instanceof SafeStringInterface) {
return $string;
}
$string = (string) $string;
if ($string === '') {
return '';
}
$safe_string = new static();
$safe_string->string = $string;
return $safe_string;
}
/**
* Returns the string version of the SafeString object.
*
* @return string
* The safe string content.
*/
public function __toString() {
return $this->string;
}
/**
* Returns the string length.
*
* @return int
* The length of the string.
*/
public function count() {
return Unicode::strlen($this->string);
}
/**
* Returns a representation of the object for use in JSON serialization.
*
* @return string
* The safe string content.
*/
public function jsonSerialize() {
return $this->__toString();
}
}

View file

@ -0,0 +1,48 @@
<?php
/**
* @file
* Contains \Drupal\Component\Utility\ToStringTrait.
*/
namespace Drupal\Component\Utility;
/**
* Wraps __toString in a trait to avoid some fatals.
*/
trait ToStringTrait {
/**
* Implements the magic __toString() method.
*/
public function __toString() {
try {
return (string) $this->render();
}
catch (\Exception $e) {
// User errors in __toString() methods are considered fatal in the Drupal
// error handler.
trigger_error(get_class($e) . ' thrown while calling __toString on a ' . get_class($this) . ' object in ' . $e->getFile() . ' on line ' . $e->getLine() . ': ' . $e->getMessage(), E_USER_ERROR);
// In case we are using another error handler that did not fatal on the
// E_USER_ERROR, we terminate execution. However, for test purposes allow
// a return value.
return $this->_die();
}
}
/**
* For test purposes, wrap die() in an overridable method.
*/
protected function _die() {
die();
}
/**
* Renders the object as a string.
*
* @return string|object
* The rendered string or an object implementing __toString().
*/
abstract public function render();
}

View file

@ -412,8 +412,8 @@ EOD;
// Find the starting byte offset.
$bytes = 0;
if ($start > 0) {
// Count all the continuation bytes from the start until we have found
// $start characters or the end of the string.
// Count all the characters except continuation bytes from the start
// until we have found $start characters or the end of the string.
$bytes = -1; $chars = -1;
while ($bytes < $strlen - 1 && $chars < $start) {
$bytes++;
@ -424,8 +424,8 @@ EOD;
}
}
elseif ($start < 0) {
// Count all the continuation bytes from the end until we have found
// abs($start) characters.
// Count all the characters except continuation bytes from the end
// until we have found abs($start) characters.
$start = abs($start);
$bytes = $strlen; $chars = 0;
while ($bytes > 0 && $chars < $start) {
@ -443,9 +443,9 @@ EOD;
$iend = $strlen;
}
elseif ($length > 0) {
// Count all the continuation bytes from the starting index until we have
// found $length characters or reached the end of the string, then
// backtrace one byte.
// Count all the characters except continuation bytes from the starting
// index until we have found $length characters or reached the end of
// the string, then backtrace one byte.
$iend = $istart - 1;
$chars = -1;
$last_real = FALSE;
@ -458,15 +458,15 @@ EOD;
$last_real = TRUE;
}
}
// Backtrace one byte if the last character we found was a real character
// and we don't need it.
// Backtrace one byte if the last character we found was a real
// character and we don't need it.
if ($last_real && $chars >= $length) {
$iend--;
}
}
elseif ($length < 0) {
// Count all the continuation bytes from the end until we have found
// abs($start) characters, then backtrace one byte.
// Count all the characters except continuation bytes from the end
// until we have found abs($start) characters, then backtrace one byte.
$length = abs($length);
$iend = $strlen; $chars = 0;
while ($iend > 0 && $chars < $length) {
@ -697,4 +697,33 @@ EOD;
return (preg_match('/^./us', $text) == 1);
}
/**
* Finds the position of the first occurrence of a string in another string.
*
* @param string $haystack
* The string to search in.
* @param string $needle
* The string to find in $haystack.
* @param int $offset
* If specified, start the search at this number of characters from the
* beginning (default 0).
*
* @return int|false
* The position where $needle occurs in $haystack, always relative to the
* beginning (independent of $offset), or FALSE if not found. Note that
* a return value of 0 is not the same as FALSE.
*/
public static function strpos($haystack, $needle, $offset = 0) {
if (static::getStatus() == static::STATUS_MULTIBYTE) {
return mb_strpos($haystack, $needle, $offset);
}
else {
// Remove Unicode continuation characters, to be compatible with
// Unicode::strlen() and Unicode::substr().
$haystack = preg_replace("/[\x80-\xBF]/", '', $haystack);
$needle = preg_replace("/[\x80-\xBF]/", '', $needle);
return strpos($haystack, $needle, $offset);
}
}
}

View file

@ -304,7 +304,22 @@ class UrlHelper {
* \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 functions that will
* call \Drupal\Component\Utility\SafeMarkup::checkPlain() separately.
* call Html::escape() separately. The exact behavior depends on the value:
* - If the value is a well-formed (per RFC 3986) relative URL or
* absolute URL that does not use a dangerous protocol (like
* "javascript:"), then the URL remains unchanged. This includes all
* URLs generated via Url::toString() and UrlGeneratorTrait::url().
* - If the value is a well-formed absolute URL with a dangerous protocol,
* the protocol is stripped. This process is repeated on the remaining URL
* until it is stripped down to a safe protocol.
* - If the value is not a well-formed URL, the same sanitization behavior as
* for well-formed URLs will be invoked, which strips most substrings that
* precede a ":". The result can be used in URL attributes such as "href"
* or "src" (only after calling Html::escape() separately), but this may not
* produce valid HTML (e.g., malformed URLs within "href" attributes fail
* HTML validation). This can be avoided by using
* Url::fromUri($possibly_not_a_url)->toString(), which either throws an
* exception or returns a well-formed URL.
*
* @param string $uri
* A plain-text URI that might contain dangerous protocols.
@ -314,6 +329,11 @@ class UrlHelper {
* 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.
*
* @see \Drupal\Component\Utility\Html::escape()
* @see \Drupal\Core\Url::toString()
* @see \Drupal\Core\Routing\UrlGeneratorTrait::url()
* @see \Drupal\Core\Url::fromUri()
*/
public static function stripDangerousProtocols($uri) {
$allowed_protocols = array_flip(static::$allowedProtocols);

View file

@ -106,7 +106,7 @@ class Xss {
*
* Use only for fields where it is impractical to use the
* whole filter system, but where some (mainly inline) mark-up
* is desired (so \Drupal\Component\Utility\SafeMarkup::checkPlain() is
* is desired (so \Drupal\Component\Utility\Html::escape() is
* not acceptable).
*
* Allows all tags that can be used inside an HTML body, save