performance tweak related to title conversion
[lhc/web/wiklou.git] / includes / Parser.php
index f1fc4b5..4b79b83 100644 (file)
@@ -16,6 +16,7 @@
  * Hence, we limit the number of inclusions of any given page, thus bringing any
  * attack back to O(N).
  */
+
 define( 'MAX_INCLUDE_REPEAT', 100 );
 define( 'MAX_INCLUDE_SIZE', 1000000 ); // 1 Million
 
@@ -136,7 +137,7 @@ class Parser
         * @return ParserOutput a ParserOutput
         */
        function parse( $text, &$title, $options, $linestart = true, $clearState = true ) {
-               global $wgUseTidy;
+               global $wgUseTidy, $wgContLang;
                $fname = 'Parser::parse';
                wfProfileIn( $fname );
 
@@ -150,6 +151,7 @@ class Parser
 
                $stripState = NULL;
                $text = $this->strip( $text, $this->mStripState );
+
                $text = $this->internalParse( $text, $linestart );
                $text = $this->unstrip( $text, $this->mStripState );
                # Clean up special characters, only run once, next-to-last before doBlockLevels
@@ -182,6 +184,9 @@ class Parser
                }
                # only once and last
                $text = $this->doBlockLevels( $text, $linestart );
+
+               $text = $wgContLang->convert($text);
+
                $text = $this->unstripNoWiki( $text, $this->mStripState );
                $this->mOutput->setText( $text );
                wfProfileOut( $fname );
@@ -658,8 +663,6 @@ class Parser
                $text = $this->removeHTMLtags( $text );
                $text = $this->replaceVariables( $text, $args );
 
-               $text = $wgContLang->convert($text);
-
                $text = preg_replace( '/(^|\n)-----*/', '\\1<hr />', $text );
 
                $text = $this->doHeadings( $text );
@@ -669,8 +672,6 @@ class Parser
                }
                $text = $this->doAllQuotes( $text );
                $text = $this->replaceInternalLinks ( $text );
-               # Another call to replace links and images inside captions of images
-               $text = $this->replaceInternalLinks ( $text );
                $text = $this->replaceExternalLinks( $text );
                $text = $this->doMagicLinks( $text );
                $text = $this->doTableStuff( $text );
@@ -1063,9 +1064,13 @@ class Parser
         *
         * @access private
         */
+
        function replaceInternalLinks( $s ) {
                global $wgLang, $wgContLang, $wgLinkCache;
                static $fname = 'Parser::replaceInternalLinks' ;
+               # use a counter to prevent too much unknown links from
+               # being checked for different language variants.
+               static $convertCount;
                wfProfileIn( $fname );
 
                wfProfileIn( $fname.'-setup' );
@@ -1076,19 +1081,23 @@ class Parser
 
                $redirect = MagicWord::get ( MAG_REDIRECT ) ;
 
+               #split the entire text string on occurences of [[
                $a = explode( '[[', ' ' . $s );
+               #get the first element (all text up to first [[), and remove the space we added
                $s = array_shift( $a );
                $s = substr( $s, 1 );
 
                # Match a link having the form [[namespace:link|alternate]]trail
                static $e1 = FALSE;
                if ( !$e1 ) { $e1 = "/^([{$tc}]+)(?:\\|([^]]+))?]](.*)\$/sD"; }
+               # Match cases where there is no "]]", which might still be images
+               static $e1_img = FALSE;
+               if ( !$e1_img ) { $e1_img = "/^([{$tc}]+)\\|(.*)\$/sD"; }
                # Match the end of a line for a word that's not followed by whitespace,
                # e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched
                static $e2 = '/^(.*?)([a-zA-Z\x80-\xff]+)$/sD';
 
                $useLinkPrefixExtension = $wgContLang->linkPrefixExtension();
-               # Special and Media are pseudo-namespaces; no pages actually exist in them
 
                $nottalk = !Namespace::isTalk( $this->mTitle->getNamespace() );
 
@@ -1105,8 +1114,9 @@ class Parser
 
                wfProfileOut( $fname.'-setup' );
 
-               # start procedeeding each line
-               foreach ( $a as $line ) {
+               # Loop for each link
+               for ($k = 0; isset( $a[$k] ); $k++) {
+                       $line = $a[$k];
                        wfProfileIn( $fname.'-prefixhandling' );
                        if ( $useLinkPrefixExtension ) {
                                if ( preg_match( $e2, $s, $m ) ) {
@@ -1123,11 +1133,18 @@ class Parser
                        }
                        wfProfileOut( $fname.'-prefixhandling' );
 
+                       $might_be_img = false;
+                       
                        if ( preg_match( $e1, $line, $m ) ) { # page with normal text or alt
                                $text = $m[2];
                                # fix up urlencoded title texts
                                if(preg_match('/%/', $m[1] )) $m[1] = urldecode($m[1]);
                                $trail = $m[3];
+                       } elseif( preg_match($e1_img, $line, $m) ) { # Invalid, but might be an image with a link in its caption
+                               $might_be_img = true;
+                               $text = $m[2];
+                               if(preg_match('/%/', $m[1] )) $m[1] = urldecode($m[1]);
+                               $trail = "";
                        } else { # Invalid form; output directly
                                $s .= $prefix . '[[' . $line ;
                                continue;
@@ -1150,9 +1167,6 @@ class Parser
                                $link = substr($link, 1);
                        }
                        
-                       $wasblank = ( '' == $text );
-                       if( $wasblank ) $text = $link;
-
                        $nt = Title::newFromText( $link );
                        if( !$nt ) {
                                $s .= $prefix . '[[' . $line;
@@ -1163,12 +1177,14 @@ class Parser
                        //if the article does not exist
                        global $wgContLang;
                        $variants = $wgContLang->getVariants();
-                       if(sizeof($variants) > 1) {
+
+                       if(sizeof($variants) > 1 && $convertCount < 200) {
                                $varnt = false; 
                                if($nt->getArticleID() == 0) {
                                        foreach ( $variants as $v ) {
                                                if($v == $wgContLang->getPreferredVariant())
                                                        continue;
+                                               $convertCount ++;
                                                $varlink = $wgContLang->autoConvert($link, $v);
                                                $varnt = Title::newFromText($varlink);
                                                if($varnt && $varnt->getArticleID()>0) {
@@ -1185,6 +1201,46 @@ class Parser
                        $ns = $nt->getNamespace();
                        $iw = $nt->getInterWiki();
                        
+                       if ($might_be_img) { # if this is actually an invalid link
+                               if ($ns == NS_IMAGE && $noforce) { #but might be an image
+                                       $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) );
+                                               if( preg_match("/^(.*?]].*?)]](.*)$/sD", $next_line, $m) ) {
+                                               # the first ]] closes the inner link, the second the image
+                                                       $found = true;
+                                                       $text .= '[[' . $m[1];
+                                                       $trail = $m[2];
+                                                       break;
+                                               } elseif( preg_match("/^.*?]].*$/sD", $next_line, $m) ) {
+                                                       #if there's exactly one ]] that's fine, we'll keep looking
+                                                       $text .= '[[' . $m[0];
+                                               } else {
+                                                       #if $next_line is invalid too, we need look no further
+                                                       $text .= '[[' . $next_line;
+                                                       break;
+                                               }
+                                       }
+                                       if ( !$found ) {
+                                               # we couldn't find the end of this imageLink, so output it raw
+                                               #but don't ignore what might be perfectly normal links in the text we've examined
+                                               $text = $this->replaceInternalLinks($text);
+                                               $s .= $prefix . '[[' . $link . '|' . $text;
+                                               # note: no $trail, because without an end, there *is* no trail
+                                               continue;
+                                       }
+                               } else { #it's not an image, so output it raw
+                                       $s .= $prefix . '[[' . $link . '|' . $text;
+                                       # note: no $trail, because without an end, there *is* no trail
+                                       continue;
+                               }
+                       }
+
+                       $wasblank = ( '' == $text );
+                       if( $wasblank ) $text = $link;
+
+                       
                        # Link not escaped by : , create the various objects
                        if( $noforce ) {
 
@@ -1197,19 +1253,25 @@ class Parser
                                }
                                
                                if ( $ns == NS_IMAGE ) {
-                                       $s .= $prefix . $sk->makeImageLinkObj( $nt, $text ) . $trail;
+                                       # recursively parse links inside the image caption
+                                       # actually, this will parse them in any other parameters, too,
+                                       # but it might be hard to fix that, and it doesn't matter ATM
+                                       $text = $this->replaceExternalLinks($text);
+                                       $text = $this->replaceInternalLinks($text);
+                                       
+                                       # replace the image with a link-holder so that replaceExternalLinks() can't mess with it
+                                       $s .= $prefix . $this->insertStripItem( $sk->makeImageLinkObj( $nt, $text ), $this->mStripState ) . $trail;
                                        $wgLinkCache->addImageLinkObj( $nt );
                                        continue;
                                }
                                
                                if ( $ns == NS_CATEGORY ) {
                                        $t = $nt->getText() ;
-                                       $nnt = Title::newFromText ( Namespace::getCanonicalName(NS_CATEGORY).':'.$t ) ;
 
                                        $wgLinkCache->suspend(); # Don't save in links/brokenlinks
                                        $pPLC=$sk->postParseLinkColour();
                                        $sk->postParseLinkColour( false );
-                                       $t = $sk->makeLinkObj( $nnt, $t, '', '' , $prefix );
+                                       $t = $sk->makeLinkObj( $nt, $t, '', '' , $prefix );
                                        $sk->postParseLinkColour( $pPLC );
                                        $wgLinkCache->resume();
 
@@ -1228,7 +1290,9 @@ class Parser
                                        continue;
                                }
                        }
-                       
+
+            $text = $wgContLang->convert($text);                       
+
                        if( ( $nt->getPrefixedText() === $this->mTitle->getPrefixedText() ) &&
                            ( strpos( $link, '#' ) === FALSE ) ) {
                                # Self-links are handled specially; generally de-link and change to bold.
@@ -1236,6 +1300,7 @@ class Parser
                                continue;
                        }
 
+                       # Special and Media are pseudo-namespaces; no pages actually exist in them
                        if( $ns == NS_MEDIA ) {
                                $s .= $prefix . $sk->makeMediaLinkObj( $nt, $text ) . $trail;
                                $wgLinkCache->addImageLinkObj( $nt );