WordPress.org

Make WordPress Core

Ticket #16042: 16042-full.patch

File 16042-full.patch, 17.4 KB (added by hakre, 4 years ago)

Patch against branch 2.9

  • wp-includes/kses.php

     
    11<?php 
    22/** 
    3  * HTML/XHTML filter that only allows some elements and attributes 
     3 * kses 0.2.2 - HTML/XHTML filter that only allows some elements and attributes 
     4 * Copyright (C) 2002, 2003, 2005  Ulf Harnhammar 
    45 * 
     6 * This program is free software and open source software; you can redistribute 
     7 * it and/or modify it under the terms of the GNU General Public License as 
     8 * published by the Free Software Foundation; either version 2 of the License, 
     9 * or (at your option) any later version. 
     10 * 
     11 * This program is distributed in the hope that it will be useful, but WITHOUT 
     12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
     13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
     14 * more details. 
     15 * 
     16 * You should have received a copy of the GNU General Public License along 
     17 * with this program; if not, write to the Free Software Foundation, Inc., 
     18 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  or visit 
     19 * http://www.gnu.org/licenses/gpl.html 
     20 *  
     21 * [kses strips evil scripts!] 
     22 * 
    523 * Added wp_ prefix to avoid conflicts with existing kses users 
    624 * 
    725 * @version 0.2.2 
     
    1028 * 
    1129 * @package External 
    1230 * @subpackage KSES 
    13  * 
    14  * @internal 
    15  * *** CONTACT INFORMATION *** 
    16  * E-mail:      metaur at users dot sourceforge dot net 
    17  * Web page:    http://sourceforge.net/projects/kses 
    18  * Paper mail:  Ulf Harnhammar 
    19  *              Ymergatan 17 C 
    20  *              753 25  Uppsala 
    21  *              SWEDEN 
    22  * 
    23  * [kses strips evil scripts!] 
    2431 */ 
    2532 
    2633/** 
     
    2936 * 
    3037 * @since 1.2.0 
    3138 */ 
    32 if (!defined('CUSTOM_TAGS')) 
    33         define('CUSTOM_TAGS', false); 
     39if ( ! defined( 'CUSTOM_TAGS' ) ) 
     40        define( 'CUSTOM_TAGS', false ); 
    3441 
    35 if (!CUSTOM_TAGS) { 
     42if ( ! CUSTOM_TAGS ) { 
    3643        /** 
    3744         * Kses global for default allowable HTML tags. 
    3845         * 
     
    5764                        'title' => array ()), 
    5865                'acronym' => array( 
    5966                        'title' => array ()), 
     67                'article' => array( 
     68                        'align' => array (), 
     69                        'class' => array (), 
     70                        'dir' => array (), 
     71                        'lang' => array(), 
     72                        'style' => array (), 
     73                        'xml:lang' => array(), 
     74                ), 
     75                'aside' => array( 
     76                        'align' => array (), 
     77                        'class' => array (), 
     78                        'dir' => array (), 
     79                        'lang' => array(), 
     80                        'style' => array (), 
     81                        'xml:lang' => array(), 
     82                ), 
    6083                'b' => array(), 
    6184                'big' => array(), 
    6285                'blockquote' => array( 
     
    94117                'del' => array( 
    95118                        'datetime' => array ()), 
    96119                'dd' => array(), 
     120                'details' => array( 
     121                        'align' => array (), 
     122                        'class' => array (), 
     123                        'dir' => array (), 
     124                        'lang' => array(), 
     125                        'open' => array (), 
     126                        'style' => array (), 
     127                        'xml:lang' => array(), 
     128                ), 
    97129                'div' => array( 
    98130                        'align' => array (), 
    99131                        'class' => array (), 
     
    105137                'dt' => array(), 
    106138                'em' => array(), 
    107139                'fieldset' => array(), 
     140                'figure' => array( 
     141                        'align' => array (), 
     142                        'class' => array (), 
     143                        'dir' => array (), 
     144                        'lang' => array(), 
     145                        'style' => array (), 
     146                        'xml:lang' => array(), 
     147                ), 
     148                'figcaption' => array( 
     149                        'align' => array (), 
     150                        'class' => array (), 
     151                        'dir' => array (), 
     152                        'lang' => array(), 
     153                        'style' => array (), 
     154                        'xml:lang' => array(), 
     155                ), 
    108156                'font' => array( 
    109157                        'color' => array (), 
    110158                        'face' => array (), 
    111159                        'size' => array ()), 
     160                'footer' => array( 
     161                        'align' => array (), 
     162                        'class' => array (), 
     163                        'dir' => array (), 
     164                        'lang' => array(), 
     165                        'style' => array (), 
     166                        'xml:lang' => array(), 
     167                ), 
    112168                'form' => array( 
    113169                        'action' => array (), 
    114170                        'accept' => array (), 
     
    147203                        'class' => array (), 
    148204                        'id'    => array (), 
    149205                        'style' => array ()), 
     206                'header' => array( 
     207                        'align' => array (), 
     208                        'class' => array (), 
     209                        'dir' => array (), 
     210                        'lang' => array(), 
     211                        'style' => array (), 
     212                        'xml:lang' => array(), 
     213                ), 
     214                'hgroup' => array( 
     215                        'align' => array (), 
     216                        'class' => array (), 
     217                        'dir' => array (), 
     218                        'lang' => array(), 
     219                        'style' => array (), 
     220                        'xml:lang' => array(), 
     221                ), 
    150222                'hr' => array ( 
    151223                        'align' => array (), 
    152224                        'class' => array (), 
     
    177249                'li' => array ( 
    178250                        'align' => array (), 
    179251                        'class' => array ()), 
     252                'menu' => array ( 
     253                        'class' => array (), 
     254                        'style' => array (), 
     255                        'type' => array ()), 
     256                'nav' => array( 
     257                        'align' => array (), 
     258                        'class' => array (), 
     259                        'dir' => array (), 
     260                        'lang' => array(), 
     261                        'style' => array (), 
     262                        'xml:lang' => array(), 
     263                ), 
    180264                'p' => array( 
    181265                        'class' => array (), 
    182266                        'align' => array (), 
     
    198282                        'style' => array (), 
    199283                        'title' => array (), 
    200284                        'xml:lang' => array()), 
     285                'section' => array( 
     286                        'align' => array (), 
     287                        'class' => array (), 
     288                        'dir' => array (), 
     289                        'lang' => array(), 
     290                        'style' => array (), 
     291                        'xml:lang' => array(), 
     292                ), 
    201293                'strike' => array(), 
    202294                'strong' => array(), 
    203295                'sub' => array(), 
     296                'summary' => array( 
     297                        'align' => array (), 
     298                        'class' => array (), 
     299                        'dir' => array (), 
     300                        'lang' => array(), 
     301                        'style' => array (), 
     302                        'xml:lang' => array(), 
     303                ), 
    204304                'sup' => array(), 
    205305                'table' => array( 
    206306                        'align' => array (), 
     
    333433                //      'u' => array(), 
    334434                //      'ul' => array(), 
    335435        ); 
     436 
     437        $allowedentitynames = array( 
     438                'nbsp',    'iexcl',  'cent',    'pound',  'curren', 'yen', 
     439                'brvbar',  'sect',   'uml',     'copy',   'ordf',   'laquo', 
     440                'not',     'shy',    'reg',     'macr',   'deg',    'plusmn', 
     441                'acute',   'micro',  'para',    'middot', 'cedil',  'ordm', 
     442                'raquo',   'iquest', 'Agrave',  'Aacute', 'Acirc',  'Atilde', 
     443                'Auml',    'Aring',  'AElig',   'Ccedil', 'Egrave', 'Eacute', 
     444                'Ecirc',   'Euml',   'Igrave',  'Iacute', 'Icirc',  'Iuml', 
     445                'ETH',     'Ntilde', 'Ograve',  'Oacute', 'Ocirc',  'Otilde', 
     446                'Ouml',    'times',  'Oslash',  'Ugrave', 'Uacute', 'Ucirc', 
     447                'Uuml',    'Yacute', 'THORN',   'szlig',  'agrave', 'aacute', 
     448                'acirc',   'atilde', 'auml',    'aring',  'aelig',  'ccedil', 
     449                'egrave',  'eacute', 'ecirc',   'euml',   'igrave', 'iacute', 
     450                'icirc',   'iuml',   'eth',     'ntilde', 'ograve', 'oacute', 
     451                'ocirc',   'otilde', 'ouml',    'divide', 'oslash', 'ugrave', 
     452                'uacute',  'ucirc',  'uuml',    'yacute', 'thorn',  'yuml', 
     453                'quot',    'amp',    'lt',      'gt',     'apos',   'OElig', 
     454                'oelig',   'Scaron', 'scaron',  'Yuml',   'circ',   'tilde', 
     455                'ensp',    'emsp',   'thinsp',  'zwnj',   'zwj',    'lrm', 
     456                'rlm',     'ndash',  'mdash',   'lsquo',  'rsquo',  'sbquo', 
     457                'ldquo',   'rdquo',  'bdquo',   'dagger', 'Dagger', 'permil', 
     458                'lsaquo',  'rsaquo', 'euro',    'fnof',   'Alpha',  'Beta', 
     459                'Gamma',   'Delta',  'Epsilon', 'Zeta',   'Eta',    'Theta', 
     460                'Iota',    'Kappa',  'Lambda',  'Mu',     'Nu',     'Xi', 
     461                'Omicron', 'Pi',     'Rho',     'Sigma',  'Tau',    'Upsilon', 
     462                'Phi',     'Chi',    'Psi',     'Omega',  'alpha',  'beta', 
     463                'gamma',   'delta',  'epsilon', 'zeta',   'eta',    'theta', 
     464                'iota',    'kappa',  'lambda',  'mu',     'nu',     'xi', 
     465                'omicron', 'pi',     'rho',     'sigmaf', 'sigma',  'tau', 
     466                'upsilon', 'phi',    'chi',     'psi',    'omega',  'thetasym', 
     467                'upsih',   'piv',    'bull',    'hellip', 'prime',  'Prime', 
     468                'oline',   'frasl',  'weierp',  'image',  'real',   'trade', 
     469                'alefsym', 'larr',   'uarr',    'rarr',   'darr',   'harr', 
     470                'crarr',   'lArr',   'uArr',    'rArr',   'dArr',   'hArr', 
     471                'forall',  'part',   'exist',   'empty',  'nabla',  'isin', 
     472                'notin',   'ni',     'prod',    'sum',    'minus',  'lowast', 
     473                'radic',   'prop',   'infin',   'ang',    'and',    'or', 
     474                'cap',     'cup',    'int',     'sim',    'cong',   'asymp', 
     475                'ne',      'equiv',  'le',      'ge',     'sub',    'sup', 
     476                'nsub',    'sube',   'supe',    'oplus',  'otimes', 'perp', 
     477                'sdot',    'lceil',  'rceil',   'lfloor', 'rfloor', 'lang', 
     478                'rang',    'loz',    'spades',  'clubs',  'hearts', 'diams', 
     479        ); 
    336480} 
    337481 
    338482/** 
     
    344488 * call this function. 
    345489 * 
    346490 * The default allowed protocols are 'http', 'https', 'ftp', 'mailto', 'news', 
    347  * 'irc', 'gopher', 'nntp', 'feed', and finally 'telnet. This covers all common 
    348  * link protocols, except for 'javascript' which should not be allowed for 
    349  * untrusted users. 
     491 * 'irc', 'gopher', 'nntp', 'feed', 'telnet, 'mms', 'rtsp' and 'svn'. This 
     492 * covers all common link protocols, except for 'javascript' which should not 
     493 * be allowed for untrusted users. 
    350494 * 
    351495 * @since 1.0.0 
    352496 * 
     
    355499 * @param array $allowed_protocols Optional. Allowed protocol in links. 
    356500 * @return string Filtered content with only allowed HTML elements 
    357501 */ 
    358 function wp_kses($string, $allowed_html, $allowed_protocols = array ('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet')) { 
     502function wp_kses($string, $allowed_html, $allowed_protocols = array ()) { 
     503        $allowed_protocols = wp_parse_args( $allowed_protocols, apply_filters('kses_allowed_protocols', array ('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn') )); 
    359504        $string = wp_kses_no_null($string); 
    360505        $string = wp_kses_js_entities($string); 
    361506        $string = wp_kses_normalize_entities($string); 
     
    409554        global $pass_allowed_html, $pass_allowed_protocols; 
    410555        $pass_allowed_html = $allowed_html; 
    411556        $pass_allowed_protocols = $allowed_protocols; 
    412         return preg_replace_callback('%((<!--.*?(-->|$))|(<[^>]*(>|$)|>))%', 
    413                 create_function('$match', 'global $pass_allowed_html, $pass_allowed_protocols; return wp_kses_split2($match[1], $pass_allowed_html, $pass_allowed_protocols);'), $string); 
     557        return preg_replace_callback( '%((<!--.*?(-->|$))|(<[^>]*(>|$)|>))%', '_wp_kses_split_callback', $string ); 
    414558} 
    415559 
    416560/** 
     561 * Callback for wp_kses_split. 
     562 * 
     563 * @since 3.1.0 
     564 * @access private 
     565 */ 
     566function _wp_kses_split_callback( $match ) { 
     567        global $pass_allowed_html, $pass_allowed_protocols; 
     568        return wp_kses_split2( $match[1], $pass_allowed_html, $pass_allowed_protocols ); 
     569} 
     570 
     571/** 
    417572 * Callback for wp_kses_split for fixing malformed HTML tags. 
    418573 * 
    419574 * This function does a lot of work. It rejects some very malformed things like 
     
    495650        # Is there a closing XHTML slash at the end of the attributes? 
    496651 
    497652        $xhtml_slash = ''; 
    498         if (preg_match('%\s/\s*$%', $attr)) 
     653        if (preg_match('%\s*/\s*$%', $attr)) 
    499654                $xhtml_slash = ' /'; 
    500655 
    501656        # Are any attributes allowed at all for this element? 
     
    533688                                        break; 
    534689                                } 
    535690 
    536                         if ( $arreach['name'] == 'style' ) { 
     691                        if ( strtolower($arreach['name']) == 'style' ) { 
    537692                                $orig_value = $arreach['value']; 
    538693 
    539694                                $value = safecss_filter_attr($orig_value); 
     
    621776 
    622777                        case 2 : # attribute value, a URL after href= for instance 
    623778 
    624                                 if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match)) 
     779                                if (preg_match('%^"([^"]*)"(\s+|/?$)%', $attr, $match)) 
    625780                                        # "value" 
    626781                                        { 
    627782                                        $thisval = $match[1]; 
    628                                         if ( in_array($attrname, $uris) ) 
     783                                        if ( in_array(strtolower($attrname), $uris) ) 
    629784                                                $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); 
    630785 
    631786                                        if(FALSE === array_key_exists($attrname, $attrarr)) { 
     
    637792                                        break; 
    638793                                } 
    639794 
    640                                 if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match)) 
     795                                if (preg_match("%^'([^']*)'(\s+|/?$)%", $attr, $match)) 
    641796                                        # 'value' 
    642797                                        { 
    643798                                        $thisval = $match[1]; 
    644                                         if ( in_array($attrname, $uris) ) 
     799                                        if ( in_array(strtolower($attrname), $uris) ) 
    645800                                                $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); 
    646801 
    647802                                        if(FALSE === array_key_exists($attrname, $attrarr)) { 
     
    653808                                        break; 
    654809                                } 
    655810 
    656                                 if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match)) 
     811                                if (preg_match("%^([^\s\"']+)(\s+|/?$)%", $attr, $match)) 
    657812                                        # value 
    658813                                        { 
    659814                                        $thisval = $match[1]; 
    660                                         if ( in_array($attrname, $uris) ) 
     815                                        if ( in_array(strtolower($attrname), $uris) ) 
    661816                                                $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); 
    662817 
    663818                                        if(FALSE === array_key_exists($attrname, $attrarr)) { 
     
    699854 * @param string $vless Whether the value is valueless or not. Use 'y' or 'n' 
    700855 * @param string $checkname What $checkvalue is checking for. 
    701856 * @param mixed $checkvalue What constraint the value should pass 
    702  * @return bool Whether check passes (true) or not (false) 
     857 * @return bool Whether check passes 
    703858 */ 
    704859function wp_kses_check_attr_val($value, $vless, $checkname, $checkvalue) { 
    705860        $ok = true; 
     
    8801035 * @return string Sanitized content 
    8811036 */ 
    8821037function wp_kses_bad_protocol_once($string, $allowed_protocols) { 
    883         global $_kses_allowed_protocols; 
    884         $_kses_allowed_protocols = $allowed_protocols; 
     1038        $string2 = preg_split( '/:|&#0*58;|&#x0*3a;/i', $string, 2 ); 
     1039        if ( isset($string2[1]) && ! preg_match('%/\?%', $string2[0]) ) 
     1040                $string = wp_kses_bad_protocol_once2( $string2[0], $allowed_protocols ) . trim( $string2[1] ); 
    8851041 
    886         $string2 = preg_split('/:|&#58;|&#x3a;/i', $string, 2); 
    887         if ( isset($string2[1]) && !preg_match('%/\?%', $string2[0]) ) 
    888                 $string = wp_kses_bad_protocol_once2($string2[0]) . trim($string2[1]); 
    889         else 
    890                 $string = preg_replace_callback('/^((&[^;]*;|[\sA-Za-z0-9])*)'.'(:|&#58;|&#[Xx]3[Aa];)\s*/', 'wp_kses_bad_protocol_once2', $string); 
    891  
    8921042        return $string; 
    8931043} 
    8941044 
     
    9011051 * @access private 
    9021052 * @since 1.0.0 
    9031053 * 
    904  * @param mixed $matches string or preg_replace_callback() matches array to check for bad protocols 
     1054 * @param string $string URI scheme to check against the whitelist 
     1055 * @param string $allowed_protocols Allowed protocols 
    9051056 * @return string Sanitized content 
    9061057 */ 
    907 function wp_kses_bad_protocol_once2($matches) { 
    908         global $_kses_allowed_protocols; 
    909  
    910         if ( is_array($matches) ) { 
    911                 if ( ! isset($matches[1]) || empty($matches[1]) ) 
    912                         return ''; 
    913  
    914                 $string = $matches[1]; 
    915         } else { 
    916                 $string = $matches; 
    917         } 
    918  
     1058function wp_kses_bad_protocol_once2( $string, $allowed_protocols ) { 
    9191059        $string2 = wp_kses_decode_entities($string); 
    9201060        $string2 = preg_replace('/\s/', '', $string2); 
    9211061        $string2 = wp_kses_no_null($string2); 
    9221062        $string2 = strtolower($string2); 
    9231063 
    9241064        $allowed = false; 
    925         foreach ( (array) $_kses_allowed_protocols as $one_protocol) 
    926                 if (strtolower($one_protocol) == $string2) { 
     1065        foreach ( (array) $allowed_protocols as $one_protocol ) 
     1066                if ( strtolower($one_protocol) == $string2 ) { 
    9271067                        $allowed = true; 
    9281068                        break; 
    9291069                } 
     
    9521092 
    9531093        # Change back the allowed entities in our entity whitelist 
    9541094 
    955         $string = preg_replace('/&amp;([A-Za-z][A-Za-z0-9]{0,19});/', '&\\1;', $string); 
    956         $string = preg_replace_callback('/&amp;#0*([0-9]{1,5});/', 'wp_kses_normalize_entities2', $string); 
    957         $string = preg_replace_callback('/&amp;#([Xx])0*(([0-9A-Fa-f]{2}){1,2});/', 'wp_kses_normalize_entities3', $string); 
     1095        $string = preg_replace_callback('/&amp;([A-Za-z]{2,8});/', 'wp_kses_named_entities', $string); 
     1096        $string = preg_replace_callback('/&amp;#(0*[0-9]{1,7});/', 'wp_kses_normalize_entities2', $string); 
     1097        $string = preg_replace_callback('/&amp;#[Xx](0*[0-9A-Fa-f]{1,6});/', 'wp_kses_normalize_entities3', $string); 
    9581098 
    9591099        return $string; 
    9601100} 
     
    9621102/** 
    9631103 * Callback for wp_kses_normalize_entities() regular expression. 
    9641104 * 
     1105 * This function only accepts valid named entity references, which are finite, 
     1106 * case-sensitive, and highly scrutinized by HTML and XML validators. 
     1107 * 
     1108 * @since 3.0.0 
     1109 * 
     1110 * @param array $matches preg_replace_callback() matches array 
     1111 * @return string Correctly encoded entity 
     1112 */ 
     1113function wp_kses_named_entities($matches) { 
     1114        global $allowedentitynames; 
     1115 
     1116        if ( empty($matches[1]) ) 
     1117                return ''; 
     1118 
     1119        $i = $matches[1]; 
     1120        return ( ( ! in_array($i, $allowedentitynames) ) ? "&amp;$i;" : "&$i;" ); 
     1121} 
     1122 
     1123/** 
     1124 * Callback for wp_kses_normalize_entities() regular expression. 
     1125 * 
    9651126 * This function helps wp_kses_normalize_entities() to only accept 16 bit values 
    9661127 * and nothing more for &#number; entities. 
    9671128 * 
     
    9721133 * @return string Correctly encoded entity 
    9731134 */ 
    9741135function wp_kses_normalize_entities2($matches) { 
    975         if ( ! isset($matches[1]) || empty($matches[1]) ) 
     1136        if ( empty($matches[1]) ) 
    9761137                return ''; 
    9771138 
    9781139        $i = $matches[1]; 
    979         return ( ( ! valid_unicode($i) ) || ($i > 65535) ? "&amp;#$i;" : "&#$i;" ); 
     1140        if (valid_unicode($i)) { 
     1141                $i = str_pad(ltrim($i,'0'), 3, '0', STR_PAD_LEFT); 
     1142                $i = "&#$i;"; 
     1143        } else { 
     1144                $i = "&amp;#$i;"; 
     1145        } 
     1146 
     1147        return $i; 
    9801148} 
    9811149 
    9821150/** 
     
    9911159 * @return string Correctly encoded entity 
    9921160 */ 
    9931161function wp_kses_normalize_entities3($matches) { 
    994         if ( ! isset($matches[2]) || empty($matches[2]) ) 
     1162        if ( empty($matches[1]) ) 
    9951163                return ''; 
    9961164 
    997         $hexchars = $matches[2]; 
    998         return ( ( ! valid_unicode(hexdec($hexchars)) ) ? "&amp;#x$hexchars;" : "&#x$hexchars;" ); 
     1165        $hexchars = $matches[1]; 
     1166        return ( ( ! valid_unicode(hexdec($hexchars)) ) ? "&amp;#x$hexchars;" : '&#x'.ltrim($hexchars,'0').';' ); 
    9991167} 
    10001168 
    10011169/** 
     
    11961364add_action('init', 'kses_init'); 
    11971365add_action('set_current_user', 'kses_init'); 
    11981366 
     1367/** 
     1368 * Inline CSS filter 
     1369 * 
     1370 * @since 2.8.1 
     1371 */ 
    11991372function safecss_filter_attr( $css, $deprecated = '' ) { 
    12001373        $css = wp_kses_no_null($css); 
    12011374        $css = str_replace(array("\n","\r","\t"), '', $css); 
    12021375 
    1203         if ( preg_match( '%[\\(&]|/\*%', $css ) ) // remove any inline css containing \ ( & or comments 
     1376        if ( preg_match( '%[\\(&=}]|/\*%', $css ) ) // remove any inline css containing \ ( & } = or comments 
    12041377                return ''; 
    12051378 
    1206         $css_array = split( ';', trim( $css ) ); 
     1379        $css_array = explode( ';', trim( $css ) ); 
    12071380        $allowed_attr = apply_filters( 'safe_style_css', array( 'text-align', 'margin', 'color', 'float', 
    12081381        'border', 'background', 'background-color', 'border-bottom', 'border-bottom-color', 
    12091382        'border-bottom-style', 'border-bottom-width', 'border-collapse', 'border-color', 'border-left',