WordPress.org

Make WordPress Core

Changeset 29781


Ignore:
Timestamp:
09/29/2014 04:06:54 AM (5 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.