Commit 0a67ffba authored by effulgentsia's avatar effulgentsia

Issue #2575615 by alexpott, pwolanin, stefan.r, catch, dawehner, effulgentsia,...

Issue #2575615 by alexpott, pwolanin, stefan.r, catch, dawehner, effulgentsia, xjm, David_Rothstein, iMiksu, lauriii, joelpittet: Introduce HtmlEscapedText and remove SafeMarkup::setMultiple() and SafeMarkup::getAll() and remove the static safeStrings list
parent 3884a586
......@@ -47,14 +47,7 @@ function _batch_page(Request $request) {
return new RedirectResponse(\Drupal::url('<front>', [], ['absolute' => TRUE]));
}
}
// Restore safe strings from previous batches.
// This is safe because we are passing through the known safe values from
// SafeMarkup::getAll(). See _batch_shutdown().
// @todo Ensure we are not storing an excessively large string list in:
// https://www.drupal.org/node/2295823
if (!empty($batch['safe_strings'])) {
SafeMarkup::setMultiple($batch['safe_strings']);
}
// Register database update for the end of processing.
drupal_register_shutdown_function('_batch_shutdown');
......@@ -521,10 +514,6 @@ function _batch_finished() {
*/
function _batch_shutdown() {
if ($batch = batch_get()) {
// Update safe strings.
// @todo Ensure we are not storing an excessively large string list in:
// https://www.drupal.org/node/2295823
$batch['safe_strings'] = SafeMarkup::getAll();
\Drupal::service('batch.storage')->update($batch);
}
}
......@@ -6,7 +6,6 @@
*/
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Database\Database;
......@@ -701,8 +700,6 @@ function template_preprocess_form_element_label(&$variables) {
* - css: Array of paths to CSS files to be used on the progress page.
* - url_options: options passed to url() when constructing redirect URLs for
* the batch.
* - safe_strings: Internal use only. Used to store and retrieve strings
* marked as safe between requests.
* - progressive: A Boolean that indicates whether or not the batch needs to
* run progressively. TRUE indicates that the batch will run in more than
* one run. FALSE (default) indicates that the batch will finish in a single
......@@ -854,11 +851,6 @@ function batch_process($redirect = NULL, Url $url = NULL, $redirect_callback = N
$request->query->remove('destination');
}
// Store safe strings.
// @todo Ensure we are not storing an excessively large string list in:
// https://www.drupal.org/node/2295823
$batch['safe_strings'] = SafeMarkup::getAll();
// Store the batch.
\Drupal::service('batch.storage')->create($batch);
......
<?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();
}
}
......@@ -31,6 +31,9 @@
* @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 {
......
......@@ -7,26 +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()
......@@ -35,100 +25,23 @@
*/
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\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.
*/
public static function isSafe($string, $strategy = 'html') {
// Do the instanceof checks first to save unnecessarily casting the object
// to a string.
return $string instanceOf MarkupInterface || 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.
* @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 getAll() {
return static::$safeStrings;
public static function isSafe($string, $strategy = 'html') {
return $string instanceOf MarkupInterface;
}
/**
......@@ -140,13 +53,10 @@ public static function getAll() {
* @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.
*
* @ingroup sanitization
* @return \Drupal\Component\Render\HtmlEscapedText
* An HtmlEscapedText object that escapes when rendered to string.
*
* @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
......@@ -156,9 +66,7 @@ public static function getAll() {
* @see drupal_validate_utf8()
*/
public static function checkPlain($text) {
$string = Html::escape($text);
static::$safeStrings[$string]['html'] = TRUE;
return $string;
return new HtmlEscapedText($text);
}
/**
......@@ -176,8 +84,6 @@ public static function checkPlain($text) {
* 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
*
......
......@@ -169,14 +169,6 @@ protected function loadCachedFormState($form_build_id, FormStateInterface $form_
require_once $this->root . '/' . $file;
}
}
// Retrieve the list of safe strings and store it for this request. The
// safety of these strings has already been determined in ::setCache().
// @todo Ensure we are not storing an excessively large string list
// in: https://www.drupal.org/node/2295823
$build_info += ['safe_strings' => []];
SafeMarkup::setMultiple($build_info['safe_strings']);
unset($build_info['safe_strings']);
$form_state->setBuildInfo($build_info);
}
}
......@@ -206,11 +198,6 @@ public function setCache($form_build_id, $form, FormStateInterface $form_state)
$this->keyValueExpirableFactory->get('form')->setWithExpire($form_build_id, $form, $expire);
}
// Store the known list of safe strings for form re-use.
// @todo Ensure we are not storing an excessively large string list in:
// https://www.drupal.org/node/2295823
$form_state->addBuildInfo('safe_strings', SafeMarkup::getAll());
if ($data = $form_state->getCacheableArray()) {
$this->keyValueExpirableFactory->get('form_state')->setWithExpire($form_build_id, $data, $expire);
}
......
......@@ -7,8 +7,8 @@
namespace Drupal\Core\Utility;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\HtmlEscapedText;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Cache\CacheBackendInterface;
......@@ -207,7 +207,7 @@ public function replace($text, array $data = array(), array $options = array(),
// Escape the tokens, unless they are explicitly markup.
foreach ($replacements as $token => $value) {
$replacements[$token] = SafeMarkup::isSafe($value) ? $value : Html::escape($value);
$replacements[$token] = $value instanceof MarkupInterface ? $value : new HtmlEscapedText($value);
}
// Optionally alter the list of replacement values.
......
......@@ -54,12 +54,14 @@ function testBatchForm() {
// Batch 0: no operation.
$edit = array('batch' => 'batch_0');
$this->drupalPostForm('batch-test', $edit, 'Submit');
$this->assertNoEscaped('<', 'No escaped markup is present.');
$this->assertBatchMessages($this->_resultMessages('batch_0'), 'Batch with no operation performed successfully.');
$this->assertText('Redirection successful.', 'Redirection after batch execution is correct.');
// Batch 1: several simple operations.
$edit = array('batch' => 'batch_1');
$this->drupalPostForm('batch-test', $edit, 'Submit');
$this->assertNoEscaped('<', 'No escaped markup is present.');
$this->assertBatchMessages($this->_resultMessages('batch_1'), 'Batch with simple operations performed successfully.');
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), 'Execution order was correct.');
$this->assertText('Redirection successful.', 'Redirection after batch execution is correct.');
......@@ -67,6 +69,7 @@ function testBatchForm() {
// Batch 2: one multistep operation.
$edit = array('batch' => 'batch_2');
$this->drupalPostForm('batch-test', $edit, 'Submit');
$this->assertNoEscaped('<', 'No escaped markup is present.');
$this->assertBatchMessages($this->_resultMessages('batch_2'), 'Batch with multistep operation performed successfully.');
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_2'), 'Execution order was correct.');
$this->assertText('Redirection successful.', 'Redirection after batch execution is correct.');
......@@ -74,6 +77,7 @@ function testBatchForm() {
// Batch 3: simple + multistep combined.
$edit = array('batch' => 'batch_3');
$this->drupalPostForm('batch-test', $edit, 'Submit');
$this->assertNoEscaped('<', 'No escaped markup is present.');
$this->assertBatchMessages($this->_resultMessages('batch_3'), 'Batch with simple and multistep operations performed successfully.');
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_3'), 'Execution order was correct.');
$this->assertText('Redirection successful.', 'Redirection after batch execution is correct.');
......@@ -81,6 +85,7 @@ function testBatchForm() {
// Batch 4: nested batch.
$edit = array('batch' => 'batch_4');
$this->drupalPostForm('batch-test', $edit, 'Submit');
$this->assertNoEscaped('<', 'No escaped markup is present.');
$this->assertBatchMessages($this->_resultMessages('batch_4'), 'Nested batch performed successfully.');
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_4'), 'Execution order was correct.');
$this->assertText('Redirection successful.', 'Redirection after batch execution is correct.');
......@@ -91,6 +96,7 @@ function testBatchForm() {
*/
function testBatchFormMultistep() {
$this->drupalGet('batch-test/multistep');
$this->assertNoEscaped('<', 'No escaped markup is present.');
$this->assertText('step 1', 'Form is displayed in step 1.');
// First step triggers batch 1.
......@@ -98,12 +104,14 @@ function testBatchFormMultistep() {
$this->assertBatchMessages($this->_resultMessages('batch_1'), 'Batch for step 1 performed successfully.');
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), 'Execution order was correct.');
$this->assertText('step 2', 'Form is displayed in step 2.');
$this->assertNoEscaped('<', 'No escaped markup is present.');
// Second step triggers batch 2.
$this->drupalPostForm(NULL, array(), 'Submit');
$this->assertBatchMessages($this->_resultMessages('batch_2'), 'Batch for step 2 performed successfully.');
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_2'), 'Execution order was correct.');
$this->assertText('Redirection successful.', 'Redirection after batch execution is correct.');
$this->assertNoEscaped('<', 'No escaped markup is present.');
}
/**
......
......@@ -40,7 +40,7 @@ function testDrupalSetMessage() {
// Ensure Markup objects are rendered as expected.
$this->assertRaw('Markup with <em>markup!</em>');
$this->assertUniqueText('Markup with markup!');
$this->assertRaw('SafeString2 with <em>markup!</em>');
$this->assertRaw('Markup2 with <em>markup!</em>');
// Ensure when the same message is of different types it is not duplicated.
$this->assertUniqueText('Non duplicate Markup / string.');
......
......@@ -119,7 +119,7 @@ public function drupalSetMessageTest() {
// Test duplicate Markup messages.
drupal_set_message(Markup::create('Markup with <em>markup!</em>'));
// Ensure that multiple Markup messages work.
drupal_set_message(Markup::create('SafeString2 with <em>markup!</em>'));
drupal_set_message(Markup::create('Markup2 with <em>markup!</em>'));
// Test mixing of types.
drupal_set_message(Markup::create('Non duplicate Markup / string.'));
......
......@@ -46,8 +46,6 @@
<listeners>
<listener class="\Drupal\Tests\Listeners\DrupalStandardsListener">
</listener>
<listener class="\Drupal\Tests\Listeners\SafeMarkupSideEffects">
</listener>
</listeners>
<!-- Filter for coverage reports. -->
<filter>
......
<?php
/**
* @file
* Contains \Drupal\Tests\Component\Render\HtmlEscapedTextTest.
*/
namespace Drupal\Tests\Component\Render;
use Drupal\Component\Render\HtmlEscapedText;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Tests\UnitTestCase;
/**
* Tests the HtmlEscapedText class.
*
* @coversDefaultClass \Drupal\Component\Render\HtmlEscapedText
* @group utility
*/
class HtmlEscapedTextTest extends UnitTestCase {
/**
* @covers ::__toString
* @covers ::jsonSerialize
*
* @dataProvider providerToString
*/
public function testToString($text, $expected, $message) {
$escapeable_string = new HtmlEscapedText($text);
$this->assertEquals($expected, (string) $escapeable_string, $message);
$this->assertEquals($expected, $escapeable_string->jsonSerialize());
}
/**
* Data provider for testToString().
*
* @see testToString()
*/
function providerToString() {
// Checks that invalid multi-byte sequences are escaped.
$tests[] = array("Foo\xC0barbaz", 'Foo�barbaz', 'Escapes invalid sequence "Foo\xC0barbaz"');
$tests[] = array("\xc2\"", '�&quot;', 'Escapes invalid sequence "\xc2\""');
$tests[] = array("Fooÿñ", "Fooÿñ", 'Does not escape valid sequence "Fooÿñ"');
// Checks that special characters are escaped.
$script_tag = $this->prophesize(MarkupInterface::class);
$script_tag->__toString()->willReturn('<script>');
$script_tag = $script_tag->reveal();
$tests[] = array($script_tag, '&lt;script&gt;', 'Escapes &lt;script&gt; even inside an object that implements MarkupInterface.');
$tests[] = array("<script>", '&lt;script&gt;', 'Escapes &lt;script&gt;');
$tests[] = array('<>&"\'', '&lt;&gt;&amp;&quot;&#039;', 'Escapes reserved HTML characters.');
$specialchars = $this->prophesize(MarkupInterface::class);
$specialchars->__toString()->willReturn('<>&"\'');
$specialchars = $specialchars->reveal();
$tests[] = array($specialchars, '&lt;&gt;&amp;&quot;&#039;', 'Escapes reserved HTML characters even inside an object that implements MarkupInterface.');
return $tests;
}
/**
* @covers ::count
*/
public function testCount() {
$string = 'Can I please have a <em>kitten</em>';
$escapeable_string = new HtmlEscapedText($string);
$this->assertEquals(strlen($string), $escapeable_string->count());
}
}
......@@ -7,6 +7,7 @@
namespace Drupal\Tests\Component\Utility;
use Drupal\Component\Render\HtmlEscapedText;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Render\MarkupTrait;
......@@ -30,85 +31,6 @@ protected function tearDown() {
UrlHelper::setAllowedProtocols(['http', 'https']);
}
/**
* Helper function to add a string to the safe list for testing.
*
* @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 ::isSafe
*/
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().
*/
public function providerSet() {
// Checks that invalid multi-byte sequences are escaped.
$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::setMultiple().
* @dataProvider providerSet
*
* @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 testSet($text, $message) {
SafeMarkup::setMultiple([$text => ['html' => TRUE]]);
$this->assertTrue(SafeMarkup::isSafe($text), $message);
}
/**
* Tests SafeMarkup::isSafe() with different objects.
*
......@@ -122,71 +44,60 @@ public function testIsSafe() {
}
/**
* Tests SafeMarkup::setMultiple().
*
* @covers ::setMultiple
*/
public function testSetMultiple() {
$texts = array(
'multistring0' => array('html' => TRUE),
'multistring1' => array('all' => TRUE),
);
SafeMarkup::setMultiple($texts);
foreach ($texts as $string => $providers) {
$this->assertTrue(SafeMarkup::isSafe($string), 'The value has been marked as safe for html');
}
}
/**
* Tests SafeMarkup::setMultiple().
*
* Only TRUE may be passed in as the value.
* Tests SafeMarkup::checkPlain().
*
* @covers ::setMultiple
* @dataProvider providerCheckPlain
* @covers ::checkPlain
*
* @expectedException \UnexpectedValueException
* @param string $text
* The text to provide to SafeMarkup::checkPlain().
* @param string $expected
* The expected output from the function.
* @param string $message
* The message to provide as output for the test.
*/
public function testInvalidSetMultiple() {
$texts = array(
'invalidstring0' => array('html' => 1),
);
SafeMarkup::setMultiple($texts);
function testCheckPlain($text, $expected, $message) {
$result = SafeMarkup::checkPlain($text);
$this->assertTrue($result instanceof HtmlEscapedText);
$this->assertEquals($expected, $result, $message);
}
/**
* Tests SafeMarkup::checkPlain().
* Tests Drupal\Component\Render\HtmlEscapedText.
*
* Verifies that the result of SafeMarkup::checkPlain() is the same as using
* HtmlEscapedText directly.
*
* @dataProvider providerCheckPlain
* @covers ::checkPlain
*
* @param string $text
* The text to provide to SafeMarkup::checkPlain().
* The text to provide to the HtmlEscapedText constructor.
* @param string $expected
* The expected output from the function.
* @param string $message
* The message to provide as output for the test.
* @param bool $ignorewarnings
* Whether or not to ignore PHP 5.3+ invalid multibyte sequence warnings.
*/
function testCheckPlain($text, $expected, $message, $ignorewarnings = FALSE) {
$result = $ignorewarnings ? @SafeMarkup::checkPlain($text) : SafeMarkup::checkPlain($text);
function testHtmlEscapedText($text, $expected, $message) {
$result = new HtmlEscapedText($text);
$this->assertEquals($expected, $result, $message);
}
/**
* Data provider for testCheckPlain().
* Data provider for testCheckPlain() and testEscapeString().
*
* @see testCheckPlain()
*/
function providerCheckPlain() {
// Checks that invalid multi-byte sequences are escaped.
$tests[] = array("Foo\xC0barbaz", 'Foo�barbaz', 'SafeMarkup::checkPlain() escapes invalid sequence "Foo\xC0barbaz"', TRUE);
$tests[] = array("\xc2\"", '�&quot;', 'SafeMarkup::checkPlain() escapes invalid sequence "\xc2\""', TRUE);
$tests[] = array("Fooÿñ", "Fooÿñ", 'SafeMarkup::checkPlain() does not escape valid sequence "Fooÿñ"');
$tests[] = array("Foo\xC0barbaz", 'Foo�barbaz', 'Escapes invalid sequence "Foo\xC0barbaz"');
$tests[] = array("\xc2\"", '�&quot;', 'Escapes invalid sequence "\xc2\""');
$tests[] = array("Fooÿñ", "Fooÿñ", 'Does not escape valid sequence "Fooÿñ"');
// Checks that special characters are escaped.
$tests[] = array("<script>", '&lt;script&gt;', 'SafeMarkup::checkPlain() escapes &lt;script&gt;');
$tests[] = array('<>&"\'', '&lt;&gt;&amp;&quot;&#039;', 'SafeMarkup::checkPlain() escapes reserved HTML characters.');
$tests[] = array(SafeMarkupTestMarkup::create("<script>"), '&lt;script&gt;', 'Escapes &lt;script&gt; even inside an object that implements MarkupInterface.');
$tests[] = array("<script>", '&lt;script&gt;', 'Escapes &lt;script&gt;');
$tests[] = array('<>&"\'', '&lt;&gt;&amp;&quot;&#039;', 'Escapes reserved HTML characters.');
$tests[] = array(SafeMarkupTestMarkup::create('<>&"\''), '&lt;&gt;&amp;&quot;&#039;', 'Escapes reserved HTML characters even inside an object that implements MarkupInterface.');
return $tests;
}
......@@ -266,10 +177,7 @@ public function __toString() {
}
/**
* Marks text as safe.
*
* SafeMarkupTestMarkup is used to mark text as safe because
* SafeMarkup::$safeStrings is a global static that affects all tests.
* Marks an object's __toString() method as returning markup.
*/
class SafeMarkupTestMarkup implements MarkupInterface {
use MarkupTrait;
......