* (bug 23276) Add hook to Special:NewPages to modify query
[lhc/web/wiklou.git] / includes / Sanitizer.php
index 9dd648c..3d9317e 100644 (file)
@@ -389,6 +389,12 @@ class Sanitizer {
                                'li',
                        );
 
+                       global $wgAllowImageTag;
+                       if ( $wgAllowImageTag ) {
+                               $htmlsingle[] = 'img';
+                               $htmlsingleonly[] = 'img';
+                       }
+
                        $htmlsingleallowed = array_unique( array_merge( $htmlsingle, $tabletags ) );
                        $htmlelementsStatic = array_unique( array_merge( $htmlsingle, $htmlpairsStatic, $htmlnest ) );
 
@@ -738,24 +744,48 @@ class Sanitizer {
         * @return Mixed
         */
        static function checkCss( $value ) {
-               $stripped = Sanitizer::decodeCharReferences( $value );
+               $value = Sanitizer::decodeCharReferences( $value );
 
                // Remove any comments; IE gets token splitting wrong
-               $stripped = StringUtils::delimiterReplace( '/*', '*/', ' ', $stripped );
-
-               $value = $stripped;
-
-               // ... and continue checks
-               $stripped = preg_replace( '!\\\\([0-9A-Fa-f]{1,6})[ \\n\\r\\t\\f]?!e',
-                       'codepointToUtf8(hexdec("$1"))', $stripped );
-               $stripped = str_replace( '\\', '', $stripped );
-               if( preg_match( '/(?:expression|tps*:\/\/|url\\s*\().*/is',
-                               $stripped ) ) {
-                       # haxx0r
+               $value = StringUtils::delimiterReplace( '/*', '*/', ' ', $value );
+
+               // Decode escape sequences and line continuation
+               // See the grammar in the CSS 2 spec, appendix D, Mozilla implements it accurately.
+               // IE 8 doesn't implement it at all, but there's no way to introduce url() into
+               // IE that doesn't hit Mozilla also.
+               static $decodeRegex;
+               if ( !$decodeRegex ) {
+                       $space = '[\\x20\\t\\r\\n\\f]';
+                       $nl = '(?:\\n|\\r\\n|\\r|\\f)';
+                       $backslash = '\\\\';
+                       $decodeRegex = "/ $backslash 
+                               (?:
+                                       ($nl) |  # 1. Line continuation
+                                       ([0-9A-Fa-f]{1,6})$space? |  # 2. character number
+                                       (.) # 3. backslash cancelling special meaning
+                               )/xu";
+               }
+               $decoded = preg_replace_callback( $decodeRegex, 
+                       array( __CLASS__, 'cssDecodeCallback' ), $value );
+               if ( preg_match( '!expression|https?://|url\s*\(!i', $decoded ) ) {
+                       // Not allowed
                        return false;
+               } else {
+                       // Allowed, return CSS with comments stripped
+                       return $value;
                }
+       }
 
-               return $value;
+       static function cssDecodeCallback( $matches ) {
+               if ( $matches[1] !== '' ) {
+                       return '';
+               } elseif ( $matches[2] !== '' ) {
+                       return codepointToUtf8( hexdec( $matches[2] ) );
+               } elseif ( $matches[3] !== '' ) {
+                       return $matches[3];
+               } else {
+                       throw new MWException( __METHOD__.': invalid match' );
+               }
        }
 
        /**
@@ -857,6 +887,7 @@ class Sanitizer {
         *
         * To ensure we don't have to bother escaping anything, we also strip ', ",
         * & even if $wgExperimentalIds is true.  TODO: Is this the best tactic?
+        * We also strip # because it upsets IE6.
         *
         * @see http://www.w3.org/TR/html401/types.html#type-name Valid characters
         *                                                          in the id and
@@ -881,7 +912,8 @@ class Sanitizer {
                $options = (array)$options;
 
                if ( $wgHtml5 && $wgExperimentalHtmlIds && !in_array( 'legacy', $options ) ) {
-                       $id = preg_replace( '/[ \t\n\r\f_\'"&]+/', '_', $id );
+                       $id = Sanitizer::decodeCharReferences( $id );
+                       $id = preg_replace( '/[ \t\n\r\f_\'"&#]+/', '_', $id );
                        $id = trim( $id, '_' );
                        if ( $id === '' ) {
                                # Must have been all whitespace to start with.
@@ -1150,6 +1182,30 @@ class Sanitizer {
                        $text );
        }
 
+       /**
+        * Decode any character references, numeric or named entities,
+        * in the next and normalize the resulting string. (bug 14952)
+        *
+        * 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)
+        * @return String (still normalized, without entities)
+        */
+       public static function decodeCharReferencesAndNormalize( $text ) {
+               global $wgContLang;
+               $text = preg_replace_callback(
+                       MW_CHAR_REFS_REGEX,
+                       array( 'Sanitizer', 'decodeCharReferencesCallback' ),
+                       $text, /* limit */ -1, $count );
+
+               if ( $count ) {
+                       return $wgContLang->normalize( $text );
+               } else {
+                       return $text;
+               }
+       }
+
        /**
         * @param $matches String
         * @return String
@@ -1227,7 +1283,7 @@ class Sanitizer {
        static function setupAttributeWhitelist() {
                global $wgAllowRdfaAttributes, $wgHtml5, $wgAllowMicrodataAttributes;
 
-               $common = array( 'id', 'class', 'lang', 'dir', 'title', 'style', 'xml:lang' );
+               $common = array( 'id', 'class', 'lang', 'dir', 'title', 'style' );
 
                if ( $wgAllowRdfaAttributes ) {
                        #RDFa attributes as specified in section 9 of http://www.w3.org/TR/2008/REC-rdfa-syntax-20081014
@@ -1353,8 +1409,9 @@ class Sanitizer {
 
                        # 13.2
                        # Not usually allowed, but may be used for extension-style hooks
-                       # such as <math> when it is rasterized
-                       'img'        => array_merge( $common, array( 'alt' ) ),
+                       # such as <math> when it is rasterized, or if $wgAllowImageTag is
+                       # true
+                       'img'        => array_merge( $common, array( 'alt', 'src', 'width', 'height' ) ),
 
                        # 15.2.1
                        'tt'         => $common,