Fix message cache expiry semantics
[lhc/web/wiklou.git] / includes / Sanitizer.php
index 9cac308..3acb740 100644 (file)
@@ -358,9 +358,9 @@ class Sanitizer {
         * @private
         * @param $text String
         * @param $processCallback Callback to do any variable or parameter replacements in HTML attribute values
-        * @param $args Array for the processing callback
-        * @param $extratags Array for any extra tags to include
-        * @param $removetags Array for any tags (default or extra) to exclude
+        * @param array $args for the processing callback
+        * @param array $extratags for any extra tags to include
+        * @param array $removetags for any tags (default or extra) to exclude
         * @return string
         */
        static function removeHTMLtags( $text, $processCallback = null, $args = array(), $extratags = array(), $removetags = array() ) {
@@ -372,7 +372,7 @@ class Sanitizer {
                wfProfileIn( __METHOD__ );
 
                // Base our staticInitialised variable off of the global config state so that if the globals
-               // are changed (like in the secrewed up test system) we will re-initialise the settings.
+               // are changed (like in the screwed up test system) we will re-initialise the settings.
                $globalContext = implode( '-', compact( 'wgHtml5', 'wgAllowMicrodataAttributes', 'wgAllowImageTag' ) );
                if ( !$staticInitialised || $staticInitialised != $globalContext ) {
 
@@ -381,7 +381,7 @@ class Sanitizer {
                                'h2', 'h3', 'h4', 'h5', 'h6', 'cite', 'code', 'em', 's',
                                'strike', 'strong', 'tt', 'var', 'div', 'center',
                                'blockquote', 'ol', 'ul', 'dl', 'table', 'caption', 'pre',
-                               'ruby', 'rt' , 'rb' , 'rp', 'p', 'span', 'abbr', 'dfn',
+                               'ruby', 'rt', 'rb', 'rp', 'p', 'span', 'abbr', 'dfn',
                                'kbd', 'samp'
                        );
                        if ( $wgHtml5 ) {
@@ -507,14 +507,14 @@ class Sanitizer {
                                                !in_array( 'table', $tagstack ) ) {
                                                        $badtag = true;
                                                } elseif ( in_array( $t, $tagstack ) &&
-                                               !isset( $htmlnest [$t ] ) ) {
+                                               !isset( $htmlnest[$t] ) ) {
                                                        $badtag = true;
                                                # Is it a self closed htmlpair ? (bug 5487)
                                                } elseif ( $brace == '/>' &&
                                                isset( $htmlpairs[$t] ) ) {
                                                        $badtag = true;
                                                } elseif ( isset( $htmlsingleonly[$t] ) ) {
-                                                       # Hack to force empty tag for uncloseable elements
+                                                       # Hack to force empty tag for unclosable elements
                                                        $brace = '/>';
                                                } elseif ( isset( $htmlsingle[$t] ) ) {
                                                        # Hack to not close $htmlsingle tags
@@ -555,12 +555,14 @@ class Sanitizer {
                                                continue;
                                        }
                                }
-                               $text .= '<' . str_replace( '>', '>', $x);
+                               $text .= '<' . str_replace( '>', '>', $x );
                        }
                        # Close off any remaining tags
-                       while ( is_array( $tagstack ) && ($t = array_pop( $tagstack )) ) {
+                       while ( is_array( $tagstack ) && ( $t = array_pop( $tagstack ) ) ) {
                                $text .= "</$t>\n";
-                               if ( $t == 'table' ) { $tagstack = array_pop( $tablestack ); }
+                               if ( $t == 'table' ) {
+                                       $tagstack = array_pop( $tablestack );
+                               }
                        }
                } else {
                        # this might be possible using tidy itself
@@ -585,7 +587,7 @@ class Sanitizer {
                                                continue;
                                        }
                                }
-                               $text .= '&lt;' . str_replace( '>', '&gt;', $x);
+                               $text .= '&lt;' . str_replace( '>', '&gt;', $x );
                        }
                }
                wfProfileOut( __METHOD__ );
@@ -604,9 +606,9 @@ class Sanitizer {
         */
        static function removeHTMLcomments( $text ) {
                wfProfileIn( __METHOD__ );
-               while (($start = strpos($text, '<!--')) !== false) {
-                       $end = strpos($text, '-->', $start + 4);
-                       if ($end === false) {
+               while ( ($start = strpos( $text, '<!--' ) ) !== false ) {
+                       $end = strpos( $text, '-->', $start + 4 );
+                       if ( $end === false ) {
                                # Unterminated comment; bail out
                                break;
                        }
@@ -615,22 +617,22 @@ class Sanitizer {
 
                        # Trim space and newline if the comment is both
                        # preceded and followed by a newline
-                       $spaceStart = max($start - 1, 0);
+                       $spaceStart = max( $start - 1, 0 );
                        $spaceLen = $end - $spaceStart;
-                       while (substr($text, $spaceStart, 1) === ' ' && $spaceStart > 0) {
+                       while ( substr( $text, $spaceStart, 1 ) === ' ' && $spaceStart > 0 ) {
                                $spaceStart--;
                                $spaceLen++;
                        }
-                       while (substr($text, $spaceStart + $spaceLen, 1) === ' ')
+                       while ( substr( $text, $spaceStart + $spaceLen, 1 ) === ' ' )
                                $spaceLen++;
-                       if (substr($text, $spaceStart, 1) === "\n" and substr($text, $spaceStart + $spaceLen, 1) === "\n") {
+                       if ( substr( $text, $spaceStart, 1 ) === "\n" and substr( $text, $spaceStart + $spaceLen, 1 ) === "\n" ) {
                                # Remove the comment, leading and trailing
                                # spaces, and leave only one newline.
-                               $text = substr_replace($text, "\n", $spaceStart, $spaceLen + 1);
+                               $text = substr_replace( $text, "\n", $spaceStart, $spaceLen + 1 );
                        }
                        else {
                                # Remove just the comment.
-                               $text = substr_replace($text, '', $start, $end - $start);
+                               $text = substr_replace( $text, '', $start, $end - $start );
                        }
                }
                wfProfileOut( __METHOD__ );
@@ -647,6 +649,7 @@ class Sanitizer {
         *
         * @param $params
         * @param $element
+        * @return bool
         */
        static function validateTag( $params, $element ) {
                $params = Sanitizer::decodeTagAttributes( $params );
@@ -675,7 +678,7 @@ class Sanitizer {
         *
         * - Discards attributes not on a whitelist for the given element
         * - Unsafe style attributes are discarded
-        * - Invalid id attributes are reencoded
+        * - Invalid id attributes are re-encoded
         *
         * @param $attribs Array
         * @param $element String
@@ -695,10 +698,10 @@ class Sanitizer {
         *
         * - Discards attributes not the given whitelist
         * - Unsafe style attributes are discarded
-        * - Invalid id attributes are reencoded
+        * - Invalid id attributes are re-encoded
         *
         * @param $attribs Array
-        * @param $whitelist Array: list of allowed attribute names
+        * @param array $whitelist list of allowed attribute names
         * @return Array
         *
         * @todo Check for legal values where the DTD limits things.
@@ -722,7 +725,7 @@ class Sanitizer {
                        }
 
                        # Allow any attribute beginning with "data-", if in HTML5 mode
-                       if ( !($wgHtml5 && preg_match( '/^data-/i', $attribute )) && !isset( $whitelist[$attribute] ) ) {
+                       if ( !( $wgHtml5 && preg_match( '/^data-/i', $attribute ) ) && !isset( $whitelist[$attribute] ) ) {
                                continue;
                        }
 
@@ -736,6 +739,16 @@ class Sanitizer {
                                $value = Sanitizer::escapeId( $value, 'noninitial' );
                        }
 
+                       # WAI-ARIA
+                       # http://www.w3.org/TR/wai-aria/
+                       # http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#wai-aria
+                       # For now we only support role="presentation" until we work out what roles should be
+                       # usable by content and we ensure that our code explicitly rejects patterns that
+                       # violate HTML5's ARIA restrictions.
+                       if ( $attribute === 'role' && $value !== 'presentation' ) {
+                               continue;
+                       }
+
                        //RDFa and microdata properties allow URLs, URIs and/or CURIs. check them for sanity
                        if ( $attribute === 'rel' || $attribute === 'rev' ||
                                $attribute === 'about' || $attribute === 'property' || $attribute === 'resource' || #RDFa
@@ -1002,7 +1015,7 @@ class Sanitizer {
         * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#the-id-attribute
         *   HTML5 definition of id attribute
         *
-        * @param $id String: id to escape
+        * @param string $id id to escape
         * @param $options Mixed: string or array of strings (default is array()):
         *   'noninitial': This is a non-initial fragment of an id, not a full id,
         *       so don't pay attention if the first character isn't valid at the
@@ -1059,17 +1072,17 @@ class Sanitizer {
         */
        static function escapeClass( $class ) {
                // Convert ugly stuff to underscores and kill underscores in ugly places
-               return rtrim(preg_replace(
-                       array('/(^[0-9\\-])|[\\x00-\\x20!"#$%&\'()*+,.\\/:;<=>?@[\\]^`{|}~]|\\xC2\\xA0/','/_+/'),
+               return rtrim( preg_replace(
+                       array( '/(^[0-9\\-])|[\\x00-\\x20!"#$%&\'()*+,.\\/:;<=>?@[\\]^`{|}~]|\\xC2\\xA0/', '/_+/' ),
                        '_',
-                       $class ), '_');
+                       $class ), '_' );
        }
 
        /**
-        * Given HTML input, escape with htmlspecialchars but un-escape entites.
+        * Given HTML input, escape with htmlspecialchars but un-escape entities.
         * This allows (generally harmless) entities like &#160; to survive.
         *
-        * @param $html String to escape
+        * @param string $html to escape
         * @return String: escaped input
         */
        static function escapeHtmlAllowEntities( $html ) {
@@ -1227,7 +1240,7 @@ class Sanitizer {
                        $ret = Sanitizer::normalizeEntity( $matches[1] );
                } elseif( $matches[2] != '' ) {
                        $ret = Sanitizer::decCharReference( $matches[2] );
-               } elseif( $matches[3] != ''  ) {
+               } elseif( $matches[3] != '' ) {
                        $ret = Sanitizer::hexCharReference( $matches[3] );
                }
                if( is_null( $ret ) ) {
@@ -1321,7 +1334,7 @@ class Sanitizer {
         * This is useful for page titles, not for text to be displayed,
         * MediaWiki allows HTML entities to escape normalization as a feature.
         *
-        * @param $text String (already normalized, containing entities)
+        * @param string $text (already normalized, containing entities)
         * @return String (still normalized, without entities)
         */
        public static function decodeCharReferencesAndNormalize( $text ) {
@@ -1346,9 +1359,9 @@ class Sanitizer {
                if( $matches[1] != '' ) {
                        return Sanitizer::decodeEntity( $matches[1] );
                } elseif( $matches[2] != '' ) {
-                       return  Sanitizer::decodeChar( intval( $matches[2] ) );
-               } elseif( $matches[3] != ''  ) {
-                       return  Sanitizer::decodeChar( hexdec( $matches[3] ) );
+                       return Sanitizer::decodeChar( intval( $matches[2] ) );
+               } elseif( $matches[3] != '' ) {
+                       return Sanitizer::decodeChar( hexdec( $matches[3] ) );
                }
                # Last case should be an ampersand by itself
                return $matches[0];
@@ -1416,35 +1429,47 @@ class Sanitizer {
                        return $whitelist;
                }
 
-               $common = array( 'id', 'class', 'lang', 'dir', 'title', 'style' );
+               $common = array(
+                       # HTML
+                       'id',
+                       'class',
+                       'style',
+                       'lang',
+                       'dir',
+                       'title',
+
+                       # WAI-ARIA
+                       'role',
+               );
 
                if ( $wgAllowRdfaAttributes ) {
                        #RDFa attributes as specified in section 9 of http://www.w3.org/TR/2008/REC-rdfa-syntax-20081014
                        $common = array_merge( $common, array(
-                           'about', 'property', 'resource', 'datatype', 'typeof',
+                               'about', 'property', 'resource', 'datatype', 'typeof',
                        ) );
                }
 
                if ( $wgHtml5 && $wgAllowMicrodataAttributes ) {
-                       # add HTML5 microdata tages as pecified by http://www.whatwg.org/specs/web-apps/current-work/multipage/microdata.html#the-microdata-model
+                       # add HTML5 microdata tags as specified by http://www.whatwg.org/specs/web-apps/current-work/multipage/microdata.html#the-microdata-model
                        $common = array_merge( $common, array(
-                           'itemid', 'itemprop', 'itemref', 'itemscope', 'itemtype'
+                               'itemid', 'itemprop', 'itemref', 'itemscope', 'itemtype'
                        ) );
                }
 
                $block = array_merge( $common, array( 'align' ) );
                $tablealign = array( 'align', 'char', 'charoff', 'valign' );
-               $tablecell = array( 'abbr',
-                                   'axis',
-                                   'headers',
-                                   'scope',
-                                   'rowspan',
-                                   'colspan',
-                                   'nowrap', # deprecated
-                                   'width',  # deprecated
-                                   'height', # deprecated
-                                   'bgcolor' # deprecated
-                                   );
+               $tablecell = array(
+                       'abbr',
+                       'axis',
+                       'headers',
+                       'scope',
+                       'rowspan',
+                       'colspan',
+                       'nowrap', # deprecated
+                       'width', # deprecated
+                       'height', # deprecated
+                       'bgcolor', # deprecated
+               );
 
                # Numbers refer to sections in HTML 4.01 standard describing the element.
                # See: http://www.w3.org/TR/html4/
@@ -1612,7 +1637,7 @@ class Sanitizer {
         * Warning: this return value must be further escaped for literal
         * inclusion in HTML output as of 1.10!
         *
-        * @param $text String: HTML fragment
+        * @param string $text HTML fragment
         * @return String
         */
        static function stripAllTags( $text ) {
@@ -1724,7 +1749,7 @@ class Sanitizer {
         *
         * @since 1.18
         *
-        * @param $addr String E-mail address
+        * @param string $addr E-mail address
         * @return Bool
         */
        public static function validateEmail( $addr ) {
@@ -1736,8 +1761,8 @@ class Sanitizer {
                // Please note strings below are enclosed in brackets [], this make the
                // hyphen "-" a range indicator. Hence it is double backslashed below.
                // See bug 26948
-               $rfc5322_atext   = "a-z0-9!#$%&'*+\\-\/=?^_`{|}~" ;
-               $rfc1034_ldh_str = "a-z0-9\\-" ;
+               $rfc5322_atext = "a-z0-9!#$%&'*+\\-\/=?^_`{|}~";
+               $rfc1034_ldh_str = "a-z0-9\\-";
 
                $HTML5_email_regexp = "/
                ^                      # start of string
@@ -1746,7 +1771,7 @@ class Sanitizer {
                [$rfc1034_ldh_str]+       # First domain part
                (\\.[$rfc1034_ldh_str]+)*  # Following part prefixed with a dot
                $                      # End of string
-               /ix" ; // case Insensitive, eXtended
+               /ix"; // case Insensitive, eXtended
 
                return (bool) preg_match( $HTML5_email_regexp, $addr );
        }