Remove dead code from Title::secureAndSplit()
[lhc/web/wiklou.git] / includes / Title.php
index b583554..01a28f5 100644 (file)
@@ -306,6 +306,10 @@ class Title implements LinkTarget {
        public static function newFromTextThrow( $text, $defaultNamespace = NS_MAIN ) {
                if ( is_object( $text ) ) {
                        throw new MWException( '$text must be a string, given an object' );
+               } elseif ( $text === null ) {
+                       // Legacy code relies on MalformedTitleException being thrown in this case
+                       // (happens when URL with no title in it is parsed). TODO fix
+                       throw new MalformedTitleException( 'title-invalid-empty' );
                }
 
                $titleCache = self::getTitleCache();
@@ -741,12 +745,10 @@ class Title implements LinkTarget {
        public static function makeName( $ns, $title, $fragment = '', $interwiki = '',
                $canonicalNamespace = false
        ) {
-               global $wgContLang;
-
                if ( $canonicalNamespace ) {
                        $namespace = MWNamespace::getCanonicalName( $ns );
                } else {
-                       $namespace = $wgContLang->getNsText( $ns );
+                       $namespace = MediaWikiServices::getInstance()->getContentLanguage()->getNsText( $ns );
                }
                $name = $namespace == '' ? $title : "$namespace:$title";
                if ( strval( $interwiki ) != '' ) {
@@ -1047,8 +1049,8 @@ class Title implements LinkTarget {
         * @return string Namespace text
         */
        public function getSubjectNsText() {
-               global $wgContLang;
-               return $wgContLang->getNsText( MWNamespace::getSubject( $this->mNamespace ) );
+               return MediaWikiServices::getInstance()->getContentLanguage()->
+                       getNsText( MWNamespace::getSubject( $this->mNamespace ) );
        }
 
        /**
@@ -1057,8 +1059,8 @@ class Title implements LinkTarget {
         * @return string Namespace text
         */
        public function getTalkNsText() {
-               global $wgContLang;
-               return $wgContLang->getNsText( MWNamespace::getTalk( $this->mNamespace ) );
+               return MediaWikiServices::getInstance()->getContentLanguage()->
+                       getNsText( MWNamespace::getTalk( $this->mNamespace ) );
        }
 
        /**
@@ -1289,12 +1291,9 @@ class Title implements LinkTarget {
         */
        public function isSiteConfigPage() {
                return (
-                       NS_MEDIAWIKI == $this->mNamespace
-                       && (
-                               $this->hasContentModel( CONTENT_MODEL_CSS )
-                               || $this->hasContentModel( CONTENT_MODEL_JSON )
-                               || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
-                       )
+                       $this->isSiteCssConfigPage()
+                       || $this->isSiteJsonConfigPage()
+                       || $this->isSiteJsConfigPage()
                );
        }
 
@@ -1317,13 +1316,9 @@ class Title implements LinkTarget {
         */
        public function isUserConfigPage() {
                return (
-                       NS_USER == $this->mNamespace
-                       && $this->isSubpage()
-                       && (
-                               $this->hasContentModel( CONTENT_MODEL_CSS )
-                               || $this->hasContentModel( CONTENT_MODEL_JSON )
-                               || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
-                       )
+                       $this->isUserCssConfigPage()
+                       || $this->isUserJsonConfigPage()
+                       || $this->isUserJsConfigPage()
                );
        }
 
@@ -1423,6 +1418,60 @@ class Title implements LinkTarget {
                return $this->isUserJsConfigPage();
        }
 
+       /**
+        * Is this a sitewide CSS "config" page?
+        *
+        * @return bool
+        * @since 1.32
+        */
+       public function isSiteCssConfigPage() {
+               return (
+                       NS_MEDIAWIKI == $this->mNamespace
+                       && (
+                               $this->hasContentModel( CONTENT_MODEL_CSS )
+                               // paranoia - a MediaWiki: namespace page with mismatching extension and content
+                               // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
+                               || substr( $this->getDBkey(), -4 ) === '.css'
+                       )
+               );
+       }
+
+       /**
+        * Is this a sitewide JSON "config" page?
+        *
+        * @return bool
+        * @since 1.32
+        */
+       public function isSiteJsonConfigPage() {
+               return (
+                       NS_MEDIAWIKI == $this->mNamespace
+                       && (
+                               $this->hasContentModel( CONTENT_MODEL_JSON )
+                               // paranoia - a MediaWiki: namespace page with mismatching extension and content
+                               // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
+                               || substr( $this->getDBkey(), -5 ) === '.json'
+                       )
+               );
+       }
+
+       /**
+        * Is this a sitewide JS "config" page?
+        *
+        * @return bool
+        * @since 1.31
+        */
+       public function isSiteJsConfigPage() {
+               return (
+                       NS_MEDIAWIKI == $this->mNamespace
+                       && (
+                               $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
+                               // paranoia - a MediaWiki: namespace page with mismatching extension and content
+                               // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
+                               || substr( $this->getDBkey(), -3 ) === '.js'
+                       )
+               );
+       }
+
        /**
         * Is this a talk page of some sort?
         *
@@ -1581,8 +1630,6 @@ class Title implements LinkTarget {
         * @return string The prefixed text
         */
        private function prefix( $name ) {
-               global $wgContLang;
-
                $p = '';
                if ( $this->isExternal() ) {
                        $p = $this->mInterwiki . ':';
@@ -1593,7 +1640,8 @@ class Title implements LinkTarget {
 
                        if ( $nsText === false ) {
                                // See T165149. Awkward, but better than erroneously linking to the main namespace.
-                               $nsText = $wgContLang->getNsText( NS_SPECIAL ) . ":Badtitle/NS{$this->mNamespace}";
+                               $nsText = MediaWikiServices::getInstance()->getContentLanguage()->
+                                       getNsText( NS_SPECIAL ) .  ":Badtitle/NS{$this->mNamespace}";
                        }
 
                        $p .= $nsText . ':';
@@ -1928,7 +1976,7 @@ class Title implements LinkTarget {
                                $titleRef = $this;
                                Hooks::run( 'GetLocalURL::Article', [ &$titleRef, &$url ] );
                        } else {
-                               global $wgVariantArticlePath, $wgActionPaths, $wgContLang;
+                               global $wgVariantArticlePath, $wgActionPaths;
                                $url = false;
                                $matches = [];
 
@@ -1951,7 +1999,8 @@ class Title implements LinkTarget {
                                if ( $url === false
                                        && $wgVariantArticlePath
                                        && preg_match( '/^variant=([^&]*)$/', $query, $matches )
-                                       && $this->getPageLanguage()->equals( $wgContLang )
+                                       && $this->getPageLanguage()->equals(
+                                               MediaWikiServices::getInstance()->getContentLanguage() )
                                        && $this->getPageLanguage()->hasVariants()
                                ) {
                                        $variant = urldecode( $matches[1] );
@@ -2313,6 +2362,44 @@ class Title implements LinkTarget {
                return $errors;
        }
 
+       /**
+        * Check sitewide CSS/JSON/JS permissions
+        *
+        * @param string $action The action to check
+        * @param User $user User to check
+        * @param array $errors List of current errors
+        * @param string $rigor Same format as Title::getUserPermissionsErrors()
+        * @param bool $short Short circuit on first error
+        *
+        * @return array List of errors
+        */
+       private function checkSiteConfigPermissions( $action, $user, $errors, $rigor, $short ) {
+               if ( $action != 'patrol' ) {
+                       $error = null;
+                       // Sitewide CSS/JSON/JS changes, like all NS_MEDIAWIKI changes, also require the
+                       // editinterface right. That's implemented as a restriction so no check needed here.
+                       if ( $this->isSiteCssConfigPage() && !$user->isAllowed( 'editsitecss' ) ) {
+                               $error = [ 'sitecssprotected', $action ];
+                       } elseif ( $this->isSiteJsonConfigPage() && !$user->isAllowed( 'editsitejson' ) ) {
+                               $error = [ 'sitejsonprotected', $action ];
+                       } elseif ( $this->isSiteJsConfigPage() && !$user->isAllowed( 'editsitejs' ) ) {
+                               $error = [ 'sitejsprotected', $action ];
+                       }
+
+                       if ( $error ) {
+                               if ( $user->isAllowed( 'editinterface' ) ) {
+                                       // Most users / site admins will probably find out about the new, more restrictive
+                                       // permissions by failing to edit something. Give them more info.
+                                       // TODO remove this a few release cycles after 1.32
+                                       $error = [ 'interfaceadmin-info', wfMessage( $error[0], $error[1] ) ];
+                               }
+                               $errors[] = $error;
+                       }
+               }
+
+               return $errors;
+       }
+
        /**
         * Check CSS/JSON/JS sub-page permissions
         *
@@ -2701,10 +2788,10 @@ class Title implements LinkTarget {
                                'checkReadPermissions',
                                'checkUserBlock', // for wgBlockDisablesLogin
                        ];
-               # Don't call checkSpecialsAndNSPermissions or checkUserConfigPermissions
-               # here as it will lead to duplicate error messages. This is okay to do
-               # since anywhere that checks for create will also check for edit, and
-               # those checks are called for edit.
+               # Don't call checkSpecialsAndNSPermissions, checkSiteConfigPermissions
+               # or checkUserConfigPermissions here as it will lead to duplicate
+               # error messages. This is okay to do since anywhere that checks for
+               # create will also check for edit, and those checks are called for edit.
                } elseif ( $action == 'create' ) {
                        $checks = [
                                'checkQuickPermissions',
@@ -2719,6 +2806,7 @@ class Title implements LinkTarget {
                                'checkQuickPermissions',
                                'checkPermissionHooks',
                                'checkSpecialsAndNSPermissions',
+                               'checkSiteConfigPermissions',
                                'checkUserConfigPermissions',
                                'checkPageRestrictions',
                                'checkCascadingSourcesRestrictions',
@@ -3587,10 +3675,8 @@ class Title implements LinkTarget {
         * @return string Containing capitalized title
         */
        public static function capitalize( $text, $ns = NS_MAIN ) {
-               global $wgContLang;
-
                if ( MWNamespace::isCapitalized( $ns ) ) {
-                       return $wgContLang->ucfirst( $text );
+                       return MediaWikiServices::getInstance()->getContentLanguage()->ucfirst( $text );
                } else {
                        return $text;
                }
@@ -3609,13 +3695,6 @@ class Title implements LinkTarget {
         * @return bool True on success
         */
        private function secureAndSplit() {
-               # Initialisation
-               $this->mInterwiki = '';
-               $this->mFragment = '';
-               $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN
-
-               $dbkey = $this->mDbkeyform;
-
                // @note: splitTitleString() is a temporary hack to allow MediaWikiTitleCodec to share
                //        the parsing code with Title, while avoiding massive refactoring.
                // @todo: get rid of secureAndSplit, refactor parsing code.
@@ -3623,7 +3702,7 @@ class Title implements LinkTarget {
                //        splitTitleString method, but the only implementation (MediaWikiTitleCodec) does
                $titleCodec = MediaWikiServices::getInstance()->getTitleParser();
                // MalformedTitleException can be thrown here
-               $parts = $titleCodec->splitTitleString( $dbkey, $this->getDefaultNamespace() );
+               $parts = $titleCodec->splitTitleString( $this->mDbkeyform, $this->getDefaultNamespace() );
 
                # Fill fields
                $this->setFragment( '#' . $parts['fragment'] );
@@ -4137,8 +4216,6 @@ class Title implements LinkTarget {
         *     $parent => $currentarticle
         */
        public function getParentCategories() {
-               global $wgContLang;
-
                $data = [];
 
                $titleKey = $this->getArticleID();
@@ -4157,9 +4234,11 @@ class Title implements LinkTarget {
                );
 
                if ( $res->numRows() > 0 ) {
+                       $contLang = MediaWikiServices::getInstance()->getContentLanguage();
                        foreach ( $res as $row ) {
-                               // $data[] = Title::newFromText($wgContLang->getNsText ( NS_CATEGORY ).':'.$row->cl_to);
-                               $data[$wgContLang->getNsText( NS_CATEGORY ) . ':' . $row->cl_to] = $this->getFullText();
+                               // $data[] = Title::newFromText( $contLang->getNsText ( NS_CATEGORY ).':'.$row->cl_to);
+                               $data[$contLang->getNsText( NS_CATEGORY ) . ':' . $row->cl_to] =
+                                       $this->getFullText();
                        }
                }
                return $data;
@@ -4643,11 +4722,11 @@ class Title implements LinkTarget {
                        // message content will be displayed, same for language subpages-
                        // Use always content language to avoid loading hundreds of languages
                        // to get the link color.
-                       global $wgContLang;
+                       $contLang = MediaWikiServices::getInstance()->getContentLanguage();
                        list( $name, ) = MessageCache::singleton()->figureMessage(
-                               $wgContLang->lcfirst( $this->getText() )
+                               $contLang->lcfirst( $this->getText() )
                        );
-                       $message = wfMessage( $name )->inLanguage( $wgContLang )->useDatabase( false );
+                       $message = wfMessage( $name )->inLanguage( $contLang )->useDatabase( false );
                        return $message->exists();
                }
 
@@ -4660,14 +4739,12 @@ class Title implements LinkTarget {
         * @return string|bool
         */
        public function getDefaultMessageText() {
-               global $wgContLang;
-
                if ( $this->getNamespace() != NS_MEDIAWIKI ) { // Just in case
                        return false;
                }
 
                list( $name, $lang ) = MessageCache::singleton()->figureMessage(
-                       $wgContLang->lcfirst( $this->getText() )
+                       MediaWikiServices::getInstance()->getContentLanguage()->lcfirst( $this->getText() )
                );
                $message = wfMessage( $name )->inLanguage( $lang )->useDatabase( false );
 
@@ -4794,7 +4871,6 @@ class Title implements LinkTarget {
         * @return string XML 'id' name
         */
        public function getNamespaceKey( $prepend = 'nstab-' ) {
-               global $wgContLang;
                // Gets the subject namespace of this title
                $subjectNS = MWNamespace::getSubject( $this->getNamespace() );
                // Prefer canonical namespace name for HTML IDs
@@ -4804,7 +4880,7 @@ class Title implements LinkTarget {
                        $namespaceKey = $this->getSubjectNsText();
                }
                // Makes namespace key lowercase
-               $namespaceKey = $wgContLang->lc( $namespaceKey );
+               $namespaceKey = MediaWikiServices::getInstance()->getContentLanguage()->lc( $namespaceKey );
                // Uses main
                if ( $namespaceKey == '' ) {
                        $namespaceKey = 'main';
@@ -4953,7 +5029,7 @@ class Title implements LinkTarget {
 
        /**
         * Get the language in which the content of this page is written in
-        * wikitext. Defaults to $wgContLang, but in certain cases it can be
+        * wikitext. Defaults to content language, but in certain cases it can be
         * e.g. $wgLang (such as special pages, which are in the user language).
         *
         * @since 1.18
@@ -4991,7 +5067,7 @@ class Title implements LinkTarget {
 
        /**
         * Get the language in which the content of this page is written when
-        * viewed by user. Defaults to $wgContLang, but in certain cases it can be
+        * viewed by user. Defaults to content language, but in certain cases it can be
         * e.g. $wgLang (such as special pages, which are in the user language).
         *
         * @since 1.20