From 15c1c2f130b4853fc098a8920179e322a79c0ba9 Mon Sep 17 00:00:00 2001 From: Scott Taylor Date: Fri, 15 Nov 2013 02:45:39 +0000 Subject: [PATCH] Don't place smilies inside of pre or code tags. Don't skip smilie after a smilie with an 8 in it. Fix regular expression used for smiley translations to work when there is only one registered emoticon. Props solarissmoke, soulseekah, mdbitz, yonasy. ht to mdbitz for the Unit Tests and a comprehensive patch. Fixes #16448, #20124, #25303. git-svn-id: https://develop.svn.wordpress.org/trunk@26191 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/formatting.php | 32 ++- src/wp-includes/functions.php | 8 +- tests/phpunit/tests/formatting/Smilies.php | 296 +++++++++++++++++---- 3 files changed, 275 insertions(+), 61 deletions(-) diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php index c120b61334..56aac4ca29 100644 --- a/src/wp-includes/formatting.php +++ b/src/wp-includes/formatting.php @@ -1793,18 +1793,36 @@ function translate_smiley( $matches ) { * @param string $text Content to convert smilies from text. * @return string Converted content with text smilies replaced with images. */ -function convert_smilies($text) { +function convert_smilies( $text ) { global $wp_smiliessearch; $output = ''; - if ( get_option('use_smilies') && !empty($wp_smiliessearch) ) { + if ( get_option( 'use_smilies' ) && ! empty( $wp_smiliessearch ) ) { // HTML loop taken from texturize function, could possible be consolidated - $textarr = preg_split("/(<.*>)/U", $text, -1, PREG_SPLIT_DELIM_CAPTURE); // capture the tags as well as in between - $stop = count($textarr);// loop stuff - for ($i = 0; $i < $stop; $i++) { + $textarr = preg_split( '/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // capture the tags as well as in between + $stop = count( $textarr );// loop stuff + + // Ignore proessing of specific tags + $tags_to_ignore = 'code|pre|style|script|textarea'; + $ignore_block_element = ''; + + for ( $i = 0; $i < $stop; $i++ ) { $content = $textarr[$i]; - if ((strlen($content) > 0) && ('<' != $content[0])) { // If it's not a tag - $content = preg_replace_callback($wp_smiliessearch, 'translate_smiley', $content); + + // If we're in an ignore block, wait until we find its closing tag + if ( '' == $ignore_block_element && preg_match( '/^<(' . $tags_to_ignore . ')>/', $content, $matches ) ) { + $ignore_block_element = $matches[1]; } + + // If it's not a tag and not in ignore block + if ( '' == $ignore_block_element && strlen( $content ) > 0 && '<' != $content[0] ) { + $content = preg_replace_callback( $wp_smiliessearch, 'translate_smiley', $content ); + } + + // did we exit ignore block + if ( '' != $ignore_block_element && '' == $content ) { + $ignore_block_element = ''; + } + $output .= $content; } } else { diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 7d931bc6ea..aaecdd6bc0 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -2477,6 +2477,7 @@ function _mce_set_direction( $input ) { return $input; } + /** * Convert smiley code to the icon graphic file equivalent. * @@ -2566,7 +2567,7 @@ function smilies_init() { */ krsort($wpsmiliestrans); - $wp_smiliessearch = '/(?:\s|^)'; + $wp_smiliessearch = '/((?:\s|^)'; $subchar = ''; foreach ( (array) $wpsmiliestrans as $smiley => $img ) { @@ -2576,7 +2577,7 @@ function smilies_init() { // new subpattern? if ($firstchar != $subchar) { if ($subchar != '') { - $wp_smiliessearch .= ')|(?:\s|^)'; + $wp_smiliessearch .= ')(?=\s|$))|((?:\s|^)'; ; } $subchar = $firstchar; $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:'; @@ -2586,7 +2587,8 @@ function smilies_init() { $wp_smiliessearch .= preg_quote($rest, '/'); } - $wp_smiliessearch .= ')(?:\s|$)/m'; + $wp_smiliessearch .= ')(?=\s|$))/m'; + } /** diff --git a/tests/phpunit/tests/formatting/Smilies.php b/tests/phpunit/tests/formatting/Smilies.php index 5d9777479d..2fbb79400d 100644 --- a/tests/phpunit/tests/formatting/Smilies.php +++ b/tests/phpunit/tests/formatting/Smilies.php @@ -5,56 +5,99 @@ */ class Tests_Formatting_Smilies extends WP_UnitTestCase { - function test_convert_smilies() { - global $wpsmiliestrans; + /** + * Basic Test Content DataProvider + * + * array ( input_txt, converted_output_txt) + */ + public function get_smilies_input_output() { $includes_path = includes_url("images/smilies/"); + return array ( + array ( + 'Lorem ipsum dolor sit amet mauris ;-) Praesent gravida sodales. :lol: Vivamus nec diam in faucibus eu, bibendum varius nec, imperdiet purus est, at augue at lacus malesuada elit dapibus a, :eek: mauris. Cras mauris viverra elit. Nam laoreet viverra. Pellentesque tortor. Nam libero ante, porta urna ut turpis. Nullam wisi magna, :mrgreen: tincidunt nec, sagittis non, fringilla enim. Nam consectetuer nec, ullamcorper pede eu dui odio consequat vel, vehicula tortor quis pede turpis cursus quis, egestas ipsum ultricies ut, eleifend velit. Mauris vestibulum iaculis. Sed in nunc. Vivamus elit porttitor egestas. Mauris purus :?:', + 'Lorem ipsum dolor sit amet mauris \';-)\' Praesent gravida sodales. \':lol:\' Vivamus nec diam in faucibus eu, bibendum varius nec, imperdiet purus est, at augue at lacus malesuada elit dapibus a, \':eek:\' mauris. Cras mauris viverra elit. Nam laoreet viverra. Pellentesque tortor. Nam libero ante, porta urna ut turpis. Nullam wisi magna, \':mrgreen:\' tincidunt nec, sagittis non, fringilla enim. Nam consectetuer nec, ullamcorper pede eu dui odio consequat vel, vehicula tortor quis pede turpis cursus quis, egestas ipsum ultricies ut, eleifend velit. Mauris vestibulum iaculis. Sed in nunc. Vivamus elit porttitor egestas. Mauris purus \':?:\' ' + ), + array ( + 'Welcome to the jungle! We got fun n games! :) We got everything you want 8-) Honey we know the names :)', + 'Welcome to the jungle! We got fun n games! \':)\' We got everything you want \'8-)\' Honey we know the names \':)\' ' + ), + array ( + "a little bit of this\na little bit:other: of that :D\n:D a little bit of good\nyeah with a little bit of bad8O", + "a little bit of this\na little bit:other: of that :D :D a little bit of good\nyeah with a little bit of bad8O" + ), + array ( + 'and I say it\'s allright:D:D', + 'and I say it\'s allright:D:D' + ), + array ( + '', + '' + ), + array ( + ':?:P:?::-x:mrgreen:::', + ':?:P:?::-x:mrgreen:::' + ), + ); + } + + /** + * @dataProvider get_smilies_input_output + * + * Basic Validation Test to confirm that smilies are converted to image + * when use_smilies = 1 and not when use_smilies = 0 + */ + function test_convert_standard_smilies( $in_txt, $converted_txt ) { + global $wpsmiliestrans; + // standard smilies, use_smilies: ON update_option( 'use_smilies', 1 ); smilies_init(); - $inputs = array( - 'Lorem ipsum dolor sit amet mauris ;-) Praesent gravida sodales. :lol: Vivamus nec diam in faucibus eu, bibendum varius nec, imperdiet purus est, at augue at lacus malesuada elit dapibus a, :eek: mauris. Cras mauris viverra elit. Nam laoreet viverra. Pellentesque tortor. Nam libero ante, porta urna ut turpis. Nullam wisi magna, :mrgreen: tincidunt nec, sagittis non, fringilla enim. Nam consectetuer nec, ullamcorper pede eu dui odio consequat vel, vehicula tortor quis pede turpis cursus quis, egestas ipsum ultricies ut, eleifend velit. Mauris vestibulum iaculis. Sed in nunc. Vivamus elit porttitor egestas. Mauris purus :?:', - 'Welcome to the jungle! We got fun n games! :) We got everything you want 8-) Honey we know the names :)', - "a little bit of this\na little bit:other: of that :D\n:D a little bit of good\nyeah with a little bit of bad8O", - 'and I say it\'s allright:D:D', - '', - ':?:P:?::-x:mrgreen:::', /* - 'the question is, ', - 'the question is, Should smilies be converted in code or pre tags :?:', - 'the question is, Should smilies be converted in code or pre tags :?:', - 'the question is, Should smilies be converted in invalid code or pre tags :?:', - 'Yes I am :)> :) The world makes me :mad:' */ - ); - - $outputs = array( - 'Lorem ipsum dolor sit amet mauris \';-)\' Praesent gravida sodales. \':lol:\' Vivamus nec diam in faucibus eu, bibendum varius nec, imperdiet purus est, at augue at lacus malesuada elit dapibus a, \':eek:\' mauris. Cras mauris viverra elit. Nam laoreet viverra. Pellentesque tortor. Nam libero ante, porta urna ut turpis. Nullam wisi magna, \':mrgreen:\' tincidunt nec, sagittis non, fringilla enim. Nam consectetuer nec, ullamcorper pede eu dui odio consequat vel, vehicula tortor quis pede turpis cursus quis, egestas ipsum ultricies ut, eleifend velit. Mauris vestibulum iaculis. Sed in nunc. Vivamus elit porttitor egestas. Mauris purus \':?:\' ', - 'Welcome to the jungle! We got fun n games! \':)\' We got everything you want \'8-)\' Honey we know the names \':)\' ', - "a little bit of this\na little bit:other: of that :D :D a little bit of good\nyeah with a little bit of bad8O", - 'and I say it\'s allright:D:D', - '', - ' \':?:\' P:?::-x:mrgreen:::', /* - 'the question is, ', - 'the question is, Should smilies be converted in code or pre tags :?:', - 'the question is, Should smilies be converted in code or pre tags :?:', - 'the question is, Should smilies be converted in invalid code or pre tags :?:', - 'Yes I am \':)\' > \':)\' The world makes me \':mad:\'' */ - ); - - foreach ( $inputs as $k => $input ) { - $this->assertEquals( $outputs[$k], convert_smilies($input) ); - } - - update_option( 'use_smilies', 0 ); + $this->assertEquals( $converted_txt, convert_smilies($in_txt) ); // standard smilies, use_smilies: OFF + update_option( 'use_smilies', 0 ); - foreach ( $inputs as $input ) { - $this->assertEquals( $input, convert_smilies($input) ); - } + $this->assertEquals( $in_txt, convert_smilies($in_txt) ); - return; + unset( $wpsmiliestrans ); + } + + /** + * Custom Smilies Test Content DataProvider + * + * array ( input_txt, converted_output_txt) + */ + public function get_custom_smilies_input_output() { + $includes_path = includes_url("images/smilies/"); + + return array ( + array ( + 'Peter Brian Gabriel (born 13 February 1950) is a British singer, musician, and songwriter who rose to fame as the lead vocalist and flautist of the progressive rock group Genesis. :monkey:', + 'Peter Brian Gabriel (born 13 February 1950) is a British singer, musician, and songwriter who rose to fame as the lead vocalist and flautist of the progressive rock group Genesis. \':monkey:\' ' + ), + array ( + 'Star Wars Jedi Knight :arrow: Jedi Academy is a first and third-person shooter action game set in the Star Wars universe. It was developed by Raven Software and published, distributed and marketed by LucasArts in North America and by Activision in the rest of the world. :nervou:', + 'Star Wars Jedi Knight \':arrow:\' Jedi Academy is a first and third-person shooter action game set in the Star Wars universe. It was developed by Raven Software and published, distributed and marketed by LucasArts in North America and by Activision in the rest of the world. \':nervou:\' ' + ), + array ( + ':arrow: monkey: Lorem ipsum dolor sit amet enim. Etiam ullam :PP
corper. Suspendisse a pellentesque dui, non felis. :arrow: :arrow', + ' \':arrow:\' monkey: Lorem ipsum dolor sit amet enim. Etiam ullam \':PP\'
corper. Suspendisse a pellentesque dui, non felis. \':arrow:\' :arrow' + ), + ); + } + + /** + * @dataProvider get_custom_smilies_input_output + * + * Validate Custom Smilies are converted to images when use_smilies = 1 + * @uses $wpsmiliestrans + */ + function test_convert_custom_smilies ( $in_txt, $converted_txt ) { + global $wpsmiliestrans; + $trans_orig = $wpsmiliestrans; // save original translations array // custom smilies, use_smilies: ON update_option( 'use_smilies', 1 ); @@ -67,18 +110,169 @@ class Tests_Formatting_Smilies extends WP_UnitTestCase { smilies_init(); - $inputs = array('Peter Brian Gabriel (born 13 February 1950) is a British singer, musician, and songwriter who rose to fame as the lead vocalist and flautist of the progressive rock group Genesis. :monkey:', - 'Star Wars Jedi Knight:arrow: Jedi Academy is a first and third-person shooter action game set in the Star Wars universe. It was developed by Raven Software and published, distributed and marketed by LucasArts in North America and by Activision in the rest of the world. :nervou:', - ':arrow:monkey:Lorem ipsum dolor sit amet enim. Etiam ullam:PP
corper. Suspendisse a pellentesque dui, non felis.:arrow::arrow' - ); + $this->assertEquals( $converted_txt, convert_smilies($in_txt) ); - $outputs = array('Peter Brian Gabriel (born 13 February 1950) is a British singer, musician, and songwriter who rose to fame as the lead vocalist and flautist of the progressive rock group Genesis. \'icon_arrow\'', - 'Star Wars Jedi Knight\'icon_arrow\' Jedi Academy is a first and third-person shooter action game set in the Star Wars universe. It was developed by Raven Software and published, distributed and marketed by LucasArts in North America and by Activision in the rest of the world. \'icon_nervou\'', - '\'icon_arrow\'monkey:Lorem ipsum dolor sit amet enim. Etiam ullam\'icon_tongue\'
corper. Suspendisse a pellentesque dui, non felis.\'icon_arrow\':arrow' - ); + // standard smilies, use_smilies: OFF + update_option( 'use_smilies', 0 ); - foreach ( $inputs as $k => $input ) { - $this->assertEquals( $outputs[$k], convert_smilies($input) ); - } + $this->assertEquals( $in_txt, convert_smilies($in_txt) ); + + $wpsmiliestrans = $trans_orig; // reset original translations array } -} + + + /** + * DataProvider of HTML elements/tags that smilie matches should be ignored in + * + */ + public function get_smilies_ignore_tags() { + return array ( + array( 'pre' ), + array( 'code' ), + array( 'script' ), + array( 'style' ), + array( 'textarea'), + ); + } + + /** + * Validate Conversion of Smilies is ignored in pre-determined tags + * pre, code, script, style + * + * @ticket 16448 + * @dataProvider get_smilies_ignore_tags + * @uses $wpsmiliestrans + */ + public function test_ignore_smilies_in_tags( $element ) { + global $wpsmiliestrans; + $trans_orig = $wpsmiliestrans; // save original translations array + + $includes_path = includes_url("images/smilies/"); + + $in_str = 'Do we ingore smilies ;-) in ' . $element . ' tags <' . $element . '>My Content Here :?: '; + $exp_str = 'Do we ingore smilies \';-)\' in ' . $element . ' tags <' . $element . '>My Content Here :?: '; + + // standard smilies, use_smilies: ON + update_option( 'use_smilies', 1 ); + smilies_init(); + + $this->assertEquals( $exp_str, convert_smilies($in_str) ); + + // standard smilies, use_smilies: OFF + update_option( 'use_smilies', 0 ); + + $wpsmiliestrans = $trans_orig; // reset original translations array + } + + /** + * DataProvider of Smilie Combinations + * + */ + public function get_smilies_combinations() { + $includes_path = includes_url("images/smilies/"); + + return array ( + array ( + '8-O :-(', + ' \'8-O\' \':-(\' ' + ), + array ( + '8-) 8-O', + ' \'8-)\' \'8-O\' ' + ), + array ( + '8-) 8O', + ' \'8-)\' \'8O\' ' + ), + array ( + '8-) :-(', + ' \'8-)\' \':-(\' ' + ), + array ( + '8-) :twisted:', + ' \'8-)\' \':twisted:\' ' + ), + array ( + '8O :twisted: :( :? :(', + ' \'8O\' \':twisted:\' \':(\' \':?\' \':(\' ' + ), + ); + } + + /** + * Validate Combinations of Smilies separated by single space + * are converted correctly + * + * @ticket 20124 + * @dataProvider get_smilies_combinations + * @uses $wpsmiliestrans + */ + public function test_smilies_combinations( $in_txt, $converted_txt ) { + global $wpsmiliestrans; + + // custom smilies, use_smilies: ON + update_option( 'use_smilies', 1 ); + smilies_init(); + + $this->assertEquals( $converted_txt, convert_smilies($in_txt) ); + + // custom smilies, use_smilies: OFF + update_option( 'use_smilies', 0 ); + + $this->assertEquals( $in_txt, convert_smilies($in_txt) ); + } + + /** + * DataProvider of Single Smilies input and converted output + * + */ + public function get_single_smilies_input_output() { + $includes_path = includes_url("images/smilies/"); + + return array ( + array ( + '8-O :-(', + '8-O :-(' + ), + array ( + '8O :) additional text here :)', + '8O \':)\' additional text here \':)\' ' + ), + array ( + ':) :) :) :)', + ' \':)\' \':)\' \':)\' \':)\' ' + ), + ); + } + + /** + * Validate Smilies are converted for single smilie in + * the $wpsmiliestrans global array + * + * @ticket 25303 + * @dataProvider get_single_smilies_input_output + * @uses $wpsmiliestrans + */ + public function test_single_smilies_in_wpsmiliestrans( $in_txt, $converted_txt ) { + global $wpsmiliestrans; + $orig_trans = $wpsmiliestrans; // save original tranlations array + + // standard smilies, use_smilies: ON + update_option( 'use_smilies', 1 ); + + $wpsmiliestrans = array ( + ':)' => 'icon_smile.gif' + ); + + smilies_init(); + + $this->assertEquals( $converted_txt, convert_smilies($in_txt) ); + + // standard smilies, use_smilies: OFF + update_option( 'use_smilies', 0 ); + + $this->assertEquals( $in_txt, convert_smilies($in_txt) ); + + $wpsmiliestrans = $orig_trans; // reset original translations array + } +} \ No newline at end of file