Merge "Update MagicWord to use ContentLanguage"
[lhc/web/wiklou.git] / includes / parser / Parser.php
index a1b3064..bd7d4ac 100644 (file)
@@ -153,6 +153,9 @@ class Parser {
        public $mImageParams = [];
        public $mImageParamsMagicArray = [];
        public $mMarkerIndex = 0;
+       /**
+        * @var bool Whether firstCallInit still needs to be called
+        */
        public $mFirstCall = true;
 
        # Initialised by initialiseVariables()
@@ -260,10 +263,14 @@ class Parser {
         */
        protected $mLinkRenderer;
 
+       /** @var MagicWordFactory */
+       private $magicWordFactory;
+
        /**
         * @param array $conf
+        * @param MagicWordFactory|null $magicWordFactory
         */
-       public function __construct( $conf = [] ) {
+       public function __construct( $conf = [], MagicWordFactory $magicWordFactory = null ) {
                $this->mConf = $conf;
                $this->mUrlProtocols = wfUrlProtocols();
                $this->mExtLinkBracketedRegex = '/\[(((?i)' . $this->mUrlProtocols . ')' .
@@ -284,6 +291,11 @@ class Parser {
                        $this->mPreprocessorClass = Preprocessor_Hash::class;
                }
                wfDebug( __CLASS__ . ": using preprocessor: {$this->mPreprocessorClass}\n" );
+
+               $this->magicWordFactory = $magicWordFactory;
+               if ( !$magicWordFactory ) {
+                       $this->magicWordFactory = MediaWikiServices::getInstance()->getMagicWordFactory();
+               }
        }
 
        /**
@@ -345,9 +357,7 @@ class Parser {
         * @private
         */
        public function clearState() {
-               if ( $this->mFirstCall ) {
-                       $this->firstCallInit();
-               }
+               $this->firstCallInit();
                $this->mOutput = new ParserOutput;
                $this->mOptions->registerWatcher( [ $this->mOutput, 'recordOption' ] );
                $this->mAutonumber = 0;
@@ -401,7 +411,7 @@ class Parser {
         * @param ParserOptions $options
         * @param bool $linestart
         * @param bool $clearState
-        * @param int $revid Number to pass in {{REVISIONID}}
+        * @param int|null $revid Number to pass in {{REVISIONID}}
         * @return ParserOutput A ParserOutput
         */
        public function parse(
@@ -683,7 +693,7 @@ class Parser {
         * Also removes comments.
         * Do not call this function recursively.
         * @param string $text
-        * @param Title $title
+        * @param Title|null $title
         * @param ParserOptions $options
         * @param int|null $revid
         * @param bool|PPFrame $frame
@@ -789,7 +799,7 @@ class Parser {
        /**
         * Accessor/mutator for the Title object
         *
-        * @param Title $x Title object or null to just get the current one
+        * @param Title|null $x Title object or null to just get the current one
         * @return Title
         */
        public function Title( $x = null ) {
@@ -843,7 +853,7 @@ class Parser {
        /**
         * Accessor/mutator for the ParserOptions object
         *
-        * @param ParserOptions $x New value or null to just get the current one
+        * @param ParserOptions|null $x New value or null to just get the current one
         * @return ParserOptions Current ParserOptions object
         */
        public function Options( $x = null ) {
@@ -948,6 +958,16 @@ class Parser {
                return $this->mLinkRenderer;
        }
 
+       /**
+        * Get the MagicWordFactory that this Parser is using
+        *
+        * @since 1.32
+        * @return MagicWordFactory
+        */
+       public function getMagicWordFactory() {
+               return $this->magicWordFactory;
+       }
+
        /**
         * Replaces all occurrences of HTML-style comments and the given tags
         * in the text with a random marker and returns the next text. The output
@@ -1353,15 +1373,7 @@ class Parser {
                }
 
                # Clean up special characters, only run once, next-to-last before doBlockLevels
-               $fixtags = [
-                       # French spaces, last one Guillemet-left
-                       # only if there is something before the space
-                       '/(.) (?=\\?|:|;|!|%|\\302\\273)/' => '\\1 ',
-                       # french spaces, Guillemet-right
-                       '/(\\302\\253) /' => '\\1 ',
-                       '/ (!\s*important)/' => ' \\1', # Beware of CSS magic word !important, T13874.
-               ];
-               $text = preg_replace( array_keys( $fixtags ), array_values( $fixtags ), $text );
+               $text = Sanitizer::armorFrenchSpaces( $text );
 
                $text = $this->doBlockLevels( $text, $linestart );
 
@@ -1922,7 +1934,7 @@ class Parser {
         * @since 1.21
         * @param string|bool $url Optional URL, to extract the domain from for rel =>
         *   nofollow if appropriate
-        * @param Title $title Optional Title, for wgNoFollowNsExceptions lookups
+        * @param Title|null $title Optional Title, for wgNoFollowNsExceptions lookups
         * @return string|null Rel attribute for $url
         */
        public static function getExternalLinkRel( $url = false, $title = null ) {
@@ -2490,7 +2502,7 @@ class Parser {
         *
         * @private
         *
-        * @param string $index Magic variable identifier as mapped in MagicWord::$mVariableIDs
+        * @param string $index Magic variable identifier as mapped in MagicWordFactory::$mVariableIDs
         * @param bool|PPFrame $frame
         *
         * @throws MWException
@@ -2867,11 +2879,11 @@ class Parser {
         * @private
         */
        public function initialiseVariables() {
-               $variableIDs = MagicWord::getVariableIDs();
-               $substIDs = MagicWord::getSubstIDs();
+               $variableIDs = $this->magicWordFactory->getVariableIDs();
+               $substIDs = $this->magicWordFactory->getSubstIDs();
 
-               $this->mVariables = new MagicWordArray( $variableIDs );
-               $this->mSubstWords = new MagicWordArray( $substIDs );
+               $this->mVariables = $this->magicWordFactory->newArray( $variableIDs );
+               $this->mSubstWords = $this->magicWordFactory->newArray( $substIDs );
        }
 
        /**
@@ -3106,8 +3118,9 @@ class Parser {
                        $id = $this->mVariables->matchStartToEnd( $part1 );
                        if ( $id !== false ) {
                                $text = $this->getVariableValue( $id, $frame );
-                               if ( MagicWord::getCacheTTL( $id ) > -1 ) {
-                                       $this->mOutput->updateCacheExpiry( MagicWord::getCacheTTL( $id ) );
+                               if ( $this->magicWordFactory->getCacheTTL( $id ) > -1 ) {
+                                       $this->mOutput->updateCacheExpiry(
+                                               $this->magicWordFactory->getCacheTTL( $id ) );
                                }
                                $found = true;
                        }
@@ -3116,17 +3129,17 @@ class Parser {
                # MSG, MSGNW and RAW
                if ( !$found ) {
                        # Check for MSGNW:
-                       $mwMsgnw = MagicWord::get( 'msgnw' );
+                       $mwMsgnw = $this->magicWordFactory->get( 'msgnw' );
                        if ( $mwMsgnw->matchStartAndRemove( $part1 ) ) {
                                $nowiki = true;
                        } else {
                                # Remove obsolete MSG:
-                               $mwMsg = MagicWord::get( 'msg' );
+                               $mwMsg = $this->magicWordFactory->get( 'msg' );
                                $mwMsg->matchStartAndRemove( $part1 );
                        }
 
                        # Check for RAW:
-                       $mwRaw = MagicWord::get( 'raw' );
+                       $mwRaw = $this->magicWordFactory->get( 'raw' );
                        if ( $mwRaw->matchStartAndRemove( $part1 ) ) {
                                $forceRawInterwiki = true;
                        }
@@ -3993,7 +4006,7 @@ class Parser {
         */
        public function doDoubleUnderscore( $text ) {
                # The position of __TOC__ needs to be recorded
-               $mw = MagicWord::get( 'toc' );
+               $mw = $this->magicWordFactory->get( 'toc' );
                if ( $mw->match( $text ) ) {
                        $this->mShowToc = true;
                        $this->mForceTocPosition = true;
@@ -4006,7 +4019,7 @@ class Parser {
                }
 
                # Now match and remove the rest of them
-               $mwa = MagicWord::getDoubleUnderscoreArray();
+               $mwa = $this->magicWordFactory->getDoubleUnderscoreArray();
                $this->mDoubleUnderscores = $mwa->matchAndRemove( $text );
 
                if ( isset( $this->mDoubleUnderscores['nogallery'] ) ) {
@@ -4224,6 +4237,13 @@ class Parser {
                        # Avoid insertion of weird stuff like <math> by expanding the relevant sections
                        $safeHeadline = $this->mStripState->unstripBoth( $safeHeadline );
 
+                       # Remove any <style> or <script> tags (T198618)
+                       $safeHeadline = preg_replace(
+                               '#<(style|script)(?: [^>]*[^>/])?>.*?</\1>#is',
+                               '',
+                               $safeHeadline
+                       );
+
                        # Strip out HTML (first regex removes any tag not allowed)
                        # Allowed tags are:
                        # * <sup> and <sub> (T10393)
@@ -4650,7 +4670,7 @@ class Parser {
 
                # @todo FIXME: Regex doesn't respect extension tags or nowiki
                #  => Move this logic to braceSubstitution()
-               $substWord = MagicWord::get( 'subst' );
+               $substWord = $this->magicWordFactory->get( 'subst' );
                $substRegex = '/\{\{(?!(?:' . $substWord->getBaseRegex() . '))/x' . $substWord->getRegexCase();
                $substText = '{{' . $substWord->getSynonym( 0 );
 
@@ -4863,7 +4883,7 @@ class Parser {
                $this->mFunctionHooks[$id] = [ $callback, $flags ];
 
                # Add to function cache
-               $mw = MagicWord::get( $id );
+               $mw = $this->magicWordFactory->get( $id );
                if ( !$mw ) {
                        throw new MWException( __METHOD__ . '() expecting a magic word identifier.' );
                }
@@ -5047,7 +5067,7 @@ class Parser {
                                unset( $paramMap['img_width'] );
                        }
 
-                       $mwArray = new MagicWordArray( array_keys( $paramMap ) );
+                       $mwArray = $this->magicWordFactory->newArray( array_keys( $paramMap ) );
 
                        $label = '';
                        $alt = '';
@@ -5166,7 +5186,8 @@ class Parser {
                                }
                        }
                        $this->mImageParams[$handlerClass] = $paramMap;
-                       $this->mImageParamsMagicArray[$handlerClass] = new MagicWordArray( array_keys( $paramMap ) );
+                       $this->mImageParamsMagicArray[$handlerClass] =
+                               $this->magicWordFactory->newArray( array_keys( $paramMap ) );
                }
                return [ $this->mImageParams[$handlerClass], $this->mImageParamsMagicArray[$handlerClass] ];
        }