Merge "Change name of Santali to localized version"
[lhc/web/wiklou.git] / includes / parser / Parser.php
index fd5ccb8..4073864 100644 (file)
@@ -51,9 +51,6 @@ use Wikimedia\ScopedCallback;
  * - Parser::getPreloadText()
  *     removes <noinclude> sections and <includeonly> tags
  *
- * Globals used:
- *    object: $wgContLang
- *
  * @warning $wgUser or $wgTitle or $wgRequest or $wgLang. Keep them away!
  *
  * @par Settings:
@@ -153,6 +150,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 +260,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 +288,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 +354,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;
@@ -948,6 +955,26 @@ class Parser {
                return $this->mLinkRenderer;
        }
 
+       /**
+        * Get the MagicWordFactory that this Parser is using
+        *
+        * @since 1.32
+        * @return MagicWordFactory
+        */
+       public function getMagicWordFactory() {
+               return $this->magicWordFactory;
+       }
+
+       /**
+        * Get the content language that this Parser is using
+        *
+        * @since 1.32
+        * @return Language
+        */
+       public function getContentLanguage() {
+               return $this->magicWordFactory->getContentLanguage();
+       }
+
        /**
         * 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
@@ -2127,8 +2154,7 @@ class Parser {
                if ( $useLinkPrefixExtension ) {
                        # 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
-                       global $wgContLang;
-                       $charset = $wgContLang->linkPrefixCharset();
+                       $charset = $this->getContentLanguage()->linkPrefixCharset();
                        $e2 = "/^((?>.*[^$charset]|))(.+)$/sDu";
                }
 
@@ -2482,14 +2508,14 @@ 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
         * @return string
         */
        public function getVariableValue( $index, $frame = false ) {
-               global $wgContLang, $wgSitename, $wgServer, $wgServerName;
+               global $wgSitename, $wgServer, $wgServerName;
                global $wgArticlePath, $wgScriptPath, $wgStylePath;
 
                if ( is_null( $this->mTitle ) ) {
@@ -2683,10 +2709,12 @@ class Parser {
                                $value = $this->getRevisionSize();
                                break;
                        case 'namespace':
-                               $value = str_replace( '_', ' ', $wgContLang->getNsText( $this->mTitle->getNamespace() ) );
+                               $value = str_replace( '_', ' ',
+                                       $this->getContentLanguage()->getNsText( $this->mTitle->getNamespace() ) );
                                break;
                        case 'namespacee':
-                               $value = wfUrlencode( $wgContLang->getNsText( $this->mTitle->getNamespace() ) );
+                               $value = wfUrlencode( $this->getContentLanguage()->
+                                       getNsText( $this->mTitle->getNamespace() ) );
                                break;
                        case 'namespacenumber':
                                $value = $this->mTitle->getNamespace();
@@ -2829,15 +2857,13 @@ class Parser {
         * @return string
         */
        private function getRevisionTimestampSubstring( $start, $len, $mtts, $variable ) {
-               global $wgContLang;
-
                # Get the timezone-adjusted timestamp to be used for this revision
                $resNow = substr( $this->getRevisionTimestamp(), $start, $len );
                # Possibly set vary-revision if there is not yet an associated revision
                if ( !$this->getRevisionObject() ) {
                        # Get the timezone-adjusted timestamp $mtts seconds in the future
                        $resThen = substr(
-                               $wgContLang->userAdjust( wfTimestamp( TS_MW, time() + $mtts ), '' ),
+                               $this->getContentLanguage()->userAdjust( wfTimestamp( TS_MW, time() + $mtts ), '' ),
                                $start,
                                $len
                        );
@@ -2859,11 +2885,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 );
        }
 
        /**
@@ -3098,8 +3124,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;
                        }
@@ -3108,17 +3135,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;
                        }
@@ -3383,14 +3410,12 @@ class Parser {
         * @return array
         */
        public function callParserFunction( $frame, $function, array $args = [] ) {
-               global $wgContLang;
-
                # Case sensitive functions
                if ( isset( $this->mFunctionSynonyms[1][$function] ) ) {
                        $function = $this->mFunctionSynonyms[1][$function];
                } else {
                        # Case insensitive functions
-                       $function = $wgContLang->lc( $function );
+                       $function = $this->getContentLanguage()->lc( $function );
                        if ( isset( $this->mFunctionSynonyms[0][$function] ) ) {
                                $function = $this->mFunctionSynonyms[0][$function];
                        } else {
@@ -3655,8 +3680,8 @@ class Parser {
                                        break;
                                }
                        } elseif ( $title->getNamespace() == NS_MEDIAWIKI ) {
-                               global $wgContLang;
-                               $message = wfMessage( $wgContLang->lcfirst( $title->getText() ) )->inContentLanguage();
+                               $message = wfMessage( MediaWikiServices::getInstance()->getContentLanguage()->
+                                       lcfirst( $title->getText() ) )->inContentLanguage();
                                if ( !$message->exists() ) {
                                        $text = false;
                                        break;
@@ -3985,7 +4010,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;
@@ -3998,7 +4023,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'] ) ) {
@@ -4216,6 +4241,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)
@@ -4486,19 +4518,15 @@ class Parser {
         * @return string
         */
        private function pstPass2( $text, $user ) {
-               global $wgContLang;
-
-               # Note: This is the timestamp saved as hardcoded wikitext to
-               # the database, we use $wgContLang here in order to give
-               # everyone the same signature and use the default one rather
-               # than the one selected in each user's preferences.
-               # (see also T14815)
+               # Note: This is the timestamp saved as hardcoded wikitext to the database, we use
+               # $this->getContentLanguage() here in order to give everyone the same signature and use the
+               # default one rather than the one selected in each user's preferences.  (see also T14815)
                $ts = $this->mOptions->getTimestamp();
                $timestamp = MWTimestamp::getLocalInstance( $ts );
                $ts = $timestamp->format( 'YmdHis' );
                $tzMsg = $timestamp->getTimezoneMessage()->inContentLanguage()->text();
 
-               $d = $wgContLang->timeanddate( $ts, false, false ) . " ($tzMsg)";
+               $d = $this->getContentLanguage()->timeanddate( $ts, false, false ) . " ($tzMsg)";
 
                # Variable replacement
                # Because mOutputType is OT_WIKI, this will only process {{subst:xxx}} type tags
@@ -4642,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 );
 
@@ -4849,13 +4877,11 @@ class Parser {
         * @return string|callable The old callback function for this name, if any
         */
        public function setFunctionHook( $id, callable $callback, $flags = 0 ) {
-               global $wgContLang;
-
                $oldVal = isset( $this->mFunctionHooks[$id] ) ? $this->mFunctionHooks[$id][0] : null;
                $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.' );
                }
@@ -4866,7 +4892,7 @@ class Parser {
                foreach ( $synonyms as $syn ) {
                        # Case
                        if ( !$sensitive ) {
-                               $syn = $wgContLang->lc( $syn );
+                               $syn = $this->getContentLanguage()->lc( $syn );
                        }
                        # Add leading hash
                        if ( !( $flags & self::SFH_NO_HASH ) ) {
@@ -5039,7 +5065,7 @@ class Parser {
                                unset( $paramMap['img_width'] );
                        }
 
-                       $mwArray = new MagicWordArray( array_keys( $paramMap ) );
+                       $mwArray = $this->magicWordFactory->newArray( array_keys( $paramMap ) );
 
                        $label = '';
                        $alt = '';
@@ -5158,7 +5184,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] ];
        }
@@ -5701,8 +5728,6 @@ class Parser {
         */
        public function getRevisionTimestamp() {
                if ( is_null( $this->mRevisionTimestamp ) ) {
-                       global $wgContLang;
-
                        $revObject = $this->getRevisionObject();
                        $timestamp = $revObject ? $revObject->getTimestamp() : wfTimestampNow();
 
@@ -5711,7 +5736,7 @@ class Parser {
                        # Since this value will be saved into the parser cache, served
                        # to other users, and potentially even used inside links and such,
                        # it needs to be consistent for all visitors.
-                       $this->mRevisionTimestamp = $wgContLang->userAdjust( $timestamp, '' );
+                       $this->mRevisionTimestamp = $this->getContentLanguage()->userAdjust( $timestamp, '' );
 
                }
                return $this->mRevisionTimestamp;