Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663
This commit is contained in:
parent
eb34d130a8
commit
f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions
|
@ -57,7 +57,7 @@ class Handle {
|
|||
|
||||
if (version_compare(PHP_VERSION, '7.0.0-dev') < 0) {
|
||||
// PHP 5 - create a handler to throw the exception directly.
|
||||
assert_options(ASSERT_CALLBACK, function($file, $line, $code, $message) {
|
||||
assert_options(ASSERT_CALLBACK, function($file = '', $line = 0, $code = '', $message = '') {
|
||||
if (empty($message)) {
|
||||
$message = $code;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,9 @@ class Inspector {
|
|||
/**
|
||||
* Asserts that all members are strings.
|
||||
*
|
||||
* Use this only if it is vital that the members not be objects, otherwise
|
||||
* test with ::assertAllStringable().
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
|
@ -94,7 +97,7 @@ class Inspector {
|
|||
public static function assertAllStringable($traversable) {
|
||||
if (static::assertTraversable($traversable)) {
|
||||
foreach ($traversable as $member) {
|
||||
if (!(is_string($member) || (is_object($member) && method_exists($member, '__toString')))) {
|
||||
if (!static::assertStringable($member)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +106,22 @@ class Inspector {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts argument is a string or an object castable to a string.
|
||||
*
|
||||
* Use this instead of is_string() alone unless the argument being an object
|
||||
* in any way will cause a problem.
|
||||
*
|
||||
* @param mixed string
|
||||
* Variable to be examined
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $string is a string or an object castable to a string.
|
||||
*/
|
||||
public static function assertStringable($string) {
|
||||
return is_string($string) || (is_object($string) && method_exists($string, '__toString'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all members are arrays.
|
||||
*
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Contains \Drupal\Component\Datetime\DateTimePlus.
|
||||
*/
|
||||
namespace Drupal\Component\Datetime;
|
||||
use Drupal\Component\Utility\ToStringTrait;
|
||||
|
||||
/**
|
||||
* Wraps DateTime().
|
||||
|
@ -28,6 +29,8 @@ namespace Drupal\Component\Datetime;
|
|||
*/
|
||||
class DateTimePlus {
|
||||
|
||||
use ToStringTrait;
|
||||
|
||||
const FORMAT = 'Y-m-d H:i:s';
|
||||
|
||||
/**
|
||||
|
@ -271,16 +274,12 @@ class DateTimePlus {
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements __toString() for dates.
|
||||
* Renders the timezone name.
|
||||
*
|
||||
* The DateTime class does not implement this.
|
||||
*
|
||||
* @see https://bugs.php.net/bug.php?id=62911
|
||||
* @see http://www.serverphorums.com/read.php?7,555645
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
$format = static::FORMAT;
|
||||
return $this->format($format) . ' ' . $this->getTimeZone()->getName();
|
||||
public function render() {
|
||||
return $this->format(static::FORMAT) . ' ' . $this->getTimeZone()->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -153,4 +153,13 @@ class FileCache implements FileCacheInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the static cache.
|
||||
*
|
||||
* @todo Replace this once https://www.drupal.org/node/2260187 is in.
|
||||
*/
|
||||
public static function reset() {
|
||||
static::$cached = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@ class PoItem {
|
|||
strpos($this->_source, LOCALE_PLURAL_DELIMITER) !== FALSE) {
|
||||
$this->setSource(explode(LOCALE_PLURAL_DELIMITER, $this->_source));
|
||||
$this->setTranslation(explode(LOCALE_PLURAL_DELIMITER, $this->_translation));
|
||||
$this->setPlural(count($this->_translation) > 1);
|
||||
$this->setPlural(count($this->_source) > 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,20 +31,16 @@ class Context implements ContextInterface {
|
|||
protected $contextDefinition;
|
||||
|
||||
/**
|
||||
* Sets the contextDefinition for us without needing to call the setter.
|
||||
* Create a context object.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\Context\ContextDefinitionInterface $context_definition
|
||||
* The context definition.
|
||||
* @param mixed|null $context_value
|
||||
* The value of the context.
|
||||
*/
|
||||
public function __construct(ContextDefinitionInterface $context_definition) {
|
||||
public function __construct(ContextDefinitionInterface $context_definition, $context_value = NULL) {
|
||||
$this->contextDefinition = $context_definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Component\Plugin\Context\ContextInterface::setContextValue().
|
||||
*/
|
||||
public function setContextValue($value) {
|
||||
$this->contextValue = $value;
|
||||
$this->contextValue = $context_value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,13 +70,6 @@ class Context implements ContextInterface {
|
|||
return (bool) $this->contextValue || (bool) $this->getContextDefinition()->getDefaultValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setContextDefinition(ContextDefinitionInterface $context_definition) {
|
||||
$this->contextDefinition = $context_definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Component\Plugin\Context\ContextInterface::getContextDefinition().
|
||||
*/
|
||||
|
|
|
@ -12,16 +12,6 @@ namespace Drupal\Component\Plugin\Context;
|
|||
*/
|
||||
interface ContextInterface {
|
||||
|
||||
/**
|
||||
* Sets the context value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* The value of this context, matching the context definition.
|
||||
*
|
||||
* @see \Drupal\Component\Plugin\Context\ContextInterface::setContextDefinition().
|
||||
*/
|
||||
public function setContextValue($value);
|
||||
|
||||
/**
|
||||
* Gets the context value.
|
||||
*
|
||||
|
@ -38,15 +28,6 @@ interface ContextInterface {
|
|||
*/
|
||||
public function hasContextValue();
|
||||
|
||||
/**
|
||||
* Sets the definition that the context must conform to.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\Context\ContextDefinitionInterface $context_definition
|
||||
* A defining characteristic representation of the context against which
|
||||
* that context can be validated.
|
||||
*/
|
||||
public function setContextDefinition(ContextDefinitionInterface $context_definition);
|
||||
|
||||
/**
|
||||
* Gets the provided definition that the context must conform to.
|
||||
*
|
||||
|
|
|
@ -41,17 +41,30 @@ abstract class ContextAwarePluginBase extends PluginBase implements ContextAware
|
|||
* The plugin implementation definition.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
|
||||
$context = array();
|
||||
if (isset($configuration['context'])) {
|
||||
$context = $configuration['context'];
|
||||
unset($configuration['context']);
|
||||
}
|
||||
$context_configuration = isset($configuration['context']) ? $configuration['context'] : [];
|
||||
unset($configuration['context']);
|
||||
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
foreach ($context as $key => $value) {
|
||||
|
||||
$this->contexts = $this->createContextFromConfiguration($context_configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates context objects from any context mappings in configuration.
|
||||
*
|
||||
* @param array $context_configuration
|
||||
* An associative array of context names and values.
|
||||
*
|
||||
* @return \Drupal\Component\Plugin\Context\ContextInterface[]
|
||||
* An array of context objects.
|
||||
*/
|
||||
protected function createContextFromConfiguration(array $context_configuration) {
|
||||
$contexts = [];
|
||||
foreach ($context_configuration as $key => $value) {
|
||||
$context_definition = $this->getContextDefinition($key);
|
||||
$this->context[$key] = new Context($context_definition);
|
||||
$this->context[$key]->setContextValue($value);
|
||||
$contexts[$key] = new Context($context_definition, $value);
|
||||
}
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,7 +137,7 @@ abstract class ContextAwarePluginBase extends PluginBase implements ContextAware
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function setContextValue($name, $value) {
|
||||
$this->getContext($name)->setContextValue($value);
|
||||
$this->context[$name] = new Context($this->getContextDefinition($name), $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Component\Plugin\PluginDefinitionInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\Plugin\Definition;
|
||||
|
||||
/**
|
||||
* Defines a plugin definition.
|
||||
*
|
||||
* Object-based plugin definitions MUST implement this interface.
|
||||
*
|
||||
* @ingroup Plugin
|
||||
*/
|
||||
interface PluginDefinitionInterface {
|
||||
|
||||
/**
|
||||
* Sets the class.
|
||||
*
|
||||
* @param string $class
|
||||
* A fully qualified class name.
|
||||
*
|
||||
* @return static
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* If the class is invalid.
|
||||
*/
|
||||
public function setClass($class);
|
||||
|
||||
/**
|
||||
* Gets the class.
|
||||
*
|
||||
* @return string
|
||||
* A fully qualified class name.
|
||||
*/
|
||||
public function getClass();
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
namespace Drupal\Component\Plugin\Factory;
|
||||
|
||||
use Drupal\Component\Plugin\Definition\PluginDefinitionInterface;
|
||||
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
|
||||
use Drupal\Component\Plugin\Exception\PluginException;
|
||||
|
||||
|
@ -63,7 +64,7 @@ class DefaultFactory implements FactoryInterface {
|
|||
*
|
||||
* @param string $plugin_id
|
||||
* The id of a plugin.
|
||||
* @param mixed $plugin_definition
|
||||
* @param \Drupal\Component\Plugin\Definition\PluginDefinitionInterface|mixed[] $plugin_definition
|
||||
* The plugin definition associated with the plugin ID.
|
||||
* @param string $required_interface
|
||||
* (optional) THe required plugin interface.
|
||||
|
@ -77,18 +78,32 @@ class DefaultFactory implements FactoryInterface {
|
|||
*
|
||||
*/
|
||||
public static function getPluginClass($plugin_id, $plugin_definition = NULL, $required_interface = NULL) {
|
||||
if (empty($plugin_definition['class'])) {
|
||||
throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $plugin_id));
|
||||
}
|
||||
$missing_class_message = sprintf('The plugin (%s) did not specify an instance class.', $plugin_id);
|
||||
if (is_array($plugin_definition)) {
|
||||
if (empty($plugin_definition['class'])) {
|
||||
throw new PluginException($missing_class_message);
|
||||
}
|
||||
|
||||
$class = $plugin_definition['class'];
|
||||
$class = $plugin_definition['class'];
|
||||
}
|
||||
elseif ($plugin_definition instanceof PluginDefinitionInterface) {
|
||||
if (!$plugin_definition->getClass()) {
|
||||
throw new PluginException($missing_class_message);
|
||||
}
|
||||
|
||||
$class = $plugin_definition->getClass();
|
||||
}
|
||||
else {
|
||||
$plugin_definition_type = is_object($plugin_definition) ? get_class($plugin_definition) : gettype($plugin_definition);
|
||||
throw new PluginException(sprintf('%s can only handle plugin definitions that are arrays or that implement %s, but %s given.', __CLASS__, PluginDefinitionInterface::class, $plugin_definition_type));
|
||||
}
|
||||
|
||||
if (!class_exists($class)) {
|
||||
throw new PluginException(sprintf('Plugin (%s) instance class "%s" does not exist.', $plugin_id, $class));
|
||||
}
|
||||
|
||||
if ($required_interface && !is_subclass_of($plugin_definition['class'], $required_interface)) {
|
||||
throw new PluginException(sprintf('Plugin "%s" (%s) must implement interface %s.', $plugin_id, $plugin_definition['class'], $required_interface));
|
||||
if ($required_interface && !is_subclass_of($class, $required_interface)) {
|
||||
throw new PluginException(sprintf('Plugin "%s" (%s) must implement interface %s.', $plugin_id, $class, $required_interface));
|
||||
}
|
||||
|
||||
return $class;
|
||||
|
|
253
core/lib/Drupal/Component/Render/FormattableMarkup.php
Normal file
253
core/lib/Drupal/Component/Render/FormattableMarkup.php
Normal file
|
@ -0,0 +1,253 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains Drupal\Component\Render\FormattableMarkup.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\Render;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
|
||||
/**
|
||||
* Formats a string for HTML display by replacing variable placeholders.
|
||||
*
|
||||
* When cast to a string, this object replaces variable placeholders in the
|
||||
* string with the arguments passed in during construction and escapes the
|
||||
* values so they can be safely displayed as HTML. See the documentation of
|
||||
* \Drupal\Component\Render\FormattableMarkup::placeholderFormat() for details
|
||||
* on the supported placeholders and how to use them securely. Incorrect use of
|
||||
* this class can result in security vulnerabilities.
|
||||
*
|
||||
* In most cases, you should use TranslatableMarkup or PluralTranslatableMarkup
|
||||
* rather than this object, since they will translate the text (on
|
||||
* non-English-only sites) in addition to formatting it. Variables concatenated
|
||||
* without the insertion of language-specific words or punctuation are some
|
||||
* examples where translation is not applicable and using this class directly
|
||||
* directly is appropriate.
|
||||
*
|
||||
* This class is designed for formatting messages that are mostly text, not as
|
||||
* an HTML template language. As such:
|
||||
* - The passed in string should contain no (or minimal) HTML.
|
||||
* - Variable placeholders should not be used within the "<" and ">" of an
|
||||
* HTML tag, such as in HTML attribute values. This would be a security
|
||||
* risk. Examples:
|
||||
* @code
|
||||
* // Insecure (placeholder within "<" and ">"):
|
||||
* $this->placeholderFormat('<@variable>text</@variable>', ['@variable' => $variable]);
|
||||
* // Insecure (placeholder within "<" and ">"):
|
||||
* $this->placeholderFormat('<a @variable>link text</a>', ['@variable' => $variable]);
|
||||
* // Insecure (placeholder within "<" and ">"):
|
||||
* $this->placeholderFormat('<a title="@variable">link text</a>', ['@variable' => $variable]);
|
||||
* @endcode
|
||||
* Only the "href" attribute is supported via the special ":variable"
|
||||
* placeholder, to allow simple links to be inserted:
|
||||
* @code
|
||||
* // Secure (usage of ":variable" placeholder for href attribute):
|
||||
* $this->placeholderFormat('<a href=":variable">link text</a>', [':variable' , $variable]);
|
||||
* // Secure (usage of ":variable" placeholder for href attribute):
|
||||
* $this->placeholderFormat('<a href=":variable" title="static text">link text</a>', [':variable' => $variable]);
|
||||
* // Insecure (the "@variable" placeholder does not filter dangerous
|
||||
* // protocols):
|
||||
* $this->placeholderFormat('<a href="@variable">link text</a>', ['@variable' => $variable]);
|
||||
* // Insecure ("@variable" placeholder within "<" and ">"):
|
||||
* $this->placeholderFormat('<a href=":url" title="@variable">link text</a>', [':url' => $url, '@variable' => $variable]);
|
||||
* @endcode
|
||||
* To build non-minimal HTML, use an HTML template language such as Twig,
|
||||
* rather than this class.
|
||||
*
|
||||
* @ingroup sanitization
|
||||
*
|
||||
* @see \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
* @see \Drupal\Core\StringTranslation\PluralTranslatableMarkup
|
||||
* @see \Drupal\Component\Render\FormattableMarkup::placeholderFormat()
|
||||
*/
|
||||
class FormattableMarkup implements MarkupInterface {
|
||||
|
||||
/**
|
||||
* The arguments to replace placeholders with.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $arguments = [];
|
||||
|
||||
/**
|
||||
* Constructs a new class instance.
|
||||
*
|
||||
* @param string $string
|
||||
* A string containing placeholders. The string itself will not be escaped,
|
||||
* any unsafe content must be in $args and inserted via placeholders.
|
||||
* @param array $arguments
|
||||
* An array with placeholder replacements, keyed by placeholder. See
|
||||
* \Drupal\Component\Render\FormattableMarkup::placeholderFormat() for
|
||||
* additional information about placeholders.
|
||||
*
|
||||
* @see \Drupal\Component\Render\FormattableMarkup::placeholderFormat()
|
||||
*/
|
||||
public function __construct($string, array $arguments) {
|
||||
$this->string = (string) $string;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString() {
|
||||
return static::placeholderFormat($this->string, $this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces placeholders in a string with values.
|
||||
*
|
||||
* @param string $string
|
||||
* A string containing placeholders. The string itself is expected to be
|
||||
* safe and correct HTML. Any unsafe content must be in $args and
|
||||
* inserted via placeholders.
|
||||
* @param array $args
|
||||
* An associative array of replacements. Each array key should be the same
|
||||
* as a placeholder in $string. The corresponding value should be a string
|
||||
* or an object that implements
|
||||
* \Drupal\Component\Render\MarkupInterface. The value replaces the
|
||||
* placeholder in $string. Sanitization and formatting will be done before
|
||||
* replacement. The type of sanitization and formatting depends on the first
|
||||
* character of the key:
|
||||
* - @variable: When the placeholder replacement value is:
|
||||
* - A string, the replaced value in the returned string will be sanitized
|
||||
* using \Drupal\Component\Utility\Html::escape().
|
||||
* - A MarkupInterface object, the replaced value in the returned string
|
||||
* will not be sanitized.
|
||||
* - A MarkupInterface object cast to a string, the replaced value in the
|
||||
* returned string be forcibly sanitized using
|
||||
* \Drupal\Component\Utility\Html::escape().
|
||||
* @code
|
||||
* $this->placeholderFormat('This will force HTML-escaping of the replacement value: @text', ['@text' => (string) $safe_string_interface_object));
|
||||
* @endcode
|
||||
* Use this placeholder as the default choice for anything displayed on
|
||||
* the site, but not within HTML attributes, JavaScript, or CSS. Doing so
|
||||
* is a security risk.
|
||||
* - %variable: Use when the replacement value is to be wrapped in <em>
|
||||
* tags.
|
||||
* A call like:
|
||||
* @code
|
||||
* $string = "%output_text";
|
||||
* $arguments = ['output_text' => 'text output here.'];
|
||||
* $this->placeholderFormat($string, $arguments);
|
||||
* @endcode
|
||||
* makes the following HTML code:
|
||||
* @code
|
||||
* <em class="placeholder">text output here.</em>
|
||||
* @endcode
|
||||
* As with @variable, do not use this within HTML attributes, JavaScript,
|
||||
* or CSS. Doing so is a security risk.
|
||||
* - :variable: Return value is escaped with
|
||||
* \Drupal\Component\Utility\Html::escape() and filtered for dangerous
|
||||
* protocols using UrlHelper::stripDangerousProtocols(). Use this when
|
||||
* using the "href" attribute, ensuring the attribute value is always
|
||||
* wrapped in quotes:
|
||||
* @code
|
||||
* // Secure (with quotes):
|
||||
* $this->placeholderFormat('<a href=":url">@variable</a>', [':url' => $url, @variable => $variable]);
|
||||
* // Insecure (without quotes):
|
||||
* $this->placeholderFormat('<a href=:url>@variable</a>', [':url' => $url, @variable => $variable]);
|
||||
* @endcode
|
||||
* When ":variable" comes from arbitrary user input, the result is secure,
|
||||
* but not guaranteed to be a valid URL (which means the resulting output
|
||||
* could fail HTML validation). To guarantee a valid URL, use
|
||||
* Url::fromUri($user_input)->toString() (which either throws an exception
|
||||
* or returns a well-formed URL) before passing the result into a
|
||||
* ":variable" placeholder.
|
||||
*
|
||||
* @return string
|
||||
* A formatted HTML string with the placeholders replaced.
|
||||
*
|
||||
* @ingroup sanitization
|
||||
*
|
||||
* @see \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
* @see \Drupal\Core\StringTranslation\PluralTranslatableMarkup
|
||||
* @see \Drupal\Component\Utility\Html::escape()
|
||||
* @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols()
|
||||
* @see \Drupal\Core\Url::fromUri()
|
||||
*/
|
||||
protected static function placeholderFormat($string, array $args) {
|
||||
// Transform arguments before inserting them.
|
||||
foreach ($args as $key => $value) {
|
||||
switch ($key[0]) {
|
||||
case '@':
|
||||
// Escape if the value is not an object from a class that implements
|
||||
// \Drupal\Component\Render\MarkupInterface, for example strings will
|
||||
// be escaped.
|
||||
// \Drupal\Component\Utility\SafeMarkup\SafeMarkup::isSafe() may
|
||||
// return TRUE for content that is safe within HTML fragments, but not
|
||||
// within other contexts, so this placeholder type must not be used
|
||||
// within HTML attributes, JavaScript, or CSS.
|
||||
$args[$key] = static::placeholderEscape($value);
|
||||
break;
|
||||
|
||||
case ':':
|
||||
// Strip URL protocols that can be XSS vectors.
|
||||
$value = UrlHelper::stripDangerousProtocols($value);
|
||||
// Escape unconditionally, without checking
|
||||
// \Drupal\Component\Utility\SafeMarkup\SafeMarkup::isSafe(). This
|
||||
// forces characters that are unsafe for use in an "href" HTML
|
||||
// attribute to be encoded. If a caller wants to pass a value that is
|
||||
// extracted from HTML and therefore is already HTML encoded, it must
|
||||
// invoke
|
||||
// \Drupal\Component\Render\OutputStrategyInterface::renderFromHtml()
|
||||
// on it prior to passing it in as a placeholder value of this type.
|
||||
// @todo Add some advice and stronger warnings.
|
||||
// https://www.drupal.org/node/2569041.
|
||||
$args[$key] = Html::escape($value);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
default:
|
||||
// Similarly to @, escape non-safe values. Also, add wrapping markup
|
||||
// in order to render as a placeholder. Not for use within attributes,
|
||||
// per the warning above about
|
||||
// \Drupal\Component\Utility\SafeMarkup\SafeMarkup::isSafe() and also
|
||||
// due to the wrapping markup.
|
||||
$args[$key] = '<em class="placeholder">' . static::placeholderEscape($value) . '</em>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return strtr($string, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes a placeholder replacement value if needed.
|
||||
*
|
||||
* @param string|\Drupal\Component\Render\MarkupInterface $value
|
||||
* A placeholder replacement value.
|
||||
*
|
||||
* @return string
|
||||
* The properly escaped replacement value.
|
||||
*/
|
||||
protected static function placeholderEscape($value) {
|
||||
return SafeMarkup::isSafe($value) ? (string) $value : Html::escape($value);
|
||||
}
|
||||
|
||||
}
|
61
core/lib/Drupal/Component/Render/HtmlEscapedText.php
Normal file
61
core/lib/Drupal/Component/Render/HtmlEscapedText.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Component\Render\HtmlEscapedText.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\Render;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
|
||||
/**
|
||||
* Escapes HTML syntax characters to HTML entities for display in markup.
|
||||
*
|
||||
* This class can be used to provide theme engine-like late escaping
|
||||
* functionality.
|
||||
*
|
||||
* @ingroup sanitization
|
||||
*/
|
||||
class HtmlEscapedText implements MarkupInterface {
|
||||
|
||||
/**
|
||||
* The string to escape.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $string;
|
||||
|
||||
/**
|
||||
* Constructs an HtmlEscapedText object.
|
||||
*
|
||||
* @param $string
|
||||
* The string to escape. This value will be cast to a string.
|
||||
*/
|
||||
public function __construct($string) {
|
||||
$this->string = (string) $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString() {
|
||||
return Html::escape($this->string);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count() {
|
||||
return Unicode::strlen($this->string);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize() {
|
||||
return $this->__toString();
|
||||
}
|
||||
|
||||
}
|
48
core/lib/Drupal/Component/Render/MarkupInterface.php
Normal file
48
core/lib/Drupal/Component/Render/MarkupInterface.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Component\Render\MarkupInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\Render;
|
||||
|
||||
/**
|
||||
* Marks an object's __toString() method as returning markup.
|
||||
*
|
||||
* Objects that implement this interface will not be automatically XSS filtered
|
||||
* by the render system or automatically escaped by the theme engine.
|
||||
*
|
||||
* If there is any risk of the object's __toString() method returning
|
||||
* user-entered data that has not been filtered first, it must not be used. If
|
||||
* the object that implements this does not perform automatic escaping or
|
||||
* filtering itself, then it must be marked as "@internal". For example, Views
|
||||
* has the internal ViewsRenderPipelineMarkup object to provide a custom render
|
||||
* pipeline in order to render JSON and to fast render fields. By contrast,
|
||||
* FormattableMarkup and TranslatableMarkup always sanitize their output when
|
||||
* used correctly.
|
||||
*
|
||||
* If the object is going to be used directly in Twig templates it should
|
||||
* implement \Countable so it can be used in if statements.
|
||||
*
|
||||
* @see \Drupal\Component\Render\MarkupTrait
|
||||
* @see \Drupal\Component\Utility\SafeMarkup::isSafe()
|
||||
* @see \Drupal\Core\Template\TwigExtension::escapeFilter()
|
||||
* @see \Drupal\Component\Render\FormattableMarkup
|
||||
* @see \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
* @see \Drupal\views\Render\ViewsRenderPipelineMarkup
|
||||
* @see twig_render_template()
|
||||
* @see sanitization
|
||||
* @see theme_render
|
||||
*/
|
||||
interface MarkupInterface extends \JsonSerializable {
|
||||
|
||||
/**
|
||||
* Returns markup.
|
||||
*
|
||||
* @return string
|
||||
* The markup.
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
}
|
|
@ -2,17 +2,19 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Component\Utility\SafeStringTrait.
|
||||
* Contains \Drupal\Component\Render\MarkupTrait.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\Utility;
|
||||
namespace Drupal\Component\Render;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
|
||||
/**
|
||||
* Implements SafeStringInterface and Countable for rendered objects.
|
||||
* Implements MarkupInterface and Countable for rendered objects.
|
||||
*
|
||||
* @see \Drupal\Component\Utility\SafeStringInterface
|
||||
* @see \Drupal\Component\Render\MarkupInterface
|
||||
*/
|
||||
trait SafeStringTrait {
|
||||
trait MarkupTrait {
|
||||
|
||||
/**
|
||||
* The safe string.
|
||||
|
@ -22,20 +24,20 @@ trait SafeStringTrait {
|
|||
protected $string;
|
||||
|
||||
/**
|
||||
* Creates a SafeString object if necessary.
|
||||
* Creates a Markup 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.
|
||||
* Markup object. If $string is an object that implements MarkupInterface 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
|
||||
* @return string|\Drupal\Component\Render\MarkupInterface
|
||||
* A safe string.
|
||||
*/
|
||||
public static function create($string) {
|
||||
if ($string instanceof SafeStringInterface) {
|
||||
if ($string instanceof MarkupInterface) {
|
||||
return $string;
|
||||
}
|
||||
$string = (string) $string;
|
||||
|
@ -48,7 +50,7 @@ trait SafeStringTrait {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the string version of the SafeString object.
|
||||
* Returns the string version of the Markup object.
|
||||
*
|
||||
* @return string
|
||||
* The safe string content.
|
36
core/lib/Drupal/Component/Render/OutputStrategyInterface.php
Normal file
36
core/lib/Drupal/Component/Render/OutputStrategyInterface.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Component\Render\OutputStrategyInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\Render;
|
||||
|
||||
/**
|
||||
* Provides an output strategy that formats HTML strings for a given context.
|
||||
*
|
||||
* Output strategies assist in transforming HTML strings into strings that are
|
||||
* appropriate for a given context (e.g. plain-text), through performing the
|
||||
* relevant formatting. No santization is applied.
|
||||
*/
|
||||
interface OutputStrategyInterface {
|
||||
|
||||
/**
|
||||
* Transforms a given HTML string into to a context-appropriate output string.
|
||||
*
|
||||
* This transformation consists of performing the formatting appropriate to
|
||||
* a given output context (e.g., plain-text email subjects, HTML attribute
|
||||
* values).
|
||||
*
|
||||
* @param string|object $string
|
||||
* An HTML string or an object with a ::__toString() magic method returning
|
||||
* HTML markup. The source HTML markup is considered ready for output into
|
||||
* HTML fragments and thus already properly escaped and sanitized.
|
||||
*
|
||||
* @return string
|
||||
* A new string that is formatted according to the output strategy.
|
||||
*/
|
||||
public static function renderFromHtml($string);
|
||||
|
||||
}
|
29
core/lib/Drupal/Component/Render/PlainTextOutput.php
Normal file
29
core/lib/Drupal/Component/Render/PlainTextOutput.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Component\Render\PlainTextOutput.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\Render;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
|
||||
/**
|
||||
* Provides an output strategy for transforming HTML into simple plain text.
|
||||
*
|
||||
* Use this when rendering a given HTML string into a plain text string that
|
||||
* does not need special formatting, such as a label or an email subject.
|
||||
*
|
||||
* Returns a string with HTML tags stripped and HTML entities decoded suitable
|
||||
* for email or other non-HTML contexts.
|
||||
*/
|
||||
class PlainTextOutput implements OutputStrategyInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function renderFromHtml($string) {
|
||||
return Html::decodeEntities(strip_tags((string) $string));
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
48
core/lib/Drupal/Component/Utility/ToStringTrait.php
Normal file
48
core/lib/Drupal/Component/Utility/ToStringTrait.php
Normal 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();
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Reference in a new issue