diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php index c46f01410d..6dd8faf440 100644 --- a/src/wp-includes/formatting.php +++ b/src/wp-includes/formatting.php @@ -688,24 +688,7 @@ function _wp_specialchars( $string, $quote_style = ENT_NOQUOTES, $charset = fals $quote_style = ENT_NOQUOTES; } - // Handle double encoding ourselves - if ( $double_encode ) { - $string = @htmlspecialchars( $string, $quote_style, $charset ); - } else { - // Decode & into & - $string = wp_specialchars_decode( $string, $_quote_style ); - - // Guarantee every &entity; is valid or re-encode the & - $string = wp_kses_normalize_entities( $string ); - - // Now re-encode everything except &entity; - $string = preg_split( '/(&#?x?[0-9a-z]+;)/i', $string, -1, PREG_SPLIT_DELIM_CAPTURE ); - - for ( $i = 0, $c = count( $string ); $i < $c; $i += 2 ) { - $string[$i] = @htmlspecialchars( $string[$i], $quote_style, $charset ); - } - $string = implode( '', $string ); - } + $string = @htmlspecialchars( $string, $quote_style, $charset, $double_encode ); // Backwards compatibility if ( 'single' === $_quote_style ) diff --git a/tests/phpunit/tests/formatting/EscAttr.php b/tests/phpunit/tests/formatting/EscAttr.php index 35ea2f54a5..55ca837d05 100644 --- a/tests/phpunit/tests/formatting/EscAttr.php +++ b/tests/phpunit/tests/formatting/EscAttr.php @@ -26,7 +26,7 @@ class Tests_Formatting_EscAttr extends WP_UnitTestCase { } function test_esc_attr_amp() { - $out = esc_attr( 'foo & bar &baz; '' ); - $this->assertEquals( "foo & bar &baz; '", $out ); + $out = esc_attr( 'foo & bar &baz;  ' ); + $this->assertEquals( "foo & bar &baz;  ", $out ); } } diff --git a/tests/phpunit/tests/formatting/EscHtml.php b/tests/phpunit/tests/formatting/EscHtml.php index 101692622e..291d8b0885 100644 --- a/tests/phpunit/tests/formatting/EscHtml.php +++ b/tests/phpunit/tests/formatting/EscHtml.php @@ -34,7 +34,7 @@ class Tests_Formatting_EscHtml extends WP_UnitTestCase { function test_ignores_existing_entities() { $source = '& £ " &'; - $res = '& £ " &'; + $res = '& £ " &'; $this->assertEquals( $res, esc_html($source) ); } } diff --git a/tests/phpunit/tests/formatting/JSEscape.php b/tests/phpunit/tests/formatting/JSEscape.php index 6ec3892982..286bf616e2 100644 --- a/tests/phpunit/tests/formatting/JSEscape.php +++ b/tests/phpunit/tests/formatting/JSEscape.php @@ -23,13 +23,13 @@ class Tests_Formatting_JSEscape extends WP_UnitTestCase { } function test_js_escape_amp() { - $out = esc_js('foo & bar &baz; ''); - $this->assertEquals("foo & bar &baz; '", $out); + $out = esc_js('foo & bar &baz;  '); + $this->assertEquals("foo & bar &baz;  ", $out); } function test_js_escape_quote_entity() { $out = esc_js('foo ' bar ' baz &'); - $this->assertEquals("foo \\' bar \\' baz &", $out); + $this->assertEquals("foo \\' bar \\' baz &", $out); } function test_js_no_carriage_return() { diff --git a/tests/phpunit/tests/formatting/WPSpecialchars.php b/tests/phpunit/tests/formatting/WPSpecialchars.php index 6c8765d4db..2844a1e220 100644 --- a/tests/phpunit/tests/formatting/WPSpecialchars.php +++ b/tests/phpunit/tests/formatting/WPSpecialchars.php @@ -17,6 +17,10 @@ class Tests_Formatting_WPSpecialchars extends WP_UnitTestCase { // Allowed entities should be unchanged foreach ( $allowedentitynames as $ent ) { + if ( 'apos' == $ent ) { + // But for some reason, PHP doesn't allow ' + continue; + } $ent = '&' . $ent . ';'; $this->assertEquals( $ent, _wp_specialchars( $ent ) ); } @@ -39,4 +43,58 @@ class Tests_Formatting_WPSpecialchars extends WP_UnitTestCase { $this->assertEquals( '"'hello!'"', _wp_specialchars($source, true) ); $this->assertEquals( $source, _wp_specialchars($source) ); } + + /** + * Check some of the double-encoding features for entity references. + * + * @ticket 17780 + * @dataProvider data_double_encoding + */ + function test_double_encoding( $input, $output ) { + return $this->assertEquals( $output, _wp_specialchars( $input, ENT_NOQUOTES, false, true ) ); + } + + function data_double_encoding() { + return array( + array( + 'This & that, this & that, — " " Ú   " " " " " $ ×', + 'This & that, this &amp; that, &#8212; &quot; &QUOT; &Uacute; &nbsp; &#34; &#034; &#0034; &#x00022; &#x22; &dollar; &times;', + ), + array( + '&& && && &;', + '&& &&amp; &amp;&amp; &amp;;', + ), + array( + '&garbage; &***; &aaaa; &0000; &####; &;;', + '&garbage; &***; &aaaa; &0000; &####; &;;', + ), + ); + } + + /** + * Check some of the double-encoding features for entity references. + * + * @ticket 17780 + * @dataProvider data_no_double_encoding + */ + function test_no_double_encoding( $input, $output ) { + return $this->assertEquals( $output, _wp_specialchars( $input, ENT_NOQUOTES, false, false ) ); + } + + function data_no_double_encoding() { + return array( + array( + 'This & that, this & that, — " " Ú   " " " " " $ ×', + 'This & that, this & that, — " &QUOT; Ú   " " " " " &dollar; ×', + ), + array( + '&& && && &;', + '&& && && &;', + ), + array( + '&garbage; &***; &aaaa; &0000; &####; &;;', + '&garbage; &***; &aaaa; &0000; &####; &;;', + ), + ); + } }