ported fix for bug 2257 here
[lhc/web/wiklou.git] / includes / Parser.php
index 4f6fcba..7736b04 100644 (file)
@@ -99,7 +99,7 @@ class Parser
        var $mTagHooks;
 
        # Cleared with clearState():
-       var $mOutput, $mAutonumber, $mDTopen, $mStripState = array();
+       var $mOutput, $mAutonumber, $mDTopen, $mStripState = array(), $mCurrentParams = array();
        var $mVariables, $mIncludeCount, $mArgStack, $mLastSection, $mInPre;
        var $mInterwikiLinkHolders, $mLinkHolders;
 
@@ -111,7 +111,6 @@ class Parser
                                // in this path. Used for loop detection.
 
        var $mIWTransData = array();
-       var $mAssocArgs = array();
 
        /**#@-*/
 
@@ -121,7 +120,6 @@ class Parser
         * @access public
         */
        function Parser() {
-               global $wgContLang;
                $this->mTemplates = array();
                $this->mTemplatePath = array();
                $this->mTagHooks = array();
@@ -143,6 +141,7 @@ class Parser
                $this->mStripState = array();
                $this->mArgStack = array();
                $this->mInPre = false;
+               $this->mCurrentParams = array();
                $this->mInterwikiLinkHolders = array(
                        'texts' => array(),
                        'titles' => array()
@@ -222,7 +221,7 @@ class Parser
                wfRunHooks( 'ParserBeforeTidy', array( &$this, &$text ) );
 
                $text = Sanitizer::normalizeCharReferences( $text );
-               global $wgUseTidy;
+               
                if ($wgUseTidy) {
                        $text = Parser::tidy($text);
                }
@@ -378,16 +377,14 @@ class Parser
                }
 
                # math
-               $text = Parser::extractTags('math', $text, $math_content, $uniq_prefix);
-               foreach( $math_content as $marker => $content ){
-                       if( $render ) {
-                               if( $this->mOptions->getUseTeX() ) {
+               if( $this->mOptions->getUseTeX() ) {
+                       $text = Parser::extractTags('math', $text, $math_content, $uniq_prefix);
+                       foreach( $math_content as $marker => $content ){
+                               if( $render ) {
                                        $math_content[$marker] = renderMath( $content );
                                } else {
-                                       $math_content[$marker] = '<math>'.$content.'<math>';
+                                       $math_content[$marker] = '<math>'.$content.'</math>';
                                }
-                       } else {
-                               $math_content[$marker] = '<math>'.$content.'</math>';
                        }
                }
 
@@ -426,6 +423,7 @@ class Parser
                        $text = Parser::extractTagsAndParams( $tag, $text, $ext_content[$tag],
                                $ext_tags[$tag], $ext_params[$tag], $uniq_prefix );
                        foreach( $ext_content[$tag] as $marker => $content ) {
+                               $content = $this->replaceVariables( $content, $this->mCurrentParams );
                                $full_tag = $ext_tags[$tag][$marker];
                                $params = $ext_params[$tag][$marker];
                                if ( $render ) {
@@ -659,8 +657,11 @@ class Parser
                        $fc = substr ( $x , 0 , 1 ) ;
                        if ( preg_match( '/^(:*)\{\|(.*)$/', $x, $matches ) ) {
                                $indent_level = strlen( $matches[1] );
+                               
+                               $attributes = $this->unstripForHTML( $matches[2] );
+
                                $t[$k] = str_repeat( '<dl><dd>', $indent_level ) .
-                                       '<table' . Sanitizer::fixTagAttributes ( $matches[2], 'table' ) . '>' ;
+                                       '<table' . Sanitizer::fixTagAttributes ( $attributes, 'table' ) . '>' ;
                                array_push ( $td , false ) ;
                                array_push ( $ltd , '' ) ;
                                array_push ( $tr , false ) ;
@@ -687,7 +688,8 @@ class Parser
                                array_push ( $tr , false ) ;
                                array_push ( $td , false ) ;
                                array_push ( $ltd , '' ) ;
-                               array_push ( $ltr , Sanitizer::fixTagAttributes ( $x, 'tr' ) ) ;
+                               $attributes = $this->unstripForHTML( $x );
+                               array_push ( $ltr , Sanitizer::fixTagAttributes ( $attributes, 'tr' ) ) ;
                        }
                        else if ( '|' == $fc || '!' == $fc || '|+' == substr ( $x , 0 , 2 ) ) { # Caption
                                # $x is a table row
@@ -729,7 +731,10 @@ class Parser
                                        }
                                        if ( count ( $y ) == 1 )
                                                $y = "{$z}<{$l}>{$y[0]}" ;
-                                       else $y = $y = "{$z}<{$l}".Sanitizer::fixTagAttributes($y[0], $l).">{$y[1]}" ;
+                                       else {
+                                               $attributes = $this->unstripForHTML( $y[0] );
+                                               $y = "{$z}<{$l}".Sanitizer::fixTagAttributes($attributes, $l).">{$y[1]}" ;
+                                       }
                                        $t[$k] .= $y ;
                                        array_push ( $td , true ) ;
                                }
@@ -766,7 +771,7 @@ class Parser
                $text = strtr( $text, array( '<noinclude>' => '', '</noinclude>' => '') );
                $text = preg_replace( '/<includeonly>.*?<\/includeonly>/s', '', $text );
 
-               $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'replaceVariables' ) );
+               $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'attributeStripCallback' ) );
                $text = $this->replaceVariables( $text, $args );
 
                $text = preg_replace( '/(^|\n)-----*/', '\\1<hr />', $text );
@@ -782,7 +787,7 @@ class Parser
 
                # replaceInternalLinks may sometimes leave behind
                # absolute URLs, which have to be masked to hide them from replaceExternalLinks
-               $text = str_replace("http-noparse://","http://",$text);
+               $text = str_replace(UNIQ_PREFIX."NOPARSE", "", $text);
 
                $text = $this->doMagicLinks( $text );
                $text = $this->doTableStuff( $text );
@@ -821,7 +826,7 @@ class Parser
        function doExponent( $text ) {
                $fname = 'Parser::doExponent';
                wfProfileIn( $fname );
-               $text = preg_replace('/\^\^(.*)\^\^/','<small><sup>\\1</sup></small>', $text);
+               $text = preg_replace('/\^\^(.*?)\^\^/','<small><sup>\\1</sup></small>', $text);
                wfProfileOut( $fname );
                return $text;
        }
@@ -1341,7 +1346,8 @@ class Parser
                                        $found = false;
                                        while (isset ($a[$k+1]) ) {
                                                #look at the next 'line' to see if we can close it there
-                                               $next_line =  array_shift(array_splice( $a, $k + 1, 1) );
+                                               $spliced = array_splice( $a, $k + 1, 1 );
+                                               $next_line = array_shift( $spliced );
                                                if( preg_match("/^(.*?]].*?)]](.*)$/sD", $next_line, $m) ) {
                                                # the first ]] closes the inner link, the second the image
                                                        $found = true;
@@ -1397,7 +1403,7 @@ class Parser
                                                $text = $this->replaceInternalLinks($text);
 
                                                # cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them
-                                               $s .= $prefix . str_replace('http://', 'http-noparse://', $this->makeImage( $nt, $text ) ) . $trail;
+                                               $s .= $prefix . preg_replace("/\b($wgUrlProtocols)/", UNIQ_PREFIX."NOPARSE$1", $this->makeImage( $nt, $text) ) . $trail;
                                                $wgLinkCache->addImageLinkObj( $nt );
 
                                                wfProfileOut( "$fname-image" );
@@ -1456,22 +1462,7 @@ class Parser
                                $s .= $prefix . $sk->makeKnownLinkObj( $nt, $text, '', $trail );
                                continue;
                        }
-                       if( !$nt->isExternal() && $nt->isAlwaysKnown() ) {
-                               /**
-                                * Skip lookups for special pages and self-links.
-                                * External interwiki links are not included here because
-                                * the HTTP urls would break output in the next parse step;
-                                * they will have placeholders kept.
-                                */
-                               $s .= $sk->makeKnownLinkObj( $nt, $text, '', $trail, $prefix );
-                       } else {
-                               /**
-                                * Add a link placeholder
-                                * Later, this will be replaced by a real link, after the existence or
-                                * non-existence of all the links is known
-                                */
-                               $s .= $this->makeLinkHolder( $nt, $text, '', $trail, $prefix );
-                       }
+                       $s .= $this->makeLinkHolder( $nt, $text, '', $trail, $prefix );
                }
                wfProfileOut( $fname );
                return $s;
@@ -2150,20 +2141,27 @@ class Parser
                        }
                }
 
-               # LOCALURL and LOCALURLE
+               # LOCALURL and FULLURL
                if ( !$found ) {
-                       $mwLocal = MagicWord::get( MAG_LOCALURL );
-                       $mwLocalE = MagicWord::get( MAG_LOCALURLE );
+                       $mwLocal =& MagicWord::get( MAG_LOCALURL );
+                       $mwLocalE =& MagicWord::get( MAG_LOCALURLE );
+                       $mwFull =& MagicWord::get( MAG_FULLURL );
+                       $mwFullE =& MagicWord::get( MAG_FULLURLE );
+                       
 
                        if ( $mwLocal->matchStartAndRemove( $part1 ) ) {
                                $func = 'getLocalURL';
                        } elseif ( $mwLocalE->matchStartAndRemove( $part1 ) ) {
                                $func = 'escapeLocalURL';
+                       } elseif ( $mwFull->matchStartAndRemove( $part1 ) ) {
+                               $func = 'getFullURL';
+                       } elseif ( $mwFullE->matchStartAndRemove( $part1 ) ) {
+                               $func = 'escapeFullURL';
                        } else {
-                               $func = '';
+                               $func = false;
                        }
 
-                       if ( $func !== '' ) {
+                       if ( $func !== false ) {
                                $title = Title::newFromText( $part1 );
                                if ( !is_null( $title ) ) {
                                        if ( $argc > 0 ) {
@@ -2185,6 +2183,16 @@ class Parser
                        }
                }
 
+               # PLURAL
+               if ( !$found && $argc >= 2 ) {
+                       $mwPluralForm =& MagicWord::get( MAG_PLURAL );
+                       if ( $mwPluralForm->matchStartAndRemove( $part1 ) ) {
+                               if ($argc==2) {$args[2]=$args[1];}
+                               $text = $linestart . $wgContLang->convertPlural( $part1, $args[0], $args[1], $args[2]);
+                               $found = true;
+                       }
+               }
+
                # Template table test
 
                # Did we encounter this template already? If yes, it is in the cache
@@ -2269,12 +2277,12 @@ class Parser
                        $text = wfEscapeWikiText( $text );
                } elseif ( ($this->mOutputType == OT_HTML || $this->mOutputType == OT_WIKI) && $found && !$noparse) {
                        # Clean up argument array
-                       $this->mAssocArgs = array();
+                       $assocArgs = array();
                        $index = 1;
                        foreach( $args as $arg ) {
                                $eqpos = strpos( $arg, '=' );
                                if ( $eqpos === false ) {
-                                       $this->mAssocArgs[$index++] = $arg;
+                                       $assocArgs[$index++] = $arg;
                                } else {
                                        $name = trim( substr( $arg, 0, $eqpos ) );
                                        $value = trim( substr( $arg, $eqpos+1 ) );
@@ -2282,7 +2290,7 @@ class Parser
                                                $value = '';
                                        }
                                        if ( $name !== false ) {
-                                               $this->mAssocArgs[$name] = $value;
+                                               $assocArgs[$name] = $value;
                                        }
                                }
                        }
@@ -2295,10 +2303,11 @@ class Parser
                                $text = preg_replace( '/<noinclude>.*?<\/noinclude>/s', '', $text );
                                $text = strtr( $text, array( '<includeonly>' => '' , '</includeonly>' => '' ) );
                                # Strip <nowiki>, <pre>, etc.
+                               $this->mCurrentParams = $assocArgs;
                                $text = $this->strip( $text, $this->mStripState );
-                               $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'replaceVariables' ), $this->mAssocArgs );
+                               $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'replaceVariables' ), $assocArgs );
                        }
-                       $text = $this->replaceVariables( $text, $this->mAssocArgs );
+                       $text = $this->replaceVariables( $text, $assocArgs );
 
                        # Resume the link cache and register the inclusion as a link
                        if ( $this->mOutputType == OT_HTML && !is_null( $title ) ) {
@@ -3023,7 +3032,7 @@ class Parser
                                $pdbk = $pdbks[$key] = $title->getPrefixedDBkey();
 
                                # Check if it's in the link cache already
-                               if ( $wgLinkCache->getGoodLinkID( $pdbk ) ) {
+                               if ( $title->isAlwaysKnown() || $wgLinkCache->getGoodLinkID( $pdbk ) ) {
                                        $colours[$pdbk] = 1;
                                } elseif ( $wgLinkCache->isBadLink( $pdbk ) ) {
                                        $colours[$pdbk] = 0;
@@ -3250,6 +3259,7 @@ class Parser
                $part = explode( '|', $options);
 
                $mwThumb  =& MagicWord::get( MAG_IMG_THUMBNAIL );
+               $mwManualThumb =& MagicWord::get( MAG_IMG_MANUALTHUMB );
                $mwLeft   =& MagicWord::get( MAG_IMG_LEFT );
                $mwRight  =& MagicWord::get( MAG_IMG_RIGHT );
                $mwNone   =& MagicWord::get( MAG_IMG_NONE );
@@ -3262,14 +3272,12 @@ class Parser
                $manual_thumb = '' ;
 
                foreach( $part as $key => $val ) {
-                       $val_parts = explode ( '=' , $val , 2 ) ;
-                       $left_part = array_shift ( $val_parts ) ;
                        if ( $wgUseImageResize && ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
                                $thumb=true;
-                       } elseif ( $wgUseImageResize && count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) {
+                       } elseif ( ! is_null( $match = $mwManualThumb->matchVariableStartToEnd($val) ) ) {
                                # use manually specified thumbnail
                                $thumb=true;
-                               $manual_thumb = array_shift ( $val_parts ) ;
+                               $manual_thumb = $match;
                        } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
                                # remember to set an alignment, don't render immediately
                                $align = 'right';
@@ -3313,6 +3321,26 @@ class Parser
        function disableCache() {
                $this->mOutput->mCacheTime = -1;
        }
+       
+       /**
+        * Callback from the Sanitizer for expanding items found in HTML attribute
+        * values, so they can be safely tested and escaped.
+        * @param string $text
+        * @param array $args
+        * @return string
+        * @access private
+        */
+       function attributeStripCallback( &$text, $args ) {
+               $text = $this->replaceVariables( $text, $args );
+               $text = $this->unstripForHTML( $text );
+               return $text;
+       }
+       
+       function unstripForHTML( $text ) {
+               $text = $this->unstrip( $text, $this->mStripState );
+               $text = $this->unstripNoWiki( $text, $this->mStripState );
+               return $text;
+       }
 }
 
 /**