Index: includes/parser/Parser.php =================================================================== --- includes/parser/Parser.php (revision 46746) +++ includes/parser/Parser.php (working copy) @@ -113,7 +113,8 @@ $ot, // Shortcut alias, see setOutputType() $mRevisionId, // ID to display in {{REVISIONID}} tags $mRevisionTimestamp, // The timestamp of the specified revision ID - $mRevIdForTs; // The revision ID which was used to fetch the timestamp + $mRevIdForTs, // The revision ID which was used to fetch the timestamp + $mParsing; // Boolean to avoid/detect recursive parser calls /**#@-*/ @@ -146,6 +147,7 @@ } $this->mMarkerIndex = 0; $this->mFirstCall = true; + $this->mParsing = false; } /** @@ -194,7 +196,7 @@ $this->mLastSection = ''; $this->mDTopen = false; $this->mIncludeCount = array(); - $this->mStripState = new StripState; + + #Explicitly assign by reference to avoid cloning errors + $this->mStripState =& new StripState; $this->mArgStack = false; $this->mInPre = false; $this->mLinkHolders = new LinkHolderArray( $this ); @@ -241,6 +243,10 @@ wfProfileOut( __METHOD__ ); } + public function isParsing() { + return $this->mParsing; + } + function setOutputType( $ot ) { $this->mOutputType = $ot; // Shortcut alias @@ -308,6 +314,11 @@ wfProfileIn( __METHOD__ ); wfProfileIn( $fname ); + $wasParsing = $this->mParsing; + if( $wasParsing ) { + wfDebug( "$fname: Recursive call of ".__METHOD__."\n" ); + } + $this->mParsing = true; if ( $clearState ) { $this->clearState(); } @@ -427,6 +438,7 @@ $this->mOutput->setText( $text ); $this->mRevisionId = $oldRevisionId; $this->mRevisionTimestamp = $oldRevisionTimestamp; + $this->mParsing = $wasParsing; wfProfileOut( $fname ); wfProfileOut( __METHOD__ ); @@ -452,6 +464,11 @@ */ function preprocess( $text, $title, $options, $revid = null ) { wfProfileIn( __METHOD__ ); + $wasParsing = $this->mParsing; + if( $wasParsing ) { + wfDebug( wfGetCaller().": Recursive call of ".__METHOD__."\n" ); + } + $this->mParsing = true; $this->clearState(); $this->setOutputType( self::OT_PREPROCESS ); $this->mOptions = $options; @@ -463,6 +480,7 @@ wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) ); $text = $this->replaceVariables( $text ); $text = $this->mStripState->unstripBoth( $text ); + $this->mParsing = $wasParsing; wfProfileOut( __METHOD__ ); return $text; } Index: includes/MessageCache.php =================================================================== --- includes/MessageCache.php (revision 46746) +++ includes/MessageCache.php (working copy) @@ -647,12 +647,7 @@ return $message; } - function transform( $message, $interface = false, $language = null ) { - // Avoid creating parser if nothing to transfrom - if( strpos( $message, '{{' ) === false ) { - return $message; - } - + private function initParser() { global $wgParser, $wgParserConf; if ( !$this->mParser && isset( $wgParser ) ) { # Do some initialisation so that we don't have to do it twice @@ -664,14 +659,28 @@ $this->mParser = new $class( $wgParserConf ); } else { $this->mParser = clone $wgParser; + $this->mParser->mParsing = false; } - #wfDebug( __METHOD__ . ": following contents triggered transform: $message\n" ); } + } + + public function getParser() { + $this->initParser(); + return $this->mParser; + } + + function transform( $message, $interface = false, $language = null ) { + // Avoid creating parser if nothing to transfrom + if( strpos( $message, '{{' ) === false ) { + return $message; + } + $this->initParser(); if ( $this->mParser ) { $popts = $this->getParserOptions(); $popts->setInterfaceMessage( $interface ); $popts->setTargetLanguage( $language ); $message = $this->mParser->transformMsg( $message, $popts ); } return $message; } Index: includes/OutputPage.php =================================================================== --- includes/OutputPage.php (revision 46746) +++ includes/OutputPage.php (working copy) @@ -637,13 +637,17 @@ * @param bool $interface ?? */ public function parse( $text, $linestart = true, $interface = false ) { - global $wgParser, $wgTitle; + global $wgParser, $wgTitle, $wgMessageCache; if( is_null( $wgTitle ) ) { throw new MWException( 'Empty $wgTitle in ' . __METHOD__ ); } + # If $wgParser is busy, use MessageCache's parser to avoid recursive calls + $parser = $wgParser->isParsing() && is_object( $wgMessageCache ) + ? $wgMessageCache->getParser() + : $wgParser; $popts = $this->parserOptions(); if ( $interface) { $popts->setInterfaceMessage(true); } - $parserOutput = $wgParser->parse( $text, $wgTitle, $popts, + $parserOutput = $parser->parse( $text, $wgTitle, $popts, $linestart, true, $this->mRevisionId ); if ( $interface) { $popts->setInterfaceMessage(false); } return $parserOutput->getText();