diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 82699ebd2cba44a8d6f9d1c45031bfaa824104a9..9b91430881a06ed9fc8a158bb516d633f86e6146 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -1163,11 +1163,36 @@ function drupal_unpack($obj, $field = 'data') { /** * Encode special characters in a plain-text string for display as HTML. * - * Uses drupal_validate_utf8 to prevent cross site scripting attacks on + * Also validates strings as UTF-8 to prevent cross site scripting attacks on * Internet Explorer 6. + * + * @param $text + * The text to be checked or processed. + * @return + * An HTML safe version of $text, or an empty string if $text is not + * valid UTF-8. + * @see drupal_validate_utf8(). */ function check_plain($text) { - return drupal_validate_utf8($text) ? htmlspecialchars($text, ENT_QUOTES) : ''; + // We do not want to use drupal_static() since PHP version will never change + // during a request. + static $php525; + + if (!isset($php525)) { + $php525 = version_compare(PHP_VERSION, '5.2.5', '>='); + } + // We duplicate the preg_match() to validate strings as UTF-8 from + // drupal_validate_utf8() here. This avoids the overhead of an additional + // function call, since check_plain() may be called hundreds of times during + // a request. For PHP 5.2.5+, this check for valid UTF-8 should be handled + // internally by PHP in htmlspecialchars(). + // @see http://www.php.net/releases/5_2_5.php + // @todo remove this when support for either IE6 or PHP < 5.2.5 is dropped. + + if ($php525) { + return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); + } + return (preg_match('/^./us', $text) == 1) ? htmlspecialchars($text, ENT_QUOTES, 'UTF-8') : ''; } /** diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test index d8bb13cc4db43a2be5a13e73539be0ac6d8542a6..f1bd54ac1c5a9fca6cba3d0c20cb13023a0e4820 100644 --- a/modules/simpletest/tests/common.test +++ b/modules/simpletest/tests/common.test @@ -311,6 +311,42 @@ class CommonURLUnitTest extends DrupalUnitTestCase { } } +/** + * Tests for the check_plain() and filter_xss() functions. + */ +class CommonXssUnitTest extends DrupalUnitTestCase { + + public static function getInfo() { + return array( + 'name' => 'String filtering tests', + 'description' => 'Confirm that check_plain() and filter_xss() work correctly, including invalid multi-byte sequences.', + 'group' => 'System', + ); + } + + /** + * Check that invalid multi-byte sequences are rejected. + */ + function testInvalidMultiByte() { + $text = check_plain("Foo\xC0barbaz"); + $this->assertEqual($text, '', 'check_plain() rejects invalid sequence "Foo\xC0barbaz"'); + $text = check_plain("Fooÿñ"); + $this->assertEqual($text, "Fooÿñ", 'check_plain() accepts valid sequence "Fooÿñ"'); + $text = filter_xss("Foo\xC0barbaz"); + $this->assertEqual($text, '', 'filter_xss() rejects invalid sequence "Foo\xC0barbaz"'); + $text = filter_xss("Fooÿñ"); + $this->assertEqual($text, "Fooÿñ", 'filter_xss() accepts valid sequence Fooÿñ'); + } + + /** + * Check that special characters are escaped. + */ + function testEscaping() { + $text = check_plain("