WordPress.org

Make WordPress Core

Changeset 33360


Ignore:
Timestamp:
07/22/15 05:43:35 (2 years ago)
Author:
pento
Message:

Shortcodes: Improve the reliablity of shortcodes inside HTML tags.

Merge of [33359] to the 4.2 branch.

Props miqrogroove.

See #15694.

Location:
branches/4.2
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • branches/4.2/src/wp-admin/css/press-this.css

    r32230 r33360  
    847847    font-size: 14px; 
    848848    -webkit-appearance: none; 
     849    -moz-appearance: none; 
    849850    appearance: none; 
    850851} 
  • branches/4.2/src/wp-includes/class-wp-embed.php

    r32258 r33360  
    5858 
    5959        // Do the shortcode (only the [embed] one is registered) 
    60         $content = do_shortcode( $content ); 
     60        $content = do_shortcode( $content, true ); 
    6161 
    6262        // Put the original shortcodes back 
     
    313313     */ 
    314314    public function autoembed( $content ) { 
     315        // Strip newlines from all elements. 
     316        $content = wp_replace_in_html_tags( $content, array( "\n" => " " ) ); 
     317 
     318        // Find URLs that are on their own line. 
    315319        return preg_replace_callback( '|^(\s*)(https?://[^\s"]+)(\s*)$|im', array( $this, 'autoembed_callback' ), $content ); 
    316320    } 
  • branches/4.2/src/wp-includes/formatting.php

    r33326 r33360  
    422422    $pee = str_replace(array("\r\n", "\r"), "\n", $pee);  
    423423 
     424    // Strip newlines from all elements. 
     425    $pee = wp_replace_in_html_tags( $pee, array( "\n" => " " ) ); 
     426 
    424427    // Collapse line breaks before and after <option> elements so they don't get autop'd. 
    425428    if ( strpos( $pee, '<option' ) !== false ) { 
     
    508511 
    509512    return $pee; 
     513} 
     514 
     515/** 
     516 * Replace characters or phrases within HTML elements only. 
     517 * 
     518 * @since 4.2.3 
     519 * 
     520 * @param string $haystack The text which has to be formatted. 
     521 * @param array $replace_pairs In the form array('from' => 'to', ...). 
     522 * @return string The formatted text. 
     523 */ 
     524function wp_replace_in_html_tags( $haystack, $replace_pairs ) { 
     525    // Find all elements. 
     526    $comments = 
     527          '!'           // Start of comment, after the <. 
     528        . '(?:'         // Unroll the loop: Consume everything until --> is found. 
     529        .     '-(?!->)' // Dash not followed by end of comment. 
     530        .     '[^\-]*+' // Consume non-dashes. 
     531        . ')*+'         // Loop possessively. 
     532        . '(?:-->)?';   // End of comment. If not found, match all input. 
     533 
     534    $regex = 
     535          '/('              // Capture the entire match. 
     536        .     '<'           // Find start of element. 
     537        .     '(?(?=!--)'   // Is this a comment? 
     538        .         $comments // Find end of comment. 
     539        .     '|' 
     540        .         '[^>]*>?' // Find end of element. If not found, match all input. 
     541        .     ')' 
     542        . ')/s'; 
     543 
     544    $textarr = preg_split( $regex, $haystack, -1, PREG_SPLIT_DELIM_CAPTURE ); 
     545    $changed = false; 
     546 
     547    // Optimize when searching for one item. 
     548    if ( 1 === count( $replace_pairs ) ) { 
     549        // Extract $needle and $replace. 
     550        foreach ( $replace_pairs as $needle => $replace ); 
     551 
     552        // Loop through delimeters (elements) only. 
     553        for ( $i = 1, $c = count( $textarr ); $i < $c; $i += 2 ) {  
     554            if ( false !== strpos( $textarr[$i], $needle ) ) { 
     555                $textarr[$i] = str_replace( $needle, $replace, $textarr[$i] ); 
     556                $changed = true; 
     557            } 
     558        } 
     559    } else { 
     560        // Extract all $needles. 
     561        $needles = array_keys( $replace_pairs ); 
     562 
     563        // Loop through delimeters (elements) only. 
     564        for ( $i = 1, $c = count( $textarr ); $i < $c; $i += 2 ) {  
     565            foreach ( $needles as $needle ) { 
     566                if ( false !== strpos( $textarr[$i], $needle ) ) { 
     567                    $textarr[$i] = strtr( $textarr[$i], $replace_pairs ); 
     568                    $changed = true; 
     569                    // After one strtr() break out of the foreach loop and look at next element. 
     570                    break; 
     571                } 
     572            } 
     573        } 
     574    } 
     575 
     576    if ( $changed ) { 
     577        $haystack = implode( $textarr ); 
     578    } 
     579 
     580    return $haystack; 
    510581} 
    511582 
  • branches/4.2/src/wp-includes/kses.php

    r31205 r33360  
    530530 
    531531/** 
     532 * Filters one attribute only and ensures its value is allowed. 
     533 * 
     534 * This function has the advantage of being more secure than esc_attr() and can 
     535 * escape data in some situations where wp_kses() must strip the whole attribute. 
     536 * 
     537 * @since 4.2.3 
     538 * 
     539 * @param string $string The 'whole' attribute, including name and value. 
     540 * @param string $element The element name to which the attribute belongs. 
     541 * @return string Filtered attribute. 
     542 */ 
     543function wp_kses_one_attr( $string, $element ) { 
     544    $uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action'); 
     545    $allowed_html = wp_kses_allowed_html( 'post' ); 
     546    $allowed_protocols = wp_allowed_protocols(); 
     547    $string = wp_kses_no_null( $string, array( 'slash_zero' => 'keep' ) ); 
     548    $string = wp_kses_js_entities( $string ); 
     549    $string = wp_kses_normalize_entities( $string ); 
     550 
     551    // Preserve leading and trailing whitespace. 
     552    $matches = array(); 
     553    preg_match('/^\s*/', $string, $matches); 
     554    $lead = $matches[0]; 
     555    preg_match('/\s*$/', $string, $matches); 
     556    $trail = $matches[0]; 
     557    if ( empty( $trail ) ) { 
     558        $string = substr( $string, strlen( $lead ) ); 
     559    } else { 
     560        $string = substr( $string, strlen( $lead ), -strlen( $trail ) ); 
     561    } 
     562     
     563    // Parse attribute name and value from input. 
     564    $split = preg_split( '/\s*=\s*/', $string, 2 ); 
     565    $name = $split[0]; 
     566    if ( count( $split ) == 2 ) { 
     567        $value = $split[1]; 
     568 
     569        // Remove quotes surrounding $value. 
     570        // Also guarantee correct quoting in $string for this one attribute. 
     571        if ( '' == $value ) { 
     572            $quote = ''; 
     573        } else { 
     574            $quote = $value[0]; 
     575        } 
     576        if ( '"' == $quote || "'" == $quote ) { 
     577            if ( substr( $value, -1 ) != $quote ) { 
     578                return ''; 
     579            } 
     580            $value = substr( $value, 1, -1 ); 
     581        } else { 
     582            $quote = '"'; 
     583        } 
     584 
     585        // Sanitize quotes and angle braces. 
     586        $value = htmlspecialchars( $value, ENT_QUOTES, null, false ); 
     587 
     588        // Sanitize URI values. 
     589        if ( in_array( strtolower( $name ), $uris ) ) { 
     590            $value = wp_kses_bad_protocol( $value, $allowed_protocols ); 
     591        } 
     592 
     593        $string = "$name=$quote$value$quote"; 
     594        $vless = 'n'; 
     595    } else { 
     596        $value = ''; 
     597        $vless = 'y'; 
     598    } 
     599     
     600    // Sanitize attribute by name. 
     601    wp_kses_attr_check( $name, $value, $string, $vless, $element, $allowed_html ); 
     602 
     603    // Restore whitespace. 
     604    return $lead . $string . $trail; 
     605} 
     606 
     607/** 
    532608 * Return a list of allowed tags and attributes for a given context. 
    533609 * 
     
    749825    // in $attr2 
    750826    $attr2 = ''; 
    751  
    752     $allowed_attr = $allowed_html[strtolower($element)]; 
    753     foreach ($attrarr as $arreach) { 
    754         if ( ! isset( $allowed_attr[strtolower($arreach['name'])] ) ) 
    755             continue; // the attribute is not allowed 
    756  
    757         $current = $allowed_attr[strtolower($arreach['name'])]; 
    758         if ( $current == '' ) 
    759             continue; // the attribute is not allowed 
    760  
    761         if ( strtolower( $arreach['name'] ) == 'style' ) { 
    762             $orig_value = $arreach['value']; 
    763             $value = safecss_filter_attr( $orig_value ); 
    764  
    765             if ( empty( $value ) ) 
    766                 continue; 
    767  
    768             $arreach['value'] = $value; 
    769             $arreach['whole'] = str_replace( $orig_value, $value, $arreach['whole'] ); 
     827    foreach ( $attrarr as $arreach ) { 
     828        if ( wp_kses_attr_check( $arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html ) ) { 
     829            $attr2 .= ' '.$arreach['whole']; 
    770830        } 
    771  
    772         if ( ! is_array($current) ) { 
    773             $attr2 .= ' '.$arreach['whole']; 
    774         // there are no checks 
    775  
    776         } else { 
    777             // there are some checks 
    778             $ok = true; 
    779             foreach ($current as $currkey => $currval) { 
    780                 if ( ! wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval) ) { 
    781                     $ok = false; 
    782                     break; 
    783                 } 
    784             } 
    785  
    786             if ( $ok ) 
    787                 $attr2 .= ' '.$arreach['whole']; // it passed them 
    788         } // if !is_array($current) 
    789     } // foreach 
     831    } 
    790832 
    791833    // Remove any "<" or ">" characters 
     
    793835 
    794836    return "<$element$attr2$xhtml_slash>"; 
     837} 
     838 
     839/** 
     840 * Determine whether an attribute is allowed. 
     841 * 
     842 * @since 4.2.3 
     843 * 
     844 * @param string $name The attribute name. Returns empty string when not allowed. 
     845 * @param string $value The attribute value. Returns a filtered value. 
     846 * @param string $whole The name=value input. Returns filtered input. 
     847 * @param string $vless 'y' when attribute like "enabled", otherwise 'n'. 
     848 * @param string $element The name of the element to which this attribute belongs. 
     849 * @param array $allowed_html The full list of allowed elements and attributes. 
     850 * @return bool Is the attribute allowed? 
     851 */ 
     852function wp_kses_attr_check( &$name, &$value, &$whole, $vless, $element, $allowed_html ) { 
     853    $allowed_attr = $allowed_html[strtolower( $element )]; 
     854 
     855    $name_low = strtolower( $name ); 
     856    if ( ! isset( $allowed_attr[$name_low] ) || '' == $allowed_attr[$name_low] ) { 
     857        $name = $value = $whole = ''; 
     858        return false; 
     859    } 
     860 
     861    if ( 'style' == $name_low ) { 
     862        $new_value = safecss_filter_attr( $value ); 
     863 
     864        if ( empty( $new_value ) ) { 
     865            $name = $value = $whole = ''; 
     866            return false; 
     867        } 
     868 
     869        $whole = str_replace( $value, $new_value, $whole ); 
     870        $value = $new_value; 
     871    } 
     872 
     873    if ( is_array( $allowed_attr[$name_low] ) ) { 
     874        // there are some checks 
     875        foreach ( $allowed_attr[$name_low] as $currkey => $currval ) { 
     876            if ( ! wp_kses_check_attr_val( $value, $vless, $currkey, $currval ) ) { 
     877                $name = $value = $whole = ''; 
     878                return false; 
     879            } 
     880        } 
     881    } 
     882 
     883    return true; 
    795884} 
    796885 
     
    9221011 
    9231012    return $attrarr; 
     1013} 
     1014 
     1015/** 
     1016 * Finds all attributes of an HTML element. 
     1017 * 
     1018 * Does not modify input.  May return "evil" output. 
     1019 * 
     1020 * Based on wp_kses_split2() and wp_kses_attr() 
     1021 * 
     1022 * @since 4.2.3 
     1023 * 
     1024 * @param string $element HTML element/tag 
     1025 * @return array|bool List of attributes found in $element. Returns false on failure. 
     1026 */ 
     1027function wp_kses_attr_parse( $element ) { 
     1028    $valid = preg_match('%^(<\s*)(/\s*)?([a-zA-Z0-9]+\s*)([^>]*)(>?)$%', $element, $matches); 
     1029    if ( 1 !== $valid ) { 
     1030        return false; 
     1031    } 
     1032 
     1033    $begin =  $matches[1]; 
     1034    $slash =  $matches[2]; 
     1035    $elname = $matches[3]; 
     1036    $attr =   $matches[4]; 
     1037    $end =    $matches[5]; 
     1038 
     1039    if ( '' !== $slash ) { 
     1040        // Closing elements do not get parsed. 
     1041        return false; 
     1042    } 
     1043 
     1044    // Is there a closing XHTML slash at the end of the attributes? 
     1045    if ( 1 === preg_match( '%\s*/\s*$%', $attr, $matches ) ) { 
     1046        $xhtml_slash = $matches[0]; 
     1047        $attr = substr( $attr, 0, -strlen( $xhtml_slash ) ); 
     1048    } else { 
     1049        $xhtml_slash = ''; 
     1050    } 
     1051     
     1052    // Split it 
     1053    $attrarr = wp_kses_hair_parse( $attr ); 
     1054    if ( false === $attrarr ) { 
     1055        return false; 
     1056    } 
     1057 
     1058    // Make sure all input is returned by adding front and back matter. 
     1059    array_unshift( $attrarr, $begin . $slash . $elname ); 
     1060    array_push( $attrarr, $xhtml_slash . $end ); 
     1061     
     1062    return $attrarr; 
     1063} 
     1064 
     1065/** 
     1066 * Builds an attribute list from string containing attributes. 
     1067 * 
     1068 * Does not modify input.  May return "evil" output. 
     1069 * In case of unexpected input, returns false instead of stripping things. 
     1070 * 
     1071 * Based on wp_kses_hair() but does not return a multi-dimensional array. 
     1072 * 
     1073 * @since 4.2.3 
     1074 * 
     1075 * @param string $attr Attribute list from HTML element to closing HTML element tag 
     1076 * @return array|bool List of attributes found in $attr. Returns false on failure. 
     1077 */ 
     1078function wp_kses_hair_parse( $attr ) { 
     1079    if ( '' === $attr ) { 
     1080        return array(); 
     1081    } 
     1082 
     1083    $regex = 
     1084      '(?:' 
     1085    .     '[-a-zA-Z:]+'   // Attribute name. 
     1086    . '|' 
     1087    .     '\[\[?[^\[\]]+\]\]?' // Shortcode in the name position implies unfiltered_html. 
     1088    . ')' 
     1089    . '(?:'               // Attribute value. 
     1090    .     '\s*=\s*'       // All values begin with '=' 
     1091    .     '(?:' 
     1092    .         '"[^"]*"'   // Double-quoted 
     1093    .     '|' 
     1094    .         "'[^']*'"   // Single-quoted 
     1095    .     '|' 
     1096    .         '[^\s"\']+' // Non-quoted 
     1097    .         '(?:\s|$)'  // Must have a space 
     1098    .     ')' 
     1099    . '|' 
     1100    .     '(?:\s|$)'      // If attribute has no value, space is required. 
     1101    . ')' 
     1102    . '\s*';              // Trailing space is optional except as mentioned above. 
     1103 
     1104    // Although it is possible to reduce this procedure to a single regexp, 
     1105    // we must run that regexp twice to get exactly the expected result. 
     1106 
     1107    $validation = "%^($regex)+$%"; 
     1108    $extraction = "%$regex%"; 
     1109 
     1110    if ( 1 === preg_match( $validation, $attr ) ) { 
     1111        preg_match_all( $extraction, $attr, $attrarr ); 
     1112        return $attrarr[0]; 
     1113    } else { 
     1114        return false; 
     1115    } 
    9241116} 
    9251117 
  • branches/4.2/src/wp-includes/shortcodes.php

    r32116 r33360  
    185185 * 
    186186 * @param string $content Content to search for shortcodes. 
     187 * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped. 
    187188 * @return string Content with shortcodes filtered out. 
    188189 */ 
    189 function do_shortcode($content) { 
     190function do_shortcode( $content, $ignore_html = false ) { 
    190191    global $shortcode_tags; 
    191192 
     
    197198        return $content; 
    198199 
     200    $tagnames = array_keys($shortcode_tags); 
     201    $tagregexp = join( '|', array_map('preg_quote', $tagnames) ); 
     202    $pattern = "/\\[($tagregexp)/s"; 
     203 
     204    if ( 1 !== preg_match( $pattern, $content ) ) { 
     205        // Avoids parsing HTML when there are no shortcodes or embeds anyway. 
     206        return $content; 
     207    } 
     208 
     209    $content = do_shortcodes_in_html_tags( $content, $ignore_html ); 
     210 
    199211    $pattern = get_shortcode_regex(); 
    200     return preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content ); 
     212    $content = preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content ); 
     213     
     214    // Always restore square braces so we don't break things like <!--[if IE ]> 
     215    $content = unescape_invalid_shortcodes( $content ); 
     216     
     217    return $content; 
    201218} 
    202219 
     
    292309 
    293310/** 
     311 * Search only inside HTML elements for shortcodes and process them. 
     312 * 
     313 * Any [ or ] characters remaining inside elements will be HTML encoded 
     314 * to prevent interference with shortcodes that are outside the elements. 
     315 * Assumes $content processed by KSES already.  Users with unfiltered_html 
     316 * capability may get unexpected output if angle braces are nested in tags. 
     317 * 
     318 * @since 4.2.3 
     319 * 
     320 * @param string $content Content to search for shortcodes 
     321 * @param bool $ignore_html When true, all square braces inside elements will be encoded. 
     322 * @return string Content with shortcodes filtered out. 
     323 */ 
     324function do_shortcodes_in_html_tags( $content, $ignore_html ) { 
     325    // Normalize entities in unfiltered HTML before adding placeholders. 
     326    $trans = array( '&#91;' => '&#091;', '&#93;' => '&#093;' ); 
     327    $content = strtr( $content, $trans ); 
     328    $trans = array( '[' => '&#91;', ']' => '&#93;' ); 
     329     
     330    $pattern = get_shortcode_regex(); 
     331 
     332    $comment_regex = 
     333          '!'           // Start of comment, after the <. 
     334        . '(?:'         // Unroll the loop: Consume everything until --> is found. 
     335        .     '-(?!->)' // Dash not followed by end of comment. 
     336        .     '[^\-]*+' // Consume non-dashes. 
     337        . ')*+'         // Loop possessively. 
     338        . '(?:-->)?';   // End of comment. If not found, match all input. 
     339 
     340    $regex = 
     341          '/('                   // Capture the entire match. 
     342        .     '<'                // Find start of element. 
     343        .     '(?(?=!--)'        // Is this a comment? 
     344        .         $comment_regex // Find end of comment. 
     345        .     '|' 
     346        .         '[^>]*>?'      // Find end of element. If not found, match all input. 
     347        .     ')' 
     348        . ')/s'; 
     349 
     350    $textarr = preg_split( $regex, $content, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY ); 
     351 
     352    foreach ( $textarr as &$element ) { 
     353        if ( '<' !== $element[0] ) { 
     354            continue; 
     355        } 
     356 
     357        $noopen = false === strpos( $element, '[' ); 
     358        $noclose = false === strpos( $element, ']' ); 
     359        if ( $noopen || $noclose ) { 
     360            // This element does not contain shortcodes. 
     361            if ( $noopen xor $noclose ) { 
     362                // Need to encode stray [ or ] chars. 
     363                $element = strtr( $element, $trans ); 
     364            } 
     365            continue; 
     366        } 
     367 
     368        if ( $ignore_html || '<!--' === substr( $element, 0, 4 ) ) { 
     369            // Encode all [ and ] chars. 
     370            $element = strtr( $element, $trans ); 
     371            continue; 
     372        } 
     373 
     374        $attributes = wp_kses_attr_parse( $element ); 
     375        if ( false === $attributes ) { 
     376            // Looks like we found some crazy unfiltered HTML.  Skipping it for sanity. 
     377            $element = strtr( $element, $trans ); 
     378            continue; 
     379        } 
     380         
     381        // Get element name 
     382        $front = array_shift( $attributes ); 
     383        $back = array_pop( $attributes ); 
     384        $matches = array(); 
     385        preg_match('%[a-zA-Z0-9]+%', $front, $matches); 
     386        $elname = $matches[0]; 
     387         
     388        // Look for shortcodes in each attribute separately. 
     389        foreach ( $attributes as &$attr ) { 
     390            $open = strpos( $attr, '[' ); 
     391            $close = strpos( $attr, ']' ); 
     392            if ( false === $open || false === $close ) { 
     393                continue; // Go to next attribute.  Square braces will be escaped at end of loop. 
     394            } 
     395            $double = strpos( $attr, '"' ); 
     396            $single = strpos( $attr, "'" ); 
     397            if ( ( false === $single || $open < $single ) && ( false === $double || $open < $double ) ) { 
     398                // $attr like '[shortcode]' or 'name = [shortcode]' implies unfiltered_html. 
     399                // In this specific situation we assume KSES did not run because the input 
     400                // was written by an administrator, so we should avoid changing the output 
     401                // and we do not need to run KSES here. 
     402                $attr = preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $attr ); 
     403            } else { 
     404                // $attr like 'name = "[shortcode]"' or "name = '[shortcode]'" 
     405                // We do not know if $content was unfiltered. Assume KSES ran before shortcodes. 
     406                $count = 0; 
     407                $new_attr = preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $attr, -1, $count ); 
     408                if ( $count > 0 ) { 
     409                    // Sanitize the shortcode output using KSES. 
     410                    $new_attr = wp_kses_one_attr( $new_attr, $elname ); 
     411                    if ( '' !== $new_attr ) { 
     412                        // The shortcode is safe to use now. 
     413                        $attr = $new_attr; 
     414                    } 
     415                } 
     416            } 
     417        } 
     418        $element = $front . implode( '', $attributes ) . $back; 
     419         
     420        // Now encode any remaining [ or ] chars. 
     421        $element = strtr( $element, $trans ); 
     422    } 
     423     
     424    $content = implode( '', $textarr ); 
     425     
     426    return $content; 
     427} 
     428 
     429/** 
     430 * Remove placeholders added by do_shortcodes_in_html_tags(). 
     431 * 
     432 * @since 4.2.3 
     433 * 
     434 * @param string $content Content to search for placeholders. 
     435 * @return string Content with placeholders removed. 
     436 */ 
     437function unescape_invalid_shortcodes( $content ) { 
     438        // Clean up entire string, avoids re-parsing HTML. 
     439        $trans = array( '&#91;' => '[', '&#93;' => ']' ); 
     440        $content = strtr( $content, $trans ); 
     441         
     442        return $content; 
     443} 
     444 
     445/** 
    294446 * Retrieve all attributes from the shortcodes tag. 
    295447 * 
     
    390542        return $content; 
    391543 
     544    $content = do_shortcodes_in_html_tags( $content, true ); 
     545 
    392546    $pattern = get_shortcode_regex(); 
    393  
    394     return preg_replace_callback( "/$pattern/s", 'strip_shortcode_tag', $content ); 
     547    $content = preg_replace_callback( "/$pattern/s", 'strip_shortcode_tag', $content ); 
     548 
     549    // Always restore square braces so we don't break things like <!--[if IE ]> 
     550    $content = unescape_invalid_shortcodes( $content ); 
     551     
     552    return $content; 
    395553} 
    396554 
  • branches/4.2/tests/phpunit/tests/kses.php

    r28942 r33360  
    412412        ); 
    413413    } 
     414 
     415    /** 
     416     * Test new function wp_kses_hair_parse(). 
     417     * 
     418     * @dataProvider data_hair_parse 
     419     */ 
     420    function test_hair_parse( $input, $output ) { 
     421        return $this->assertEquals( $output, wp_kses_hair_parse( $input ) ); 
     422    } 
     423 
     424    function data_hair_parse() { 
     425        return array( 
     426            array( 
     427                'title="hello" href="#" id="my_id" ', 
     428                array( 'title="hello" ', 'href="#" ', 'id="my_id" ' ), 
     429            ), 
     430            array( 
     431                '[shortcode attr="value"] href="http://www.google.com/"title="moo"disabled', 
     432                array( '[shortcode attr="value"] ', 'href="http://www.google.com/"', 'title="moo"', 'disabled' ), 
     433            ), 
     434            array( 
     435                '', 
     436                array(), 
     437            ), 
     438            array( 
     439                'a', 
     440                array( 'a' ), 
     441            ), 
     442            array( 
     443                'title="hello"disabled href=# id=\'my_id\'', 
     444                array( 'title="hello"', 'disabled ', 'href=# ', "id='my_id'" ), 
     445            ), 
     446            array( 
     447                '     ', // Calling function is expected to strip leading whitespace. 
     448                false, 
     449            ), 
     450            array( 
     451                'abcd=abcd"abcd"', 
     452                false, 
     453            ), 
     454            array( 
     455                "array[1]='z'z'z'z", 
     456                false, 
     457            ), 
     458        ); 
     459    } 
     460 
     461    /** 
     462     * Test new function wp_kses_attr_parse(). 
     463     * 
     464     * @dataProvider data_attr_parse 
     465     */ 
     466    function test_attr_parse( $input, $output ) { 
     467        return $this->assertEquals( $output, wp_kses_attr_parse( $input ) ); 
     468    } 
     469 
     470    function data_attr_parse() { 
     471        return array( 
     472            array( 
     473                '<a title="hello" href="#" id="my_id" >', 
     474                array( '<a ', 'title="hello" ', 'href="#" ', 'id="my_id" ', '>' ), 
     475            ), 
     476            array( 
     477                '<a [shortcode attr="value"] href="http://www.google.com/"title="moo"disabled>', 
     478                array( '<a ', '[shortcode attr="value"] ', 'href="http://www.google.com/"', 'title="moo"', 'disabled', '>' ), 
     479            ), 
     480            array( 
     481                '', 
     482                false, 
     483            ), 
     484            array( 
     485                'a', 
     486                false, 
     487            ), 
     488            array( 
     489                '<a>', 
     490                array( '<a', '>' ), 
     491            ), 
     492            array( 
     493                '<a%%&&**>', 
     494                false, 
     495            ), 
     496            array( 
     497                '<a title="hello"disabled href=# id=\'my_id\'>', 
     498                array( '<a ', 'title="hello"', 'disabled ', 'href=# ', "id='my_id'", ">" ), 
     499            ), 
     500            array( 
     501                '<a     >', 
     502                array( '<a     ', '>' ), 
     503            ), 
     504            array( 
     505                '<a abcd=abcd"abcd">', 
     506                false, 
     507            ), 
     508            array( 
     509                "<a array[1]='z'z'z'z>", 
     510                false, 
     511            ), 
     512            array( 
     513                '<img title="hello" src="#" id="my_id" />', 
     514                array( '<img ', 'title="hello" ', 'src="#" ', 'id="my_id"', ' />' ), 
     515            ), 
     516        ); 
     517    } 
     518 
     519    /** 
     520     * Test new function wp_kses_one_attr(). 
     521     * 
     522     * @dataProvider data_one_attr 
     523     */ 
     524    function test_one_attr( $element, $input, $output ) { 
     525        return $this->assertEquals( $output, wp_kses_one_attr( $input, $element ) ); 
     526    } 
     527 
     528    function data_one_attr() { 
     529        return array( 
     530            array( 
     531                'a', 
     532                ' title="hello" ', 
     533                ' title="hello" ', 
     534            ), 
     535            array( 
     536                'a', 
     537                'title  =  "hello"', 
     538                'title="hello"', 
     539            ), 
     540            array( 
     541                'a', 
     542                "title='hello'", 
     543                "title='hello'", 
     544            ), 
     545            array( 
     546                'a', 
     547                'title=hello', 
     548                'title="hello"', 
     549            ), 
     550            array( 
     551                'a', 
     552                'href="javascript:alert(1)"', 
     553                'href="alert(1)"', 
     554            ), 
     555            array( 
     556                'a', 
     557                'style ="style "', 
     558                'style="style"', 
     559            ), 
     560            array( 
     561                'a', 
     562                'style="style "', 
     563                'style="style"', 
     564            ), 
     565            array( 
     566                'a', 
     567                'style ="style ="', 
     568                '', 
     569            ), 
     570            array( 
     571                'img', 
     572                'src="mypic.jpg"', 
     573                'src="mypic.jpg"', 
     574            ), 
     575            array( 
     576                'img', 
     577                'onerror=alert(1)', 
     578                '', 
     579            ), 
     580            array( 
     581                'img', 
     582                'title=>', 
     583                'title="&gt;"', 
     584            ), 
     585            array( 
     586                'img', 
     587                'title="&garbage";"', 
     588                'title="&amp;garbage&quot;;"', 
     589            ), 
     590        ); 
     591    } 
    414592} 
  • branches/4.2/tests/phpunit/tests/shortcode.php

    r31622 r33360  
    387387 
    388388    /** 
     389     * Check for bugginess using normal input with latest patches. 
     390     * 
     391     * @dataProvider data_escaping 
     392     */ 
     393    function test_escaping( $input, $output ) { 
     394        return $this->assertEquals( $output, do_shortcode( $input ) ); 
     395    } 
     396 
     397    function data_escaping() { 
     398        return array( 
     399            array( 
     400                '<!--[if lt IE 7]>', 
     401                '<!--[if lt IE 7]>', 
     402            ), 
     403            array( 
     404                '[gallery title="<div>hello</div>"]', 
     405                '', 
     406            ), 
     407            array( 
     408                '[caption caption="test" width="2"]<div>hello</div>[/caption]', 
     409                '<div style="width: 12px" class="wp-caption alignnone"><div>hello</div><p class="wp-caption-text">test</p></div>', 
     410            ), 
     411            array( 
     412                '<div [gallery]>', 
     413                '<div >', 
     414            ), 
     415            array( 
     416                '<div [[gallery]]>', 
     417                '<div [gallery]>', 
     418            ), 
     419            array( 
     420                '[gallery]<div>Hello</div>[/gallery]', 
     421                '', 
     422            ), 
     423        ); 
     424    } 
     425 
     426    /** 
     427     * Check for bugginess using normal input with latest patches. 
     428     * 
     429     * @dataProvider data_escaping2 
     430     */ 
     431    function test_escaping2( $input, $output ) { 
     432        return $this->assertEquals( $output, strip_shortcodes( $input ) ); 
     433    } 
     434 
     435    function data_escaping2() { 
     436        return array( 
     437            array( 
     438                '<!--[if lt IE 7]>', 
     439                '<!--[if lt IE 7]>', 
     440            ), 
     441            array( 
     442                '[gallery title="<div>hello</div>"]', 
     443                '', 
     444            ), 
     445            array( 
     446                '[caption caption="test" width="2"]<div>hello</div>[/caption]', 
     447                '', 
     448            ), 
     449            array( 
     450                '<div [gallery]>', // Shortcodes will never be stripped inside elements. 
     451                '<div [gallery]>', 
     452            ), 
     453            array( 
     454                '<div [[gallery]]>', // Shortcodes will never be stripped inside elements. 
     455                '<div [[gallery]]>', 
     456            ), 
     457            array( 
     458                '[gallery]<div>Hello</div>[/gallery]', 
     459                '', 
     460            ), 
     461        ); 
     462    } 
     463 
     464    /** 
    389465     * @ticket 26343 
    390466     */ 
Note: See TracChangeset for help on using the changeset viewer.