var $mIncludeCount, $mArgStack, $mLastSection, $mInPre;
var $mInterwikiLinkHolders, $mLinkHolders;
var $mIncludeSizes, $mPPNodeCount, $mDefaultSort;
- var $mTplExpandCache,// empty-frame expansion cache
- $mTemplatePath; // stores an unsorted hash of all the templates already loaded
- // in this path. Used for loop detection.
+ var $mTplExpandCache; // empty-frame expansion cache
var $mTplRedirCache, $mTplDomCache, $mHeadings;
# Temporary
$this->mUniqPrefix = "\x7fUNIQ" . Parser::getRandomString();
# Clear these on every parse, bug 4549
- $this->mTemplatePath = array();
$this->mTplExpandCache = $this->mTplRedirCache = $this->mTplDomCache = array();
$this->mShowToc = true;
}
wfProfileOut( __METHOD__.'-modifiers' );
- # Save path level before recursing into functions & templates.
- $lastPathLevel = $this->mTemplatePath;
-
# Parser functions
if ( !$found ) {
wfProfileIn( __METHOD__ . '-pfunc' );
$wgContLang->findVariantLink($part1, $title);
}
# Do infinite loop check
- if ( isset( $this->mTemplatePath[$titleText] ) ) {
+ if ( isset( $frame->loopCheckHash[$titleText] ) ) {
$found = true;
- $text = "[[$part1]]" . $this->insertStripItem( '<!-- WARNING: template loop detected -->' );
+ $text = "<span class=\"error\">Template loop detected: [[$titleText]]</span>";
wfDebug( __METHOD__.": template loop broken at '$titleText'\n" );
}
+ # Do recursion depth check
+ $limit = $this->mOptions->getMaxTemplateDepth();
+ if ( $frame->depth >= $limit ) {
+ $found = true;
+ $text = "<span class=\"error\">Template recursion depth limit exceeded ($limit)</span>";
+ }
}
}
# Recover the source wikitext and return it
if ( !$found ) {
$text = '{{' . $frame->implode( '|', $titleWithSpaces, $args ) . '}}';
- # Prune lower levels off the recursion check path
- $this->mTemplatePath = $lastPathLevel;
wfProfileOut( $fname );
return $text;
}
if ( $isDOM ) {
# Clean up argument array
$newFrame = $frame->newChild( $args, $title );
- # Add a new element to the templace recursion path
- $this->mTemplatePath[$titleText] = 1;
+ # Add a new element to the templace loop detection hashtable
+ $newFrame->loopCheckHash[$titleText] = true;
if ( $titleText !== false && count( $newFrame->args ) == 0 ) {
# Expansion is eligible for the empty-frame cache
$this->mTplExpandCache[$titleText] = $text;
}
} else {
+ # Uncached expansion
$text = $newFrame->expand( $text );
}
}
$text = "\n" . $text;
}
- # Prune lower levels off the recursion check path
- $this->mTemplatePath = $lastPathLevel;
-
if ( !$this->incrementIncludeSize( 'post-expand', strlen( $text ) ) ) {
# Error, oversize inclusion
$text = "[[$originalTitle]]" .
* found The text returned is valid, stop processing the template. This
* is on by default.
* nowiki Wiki markup in the return value should be escaped
- * noparse Unsafe HTML tags should not be stripped, etc.
- * noargs Don't replace triple-brace arguments in the return value
* isHTML The returned text is HTML, armour it against wikitext transformation
*
* @public
var $parser, $title;
var $titleCache;
+ /**
+ * Hashtable listing templates which are disallowed for expansion in this frame,
+ * having been encountered previously in parent frames.
+ */
+ var $loopCheckHash;
+
+ /**
+ * Recursion depth of this frame, top = 0
+ */
+ var $depth;
+
const NO_ARGS = 1;
const NO_TEMPLATES = 2;
const STRIP_COMMENTS = 4;
$this->parser = $parser;
$this->title = $parser->mTitle;
$this->titleCache = array( $this->title ? $this->title->getPrefixedDBkey() : false );
+ $this->loopCheckHash = array();
+ $this->depth = 0;
}
/**
* Expansion frame with template arguments
*/
class PPTemplateFrame extends PPFrame {
- var $parser, $args, $parent;
- var $titleCache;
+ var $args, $parent;
function __construct( $parser, $parent = false, $args = array(), $title = false ) {
$this->parser = $parser;
$this->title = $title;
$this->titleCache = $parent->titleCache;
$this->titleCache[] = $title ? $title->getPrefixedDBkey() : false;
+ $this->loopCheckHash = /*clone*/ $parent->loopCheckHash;
+ $this->depth = $parent->depth + 1;
}
function __toString() {
var $mInterfaceMessage; # Which lang to call for PLURAL and GRAMMAR
var $mMaxIncludeSize; # Maximum size of template expansions, in bytes
var $mMaxPPNodeCount; # Maximum number of nodes touched by PPFrame::expand()
+ var $mMaxTemplateDepth; # Maximum recursion depth for templates within templates
var $mRemoveComments; # Remove HTML comments. ONLY APPLIES TO PREPROCESS OPERATIONS
var $mTemplateCallback; # Callback for template fetching
var $mEnableLimitReport; # Enable limit report in an HTML comment on output
function getInterfaceMessage() { return $this->mInterfaceMessage; }
function getMaxIncludeSize() { return $this->mMaxIncludeSize; }
function getMaxPPNodeCount() { return $this->mMaxPPNodeCount; }
+ function getMaxTemplateDepth() { return $this->mMaxTemplateDepth; }
function getRemoveComments() { return $this->mRemoveComments; }
function getTemplateCallback() { return $this->mTemplateCallback; }
function getEnableLimitReport() { return $this->mEnableLimitReport; }
function setInterfaceMessage( $x ) { return wfSetVar( $this->mInterfaceMessage, $x); }
function setMaxIncludeSize( $x ) { return wfSetVar( $this->mMaxIncludeSize, $x ); }
function setMaxPPNodeCount( $x ) { return wfSetVar( $this->mMaxPPNodeCount, $x ); }
+ function setMaxTemplateDepth( $x ) { return wfSetVar( $this->mMaxTemplateDepth, $x ); }
function setRemoveComments( $x ) { return wfSetVar( $this->mRemoveComments, $x ); }
function setTemplateCallback( $x ) { return wfSetVar( $this->mTemplateCallback, $x ); }
function enableLimitReport( $x = true ) { return wfSetVar( $this->mEnableLimitReport, $x ); }
function initialiseFromUser( $userInput ) {
global $wgUseTeX, $wgUseDynamicDates, $wgInterwikiMagic, $wgAllowExternalImages;
global $wgAllowExternalImagesFrom, $wgAllowSpecialInclusion, $wgMaxArticleSize;
- global $wgMaxPPNodeCount;
+ global $wgMaxPPNodeCount, $wgMaxTemplateDepth;
$fname = 'ParserOptions::initialiseFromUser';
wfProfileIn( $fname );
if ( !$userInput ) {
$this->mInterfaceMessage = false;
$this->mMaxIncludeSize = $wgMaxArticleSize * 1024;
$this->mMaxPPNodeCount = $wgMaxPPNodeCount;
+ $this->mMaxTemplateDepth = $wgMaxTemplateDepth;
$this->mRemoveComments = true;
$this->mTemplateCallback = array( 'Parser', 'statelessFetchTemplate' );
$this->mEnableLimitReport = false;