Make WordPress Core

Changeset 29781


Ignore:
Timestamp:
09/29/2014 04:06:54 AM (12 years ago)
Author:
wonderboymusic
Message:

The joys of wptexturize():

  • Revert parts of [28773] and [28727] and [29748].
  • Do not crash PHP. Make the shortcode quantifier possessive to avoid backtracks.
  • Reduce backtracking in long HTML comments by 100x.
  • Do not ignore unclosed HTML comments.
  • Do not break unregistered shortcodes, e.g. [hello attr="value"].
  • Do not break HTML in shortcode attributes, e.g. [hello attr="<"].
  • Do not match for shortcodes when there is extra whitespace, e.g. [ hello ].
  • Add unit tests to show #12690 was not fully resolved.
  • Tested PHP 5.2.4, 5.2.13, 5.4.32, and 5.5.8.

Adds/modifies unit tests.

Props miqrogroove.
See #29557.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/formatting.php

    r29748 r29781  
    2929 */
    3030function wptexturize($text, $reset = false) {
    31         global $wp_cockneyreplace, $shortcode_tags;
     31        global $wp_cockneyreplace;
    3232        static $static_characters, $static_replacements, $dynamic_characters, $dynamic_replacements,
    3333                $default_no_texturize_tags, $default_no_texturize_shortcodes, $run_texturize = true;
     
    206206        // Look for shortcodes and HTML elements.
    207207
    208         $tagnames = array_keys( $shortcode_tags );
    209         $tagregexp = join( '|', array_map( 'preg_quote', $tagnames ) );
    210         $tagregexp = "(?:$tagregexp)(?![\\w-])"; // Excerpt of get_shortcode_regex().
     208        $comment_regex =
     209                        '!'                             // Start of comment, after the <.
     210                .       '(?:'                   // Unroll the loop: Consume everything until --> is found.
     211                .               '-(?!->)'       // Dash not followed by end of comment.
     212                .               '[^\-]*+'       // Consume non-dashes.
     213                .       ')*+'                   // Loop possessively.
     214                .       '(?:-->)?';             // End of comment. If not found, match all input.
    211215       
    212         $regex =  '/('                  // Capture the entire match.
    213                 .       '<'             // Find start of element.
    214                 .       '(?(?=!--)'     // Is this a comment?
    215                 .               '.+?--\s*>'     // Find end of comment
     216        $shortcode_regex =
     217                        '\['                    // Find start of shortcode.
     218                .       '[\/\[]?'               // Shortcodes may begin with [/ or [[
     219                .       '[^\s\/\[\]]'   // No whitespace before name.
     220                .       '[^\[\]]*+'             // Shortcodes do not contain other shortcodes. Possessive critical.
     221                .       '\]'                    // Find end of shortcode.
     222                .       '\]?';                  // Shortcodes may end with ]]
     223       
     224        $regex =
     225                        '/('                                    // Capture the entire match.
     226                .               '<'                                     // Find start of element.
     227                .               '(?(?=!--)'                     // Is this a comment?
     228                .                       $comment_regex  // Find end of comment.
     229                .               '|'
     230                .                       '[^>]+>'                // Find end of element.
     231                .               ')'
    216232                .       '|'
    217                 .               '[^>]+>'        // Find end of element
    218                 .       ')'
    219                 . '|'
    220                 .       '\['            // Find start of shortcode.
    221                 .       '\[?'           // Shortcodes may begin with [[
    222                 .       '\/?'           // Closing slash may precede name.
    223                 .       $tagregexp      // Only match registered shortcodes, because performance.
    224                 .       '[^\[\]]*'      // Shortcodes do not contain other shortcodes.
    225                 .       '\]'            // Find end of shortcode.
    226                 .       '\]?'           // Shortcodes may end with ]]
    227                 . ')/s';
     233                .               $shortcode_regex        // Find shortcodes.
     234                .       ')/s';
    228235
    229236        $textarr = preg_split( $regex, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
     
    232239                // Only call _wptexturize_pushpop_element if $curl is a delimiter.
    233240                $first = $curl[0];
    234                 if ( '<' === $first && '>' === substr( $curl, -1 ) ) {
    235                         // This is an HTML delimiter.
    236 
    237                         if ( '<!--' !== substr( $curl, 0, 4 ) ) {
    238                                 _wptexturize_pushpop_element( $curl, $no_texturize_tags_stack, $no_texturize_tags );
    239                         }
     241                if ( '<' === $first && '<!--' === substr( $curl, 0, 4 ) ) {
     242                        // This is an HTML comment delimeter.
     243
     244                        continue;
     245
     246                } elseif ( '<' === $first && '>' === substr( $curl, -1 ) ) {
     247                        // This is an HTML element delimiter.
     248
     249                        _wptexturize_pushpop_element( $curl, $no_texturize_tags_stack, $no_texturize_tags );
    240250
    241251                } elseif ( '' === trim( $curl ) ) {
     
    244254                        continue;
    245255
    246                 } elseif ( '[' === $first && 1 === preg_match( '/^\[\[?\/?' . $tagregexp . '[^\[\]]*\]\]?$/', $curl ) ) {
     256                } elseif ( '[' === $first && 1 === preg_match( '/^' . $shortcode_regex . '$/', $curl ) ) {
    247257                        // This is a shortcode delimiter.
    248258
  • trunk/src/wp-includes/shortcodes.php

    r29748 r29781  
    232232
    233233        // WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag()
    234         // Also, see shortcode_unautop() and shortcode.js and wptexturize().
     234        // Also, see shortcode_unautop() and shortcode.js.
    235235        return
    236236                  '\\['                              // Opening bracket
  • trunk/tests/phpunit/tests/formatting/WPTexturize.php

    r29748 r29781  
    11891189                return array(
    11901190                        array(
     1191                                '[ ... ]',
     1192                                '[ &#8230; ]',
     1193                        ),
     1194                        array(
    11911195                                '[ is it wise to <a title="allow user content ] here? hmm"> maybe </a> ]',
    11921196                                '[ is it wise to <a title="allow user content ] here? hmm"> maybe </a> ]',
    11931197                        ),
    11941198                        array(
     1199                                '[is it wise to <a title="allow user content ] here? hmm"> maybe </a> ]', // HTML corruption is a known bug.  See tickets #12690 and #29557.
     1200                                '[is it wise to <a title="allow user content ] here? hmm&#8221;> maybe </a> ]',
     1201                        ),
     1202                        array(
     1203                                '[caption - is it wise to <a title="allow user content ] here? hmm"> maybe </a> ]',
     1204                                '[caption - is it wise to <a title="allow user content ] here? hmm&#8221;> maybe </a> ]',
     1205                        ),
     1206                        array(
    11951207                                '[ photos by <a href="http://example.com/?a[]=1&a[]=2"> this guy </a> ]',
    11961208                                '[ photos by <a href="http://example.com/?a[]=1&#038;a[]=2"> this guy </a> ]',
    11971209                        ),
    11981210                        array(
     1211                                '[photos by <a href="http://example.com/?a[]=1&a[]=2"> this guy </a>]',
     1212                                '[photos by <a href="http://example.com/?a[]=1&#038;a[]=2"> this guy </a>]',
     1213                        ),
     1214                        array(
    11991215                                '[gallery ...]',
    12001216                                '[gallery ...]',
     
    12131229                        ),
    12141230                        array(
    1215                                 '[...]...[/...]', // These are potentially usable shortcodes.
    1216                                 '[&#8230;]&#8230;[/&#8230;]',
    1217                         ),
    1218                         array(
    12191231                                '[[gallery]]...[[/gallery]]', // Shortcode parsing will ignore the inner ]...[ part and treat this as a single escaped shortcode.
    12201232                                '[[gallery]]&#8230;[[/gallery]]',
     
    12251237                        ),
    12261238                        array(
    1227                                 '[gal>ery ...]',
    1228                                 '[gal>ery &#8230;]',
    1229                         ),
    1230                         array(
    12311239                                '[gallery ...',
    12321240                                '[gallery &#8230;',
     
    13011309                        ),
    13021310                        array(
    1303                                 '<!-- ... -- >',
    1304                                 '<!-- ... -- >',
     1311                                '<!-- ... -- > ...',
     1312                                '<!-- ... -- > ...',
     1313                        ),
     1314                        array(
     1315                                '<!-- ...', // An unclosed comment is still a comment.
     1316                                '<!-- ...',
     1317                        ),
     1318                        array(
     1319                                'a<!-->b', // Browsers seem to allow this.
     1320                                'a<!-->b',
     1321                        ),
     1322                        array(
     1323                                'a<!--->b',
     1324                                'a<!--->b',
     1325                        ),
     1326                        array(
     1327                                'a<!---->b',
     1328                                'a<!---->b',
     1329                        ),
     1330                        array(
     1331                                'a<!----->b',
     1332                                'a<!----->b',
     1333                        ),
     1334                        array(
     1335                                'a<!-- c --->b',
     1336                                'a<!-- c --->b',
     1337                        ),
     1338                        array(
     1339                                'a<!-- c -- d -->b',
     1340                                'a<!-- c -- d -->b',
     1341                        ),
     1342                        array(
     1343                                'a<!-- <!-- c --> -->b<!-- close -->',
     1344                                'a<!-- <!-- c --> &#8211;>b<!-- close -->',
    13051345                        ),
    13061346                        array(
     
    17281768                        array(
    17291769                                '[code ...]...[/code]', // code is not a registered shortcode.
    1730                                 '[code &#8230;]&#8230;[/code]',
     1770                                '[code ...]...[/code]',
    17311771                        ),
    17321772                        array(
    17331773                                '[hello ...]...[/hello]', // hello is not a registered shortcode.
    1734                                 '[hello &#8230;]&#8230;[/hello]',
     1774                                '[hello ...]&#8230;[/hello]',
     1775                        ),
     1776                        array(
     1777                                '[...]...[/...]', // These are potentially usable shortcodes.
     1778                                '[...]&#8230;[/...]',
     1779                        ),
     1780                        array(
     1781                                '[gal>ery ...]',
     1782                                '[gal>ery ...]',
     1783                        ),
     1784                        array(
     1785                                '[randomthing param="test"]',
     1786                                '[randomthing param="test"]',
    17351787                        ),
    17361788                        array(
Note: See TracChangeset for help on using the changeset viewer.