*/
var $mLangLinkLanguages;
+ /**
+ * @var boolean Recursive call protection.
+ * This variable should be treated as if it were private.
+ */
+ public $mInParse = false;
+
/**
* Constructor
*
* Allow extensions to clean up when the parser is cloned
*/
function __clone() {
+ $this->mInParse = false;
wfRunHooks( 'ParserCloned', array( $this ) );
}
wfProfileIn( __METHOD__ );
wfProfileIn( $fname );
+ if ( $clearState ) {
+ $magicScopeVariable = $this->lock();
+ }
+
$this->startParse( $title, $options, self::OT_HTML, $clearState );
$this->mInputSize = strlen( $text );
*/
function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null ) {
wfProfileIn( __METHOD__ );
+ $magicScopeVariable = $this->lock();
$this->startParse( $title, $options, self::OT_PREPROCESS, true );
if ( $revid !== null ) {
$this->mRevisionId = $revid;
$text = $msg->params( $params )->plain();
# Parser (re)initialisation
+ $magicScopeVariable = $this->lock();
$this->startParse( $title, $options, self::OT_PLAIN, true );
$flags = PPFrame::NO_ARGS | PPFrame::NO_TEMPLATES;
* @return string The altered wiki markup
*/
public function preSaveTransform( $text, Title $title, User $user, ParserOptions $options, $clearState = true ) {
+ if ( $clearState ) {
+ $magicScopeVariable = $this->lock();
+ }
$this->startParse( $title, $options, self::OT_WIKI, $clearState );
$this->setUser( $user );
public function cleanSig( $text, $parsing = false ) {
if ( !$parsing ) {
global $wgTitle;
+ $magicScopeVariable = $this->lock();
$this->startParse( $wgTitle, new ParserOptions, self::OT_PREPROCESS, true );
}
*/
private function extractSections( $text, $section, $mode, $newText = '' ) {
global $wgTitle; # not generally used but removes an ugly failure mode
+
+ $magicScopeVariable = $this->lock();
$this->startParse( $wgTitle, new ParserOptions, self::OT_PLAIN, true );
$outText = '';
$frame = $this->getPreprocessor()->newFrame();
* @return string
*/
function testSrvus( $text, Title $title, ParserOptions $options, $outputType = self::OT_HTML ) {
+ $magicScopeVariable = $this->lock();
$this->startParse( $title, $options, $outputType, true );
$text = $this->replaceVariables( $text );
}
return $parsedWidthParam;
}
+
+ /**
+ * Lock the current instance of the parser.
+ *
+ * This is meant to stop someone from calling the parser
+ * recursively and messing up all the strip state.
+ *
+ * @throws MWException If parser is in a parse
+ * @return ScopedCallback The lock will be released once the return value goes out of scope.
+ */
+ protected function lock() {
+ if ( $this->mInParse ) {
+ throw new MWException( "Parser state cleared while parsing. Did you call Parser::parse recursively?" );
+ }
+ $this->mInParse = true;
+
+ $that = $this;
+ $recursiveCheck = new ScopedCallback( function() use ( $that ) {
+ $that->mInParse = false;
+ } );
+
+ return $recursiveCheck;
+ }
}
$this->assertEquals( $expected, $text );
}
+ /**
+ * @expectedException MWException
+ * @expectedExceptionMessage Parser state cleared while parsing. Did you call Parser::parse recursively?
+ * @covers Parser::lock
+ */
+ public function testRecursiveParse() {
+ global $wgParser;
+ $title = Title::newFromText( 'foo' );
+ $po = new ParserOptions;
+ $wgParser->setHook( 'recursivecallparser', array( $this, 'helperParserFunc' ) );
+ $wgParser->parse( '<recursivecallparser>baz</recursivecallparser>', $title, $po );
+ }
+
+ public function helperParserFunc( $input, $args, $parser) {
+ $title = Title::newFromText( 'foo' );
+ $po = new ParserOptions;
+ $parser->parse( $input, $title, $po );
+ return 'bar';
+ }
+
/**
* @covers Parser::callParserFunction
*/