diff --git a/core/lib/Drupal/Component/Utility/SafeMarkup.php b/core/lib/Drupal/Component/Utility/SafeMarkup.php index d20ad6ba08a7a631a04ad5778110342bd7768740..3020bbe5711c3b7fcf85661570db20bf7db8e127 100644 --- a/core/lib/Drupal/Component/Utility/SafeMarkup.php +++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php @@ -35,58 +35,29 @@ 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(); /** - * Adds a string to a list of strings marked as secure. - * - * 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::set('<'); - * @endcode - * or: - * @code - * SafeMarkup::set('<script>'); - * @endcode + * Checks if a string is safe to output. * - * @param string $string - * The content to be marked as secure. + * @param string|\Drupal\Component\Utility\SafeStringInterface $string + * The content to be checked. * @param string $strategy - * The escaping strategy used for this string. Two values are supported - * by default: + * 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. * - * @return string - * The input string that was marked as safe. - */ - public static function set($string, $strategy = 'html') { - $string = (string) $string; - static::$safeStrings[$string][$strategy] = TRUE; - return $string; - } - - /** - * Checks if a string is safe to output. - * - * @param string|\Drupal\Component\Utility\SafeStringInterface $string - * The content to be checked. - * @param string $strategy - * The escaping strategy. See self::set(). Defaults to 'html'. - * * @return bool * TRUE if the string has been marked secure, FALSE otherwise. */ @@ -100,12 +71,29 @@ public static function isSafe($string, $strategy = 'html') { /** * Adds previously retrieved known safe strings to the safe string list. * - * This is useful for the batch and form APIs, where it is important to - * preserve the safe markup state across page requests. The strings will be - * added to any safe strings already marked for the current request. + * 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 * diff --git a/core/lib/Drupal/Component/Utility/SafeStringInterface.php b/core/lib/Drupal/Component/Utility/SafeStringInterface.php index 45d536d15034ed1f4ca0a32f0c05c7a31af4c7be..181d1d67debdbfb806a5cdf0b1d23228f75e833c 100644 --- a/core/lib/Drupal/Component/Utility/SafeStringInterface.php +++ b/core/lib/Drupal/Component/Utility/SafeStringInterface.php @@ -29,7 +29,6 @@ * and to fast render fields. * * @see \Drupal\Component\Utility\SafeStringTrait - * @see \Drupal\Component\Utility\SafeMarkup::set() * @see \Drupal\Component\Utility\SafeMarkup::isSafe() * @see \Drupal\Core\Template\TwigExtension::escapeFilter() */ diff --git a/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php index ec83229b887a08adb01cb16bc6d8a5def9796dbf..fae15bb55c07419b9512e8cd8749eb9baca19c48 100644 --- a/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php +++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php @@ -21,54 +21,81 @@ class SafeMarkupTest extends UnitTestCase { /** - * Tests SafeMarkup::set() and SafeMarkup::isSafe(). + * Helper function to add a string to the safe list for testing. * - * @dataProvider providerSet - * - * @param string $text - * The text or object to provide to SafeMarkup::set(). - * @param string $message - * The message to provide as output for the test. + * @param string $string + * The content to be marked as secure. + * @param string $strategy + * The escaping strategy used for this string. Two values 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. + * + * @return string + * The input string that was marked as safe. + */ + protected function safeMarkupSet($string, $strategy = 'html') { + $reflected_class = new \ReflectionClass('\Drupal\Component\Utility\SafeMarkup'); + $reflected_property = $reflected_class->getProperty('safeStrings'); + $reflected_property->setAccessible(true); + $current_value = $reflected_property->getValue(); + $current_value[$string][$strategy] = TRUE; + $reflected_property->setValue($current_value); + return $string; + } + + /** + * Tests SafeMarkup::isSafe() with different providers. * - * @covers ::set + * @covers ::isSafe */ - public function testSet($text, $message) { - $returned = SafeMarkup::set($text); - $this->assertTrue(is_string($returned), 'The return value of SafeMarkup::set() is really a string'); - $this->assertEquals($returned, $text, 'The passed in value should be equal to the string value according to PHP'); - $this->assertTrue(SafeMarkup::isSafe($text), $message); - $this->assertTrue(SafeMarkup::isSafe($returned), 'The return value has been marked as safe'); + public function testStrategy() { + $returned = $this->safeMarkupSet('string0', 'html'); + $this->assertTrue(SafeMarkup::isSafe($returned), 'String set with "html" provider is safe for default (html)'); + $returned = $this->safeMarkupSet('string1', 'all'); + $this->assertTrue(SafeMarkup::isSafe($returned), 'String set with "all" provider is safe for default (html)'); + $returned = $this->safeMarkupSet('string2', 'css'); + $this->assertFalse(SafeMarkup::isSafe($returned), 'String set with "css" provider is not safe for default (html)'); + $returned = $this->safeMarkupSet('string3'); + $this->assertFalse(SafeMarkup::isSafe($returned, 'all'), 'String set with "html" provider is not safe for "all"'); } /** * Data provider for testSet(). - * - * @see testSet() */ public function providerSet() { // Checks that invalid multi-byte sequences are escaped. - $tests[] = array("Foo\xC0barbaz", 'Foo�barbaz', 'Invalid sequence "Foo\xC0barbaz" is escaped', TRUE); - $tests[] = array("Fooÿñ", 'SafeMarkup::set() does not escape valid sequence "Fooÿñ"'); - $tests[] = array(new TextWrapper("Fooÿñ"), 'SafeMarkup::set() does not escape valid sequence "Fooÿñ" in an object implementing __toString()'); - $tests[] = array("<div>", 'SafeMarkup::set() does not escape HTML'); + $tests[] = array( + 'Foo�barbaz', + 'SafeMarkup::setMarkup() functions with valid sequence "Foo�barbaz"', + TRUE + ); + $tests[] = array( + "Fooÿñ", + 'SafeMarkup::setMarkup() functions with valid sequence "Fooÿñ"' + ); + $tests[] = array("<div>", 'SafeMarkup::setMultiple() does not escape HTML'); return $tests; } /** - * Tests SafeMarkup::set() and SafeMarkup::isSafe() with different providers. + * Tests SafeMarkup::setMultiple(). + * @dataProvider providerSet * - * @covers ::isSafe + * @param string $text + * The text or object to provide to SafeMarkup::setMultiple(). + * @param string $message + * The message to provide as output for the test. + * + * @covers ::setMultiple */ - public function testStrategy() { - $returned = SafeMarkup::set('string0', 'html'); - $this->assertTrue(SafeMarkup::isSafe($returned), 'String set with "html" provider is safe for default (html)'); - $returned = SafeMarkup::set('string1', 'all'); - $this->assertTrue(SafeMarkup::isSafe($returned), 'String set with "all" provider is safe for default (html)'); - $returned = SafeMarkup::set('string2', 'css'); - $this->assertFalse(SafeMarkup::isSafe($returned), 'String set with "css" provider is not safe for default (html)'); - $returned = SafeMarkup::set('string3'); - $this->assertFalse(SafeMarkup::isSafe($returned, 'all'), 'String set with "html" provider is not safe for "all"'); + public function testSet($text, $message) { + SafeMarkup::setMultiple([$text => ['html' => TRUE]]); + $this->assertTrue(SafeMarkup::isSafe($text), $message); } /** @@ -217,7 +244,7 @@ public function __toString() { * Marks text as safe. * * SafeMarkupTestSafeString is used to mark text as safe because - * SafeMarkup::set() is a global static that affects all tests. + * SafeMarkup::$safeStrings is a global static that affects all tests. */ class SafeMarkupTestSafeString implements SafeStringInterface { use SafeStringTrait;