X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FTitle.php;h=4c2ccda8dce8f27d1089c64a3e1d3ade600f735a;hb=fd03a2922af901d5c12e1039aed84647efd757f6;hp=dedb7ac024fa4c81be4a7c17a00fd0bbbf05a52e;hpb=3fc94ebd11723676739de45c620a55bbea56dce7;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Title.php b/includes/Title.php index dedb7ac024..4c2ccda8dc 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -47,7 +47,6 @@ class Title { */ const GAID_FOR_UPDATE = 1; - /** * @name Private member variables * Please use the accessor functions instead. @@ -388,8 +387,8 @@ class Title { $titles = array( $title ); while ( --$recurse > 0 ) { if ( $title->isRedirect() ) { - $article = new Article( $title, 0 ); - $newtitle = $article->getRedirectTarget(); + $page = WikiPage::factory( $title ); + $newtitle = $page->getRedirectTarget(); } else { break; } @@ -766,19 +765,6 @@ class Title { } /** - * Return the prefixed title with spaces _without_ the interwiki prefix - * - * @return \type{\string} the title, prefixed by the namespace but not by the interwiki prefix, with spaces - */ - public function getSemiPrefixedText() { - if ( !isset( $this->mSemiPrefixedText ) ){ - $s = ( $this->mNamespace === NS_MAIN ? '' : $this->getNsText() . ':' ) . $this->mTextform; - $s = str_replace( '_', ' ', $s ); - $this->mSemiPrefixedText = $s; - } - return $this->mSemiPrefixedText; - } - /** * Get the prefixed title with spaces, plus any fragment * (part beginning with '#') @@ -885,7 +871,7 @@ class Title { */ public function getLocalURL( $query = '', $variant = false ) { global $wgArticlePath, $wgScript, $wgServer, $wgRequest; - global $wgVariantArticlePath, $wgContLang; + global $wgVariantArticlePath; if ( is_array( $query ) ) { $query = wfArrayToCGI( $query ); @@ -904,7 +890,7 @@ class Title { } else { $dbkey = wfUrlencode( $this->getPrefixedDBkey() ); if ( $query == '' ) { - if ( $variant != false && $wgContLang->hasVariants() ) { + if ( $variant != false && $this->getPageLanguage()->hasVariants() ) { if ( !$wgVariantArticlePath ) { $variantArticlePath = "$wgScript?title=$1&variant=$2"; // default } else { @@ -973,7 +959,7 @@ class Title { * for anonymous users). * @return String the URL */ - public function getLinkUrl( $query = array(), $variant = false ) { + public function getLinkURL( $query = array(), $variant = false ) { wfProfileIn( __METHOD__ ); if ( $this->isExternal() ) { $ret = $this->getFullURL( $query ); @@ -1007,9 +993,10 @@ class Title { public function escapeFullURL( $query = '' ) { return htmlspecialchars( $this->getFullURL( $query ) ); } - + /** * HTML-escaped version of getCanonicalURL() + * @since 1.18 */ public function escapeCanonicalURL( $query = '', $variant = false ) { return htmlspecialchars( $this->getCanonicalURL( $query, $variant ) ); @@ -1019,7 +1006,7 @@ class Title { * Get the URL form for an internal link. * - Used in various Squid-related code, in case we have a different * internal hostname for the server from the exposed one. - * + * * This uses $wgInternalServer to qualify the path, or $wgServer * if $wgInternalServer is not set. If the server variable used is * protocol-relative, the URL will be expanded to http:// @@ -1029,12 +1016,8 @@ class Title { * @return String the URL */ public function getInternalURL( $query = '', $variant = false ) { - if ( $this->isExternal( ) ) { - $server = ''; - } else { - global $wgInternalServer, $wgServer; - $server = $wgInternalServer !== false ? $wgInternalServer : $wgServer; - } + global $wgInternalServer, $wgServer; + $server = $wgInternalServer !== false ? $wgInternalServer : $wgServer; $url = wfExpandUrl( $server . $this->getLocalURL( $query, $variant ), PROTO_HTTP ); wfRunHooks( 'GetInternalURL', array( &$this, &$url, $query, $variant ) ); return $url; @@ -1044,12 +1027,13 @@ class Title { * Get the URL for a canonical link, for use in things like IRC and * e-mail notifications. Uses $wgCanonicalServer and the * GetCanonicalURL hook. - * + * * NOTE: Unlike getInternalURL(), the canonical URL includes the fragment - * + * * @param $query string An optional query string * @param $variant string Language variant of URL (for sr, zh, ...) * @return string The URL + * @since 1.18 */ public function getCanonicalURL( $query = '', $variant = false ) { $url = wfExpandUrl( $this->getLocalURL( $query, $variant ) . $this->getFragmentForURL(), PROTO_CANONICAL ); @@ -1130,7 +1114,7 @@ class Title { $restrictionTypes = $this->getRestrictionTypes(); # Special pages have inherent protection - if( $this->getNamespace() == NS_SPECIAL ) { + if( $this->isSpecialPage() ) { return true; } @@ -1149,6 +1133,26 @@ class Title { return false; } + /** + * Determines if $user is unable to edit this page because it has been protected + * by $wgNamespaceProtection. + * + * @param $user User object to check permissions + * @return Bool + */ + public function isNamespaceProtected( User $user ) { + global $wgNamespaceProtection; + + if ( isset( $wgNamespaceProtection[$this->mNamespace] ) ) { + foreach ( (array)$wgNamespaceProtection[$this->mNamespace] as $right ) { + if ( $right != '' && !$user->isAllowed( $right ) ) { + return true; + } + } + } + return false; + } + /** * Is this a conversion table for the LanguageConverter? * @@ -1184,6 +1188,17 @@ class Title { return $this->mWatched; } + /** + * Can $wgUser read this page? + * + * @deprecated in 1.19; use userCan(), quickUserCan() or getUserPermissionsErrors() instead + * @return Bool + * @todo fold these checks into userCan() + */ + public function userCanRead() { + return $this->userCan( 'read' ); + } + /** * Can $wgUser perform $action on this page? * This skips potentially expensive cascading permission checks @@ -1195,42 +1210,27 @@ class Title { * May provide false positives, but should never provide a false negative. * * @param $action String action that permission needs to be checked for + * @param $user User to check (since 1.19) * @return Bool */ - public function quickUserCan( $action ) { - return $this->userCan( $action, false ); - } - - /** - * Determines if $user is unable to edit this page because it has been protected - * by $wgNamespaceProtection. - * - * @param $user User object to check permissions - * @return Bool - */ - public function isNamespaceProtected( User $user ) { - global $wgNamespaceProtection; - - if ( isset( $wgNamespaceProtection[$this->mNamespace] ) ) { - foreach ( (array)$wgNamespaceProtection[$this->mNamespace] as $right ) { - if ( $right != '' && !$user->isAllowed( $right ) ) { - return true; - } - } - } - return false; + public function quickUserCan( $action, $user = null ) { + return $this->userCan( $action, $user, false ); } /** * Can $wgUser perform $action on this page? * * @param $action String action that permission needs to be checked for + * @param $user User to check (since 1.19) * @param $doExpensiveQueries Bool Set this to false to avoid doing unnecessary queries. * @return Bool */ - public function userCan( $action, $doExpensiveQueries = true ) { - global $wgUser; - return ( $this->getUserPermissionsErrorsInternal( $action, $wgUser, $doExpensiveQueries, true ) === array() ); + public function userCan( $action, $user = null, $doExpensiveQueries = true ) { + if ( !$user instanceof User ) { + global $wgUser; + $user = $wgUser; + } + return !count( $this->getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries, true ) ); } /** @@ -1316,24 +1316,7 @@ class Title { $errors[] = array( 'cant-move-to-user-page' ); } } elseif ( !$user->isAllowed( $action, $ns ) ) { - // We avoid expensive display logic for quickUserCan's and such - $groups = false; - if ( !$short ) { - $groups = array_map( array( 'User', 'makeGroupLinkWiki' ), - User::getGroupsWithPermission( $action, $ns ) ); - } - - if ( $groups ) { - global $wgLang; - $return = array( - 'badaccess-groups', - $wgLang->commaList( $groups ), - count( $groups ) - ); - } else { - $return = array( 'badaccess-group0' ); - } - $errors[] = $return; + $errors[] = $this->missingPermissionError( $action, $short ); } return $errors; @@ -1408,7 +1391,7 @@ class Title { private function checkSpecialsAndNSPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) { # Only 'createaccount' and 'execute' can be performed on # special pages, which don't actually exist in the DB. - $specialOKActions = array( 'createaccount', 'execute' ); + $specialOKActions = array( 'createaccount', 'execute', 'read' ); if ( NS_SPECIAL == $this->mNamespace && !in_array( $action, $specialOKActions ) ) { $errors[] = array( 'ns-specialprotected' ); } @@ -1472,13 +1455,10 @@ class Title { } if ( $right != '' && !$user->isAllowed( $right, $this->mNamespace ) ) { // Users with 'editprotected' permission can edit protected pages - if ( $action == 'edit' && $user->isAllowed( 'editprotected', $this->mNamespace ) ) { - // Users with 'editprotected' permission cannot edit protected pages - // with cascading option turned on. - if ( $this->mCascadeRestriction ) { - $errors[] = array( 'protectedpagetext', $right ); - } - } else { + // without cascading option turned on. + if ( $action != 'edit' || !$user->isAllowed( 'editprotected', $this->mNamespace ) + || $this->mCascadeRestriction ) + { $errors[] = array( 'protectedpagetext', $right ); } } @@ -1586,21 +1566,19 @@ class Title { * @return Array list of errors */ private function checkUserBlock( $action, $user, $errors, $doExpensiveQueries, $short ) { - if( !$doExpensiveQueries ) { + // Account creation blocks handled at userlogin. + // Unblocking handled in SpecialUnblock + if( !$doExpensiveQueries || in_array( $action, array( 'createaccount', 'unblock' ) ) ) { return $errors; } global $wgContLang, $wgLang, $wgEmailConfirmToEdit; - if ( $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount' ) { + if ( $wgEmailConfirmToEdit && !$user->isEmailConfirmed() ) { $errors[] = array( 'confirmedittext' ); } - if ( in_array( $action, array( 'read', 'createaccount', 'unblock' ) ) ){ - // Edit blocks should not affect reading. - // Account creation blocks handled at userlogin. - // Unblocking handled in SpecialUnblock - } elseif( ( $action == 'edit' || $action == 'create' ) && !$user->isBlockedFrom( $this ) ){ + if ( ( $action == 'edit' || $action == 'create' ) && !$user->isBlockedFrom( $this ) ) { // Don't block the user from editing their own talk page unless they've been // explicitly blocked from that too. } elseif( $user->isBlocked() && $user->mBlock->prevents( $action ) !== false ) { @@ -1641,6 +1619,128 @@ class Title { return $errors; } + /** + * Check that the user is allowed to read this page. + * + * @param $action String the action to check + * @param $user User to check + * @param $errors Array list of current errors + * @param $doExpensiveQueries Boolean whether or not to perform expensive queries + * @param $short Boolean short circuit on first error + * + * @return Array list of errors + */ + private function checkReadPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) { + static $useShortcut = null; + + # Initialize the $useShortcut boolean, to determine if we can skip quite a bit of code below + if ( is_null( $useShortcut ) ) { + global $wgGroupPermissions, $wgRevokePermissions; + $useShortcut = true; + if ( empty( $wgGroupPermissions['*']['read'] ) ) { + # Not a public wiki, so no shortcut + $useShortcut = false; + } elseif ( !empty( $wgRevokePermissions ) ) { + /** + * Iterate through each group with permissions being revoked (key not included since we don't care + * what the group name is), then check if the read permission is being revoked. If it is, then + * we don't use the shortcut below since the user might not be able to read, even though anon + * reading is allowed. + */ + foreach ( $wgRevokePermissions as $perms ) { + if ( !empty( $perms['read'] ) ) { + # We might be removing the read right from the user, so no shortcut + $useShortcut = false; + break; + } + } + } + } + + # Shortcut for public wikis, allows skipping quite a bit of code + if ( $useShortcut ) { + return $errors; + } + + # If the user is allowed to read pages, he is allowed to read all pages + if ( $user->isAllowed( 'read', $this->mNamespace ) ) { + return $errors; + } + + # Always grant access to the login page. + # Even anons need to be able to log in. + if ( $this->isSpecial( 'Userlogin' ) || $this->isSpecial( 'ChangePassword' ) ) { + return $errors; + } + + # Time to check the whitelist + global $wgWhitelistRead; + + # Only to these checks is there's something to check against + if ( is_array( $wgWhitelistRead ) && count( $wgWhitelistRead ) ) { + # Check for explicit whitelisting + $name = $this->getPrefixedText(); + $dbName = $this->getPrefixedDBKey(); + + // Check with and without underscores + if ( in_array( $name, $wgWhitelistRead, true ) || in_array( $dbName, $wgWhitelistRead, true ) ) { + return $errors; + } + + # Old settings might have the title prefixed with + # a colon for main-namespace pages + if ( $this->getNamespace() == NS_MAIN ) { + if ( in_array( ':' . $name, $wgWhitelistRead ) ) { + return $errors; + } + } + + # If it's a special page, ditch the subpage bit and check again + if ( $this->isSpecialPage() ) { + $name = $this->getDBkey(); + list( $name, /* $subpage */ ) = SpecialPageFactory::resolveAlias( $name ); + if ( $name !== false ) { + $pure = SpecialPage::getTitleFor( $name )->getPrefixedText(); + if ( in_array( $pure, $wgWhitelistRead, true ) ) { + return $errors; + } + } + } + } + + $errors[] = $this->missingPermissionError( $action, $short ); + return $errors; + } + + /** + * Get a description array when the user doesn't have the right to perform + * $action (i.e. when User::isAllowed() returns false) + * + * @param $action String the action to check + * @param $short Boolean short circuit on first error + * @return Array list of errors + */ + private function missingPermissionError( $action, $short ) { + // We avoid expensive display logic for quickUserCan's and such + if ( $short ) { + return array( 'badaccess-group0' ); + } + + $groups = array_map( array( 'User', 'makeGroupLinkWiki' ), + User::getGroupsWithPermission( $action, $this->mNamespace ) ); + + if ( count( $groups ) ) { + global $wgLang; + return array( + 'badaccess-groups', + $wgLang->commaList( $groups ), + count( $groups ) + ); + } else { + return array( 'badaccess-group0' ); + } + } + /** * Can $user perform $action on this page? This is an internal function, * which checks ONLY that previously checked by userCan (i.e. it leaves out @@ -1655,20 +1755,28 @@ class Title { protected function getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries = true, $short = false ) { wfProfileIn( __METHOD__ ); - $errors = array(); - $checks = array( - 'checkQuickPermissions', - 'checkPermissionHooks', - 'checkSpecialsAndNSPermissions', - 'checkCSSandJSPermissions', - 'checkPageRestrictions', - 'checkCascadingSourcesRestrictions', - 'checkActionPermissions', - 'checkUserBlock' - ); + # Read has special handling + if ( $action == 'read' ) { + $checks = array( + 'checkPermissionHooks', + 'checkReadPermissions', + ); + } else { + $checks = array( + 'checkQuickPermissions', + 'checkPermissionHooks', + 'checkSpecialsAndNSPermissions', + 'checkCSSandJSPermissions', + 'checkPageRestrictions', + 'checkCascadingSourcesRestrictions', + 'checkActionPermissions', + 'checkUserBlock' + ); + } + $errors = array(); while( count( $checks ) > 0 && - !( $short && count( $errors ) > 0 ) ) { + !( $short && count( $errors ) > 0 ) ) { $method = array_shift( $checks ); $errors = $this->$method( $action, $user, $errors, $doExpensiveQueries, $short ); } @@ -1797,108 +1905,12 @@ class Title { // Interwiki title or immovable namespace. Hooks don't get to override here return false; } - + $result = true; wfRunHooks( 'TitleIsMovable', array( $this, &$result ) ); return $result; } - /** - * Can $wgUser read this page? - * - * @return Bool - * @todo fold these checks into userCan() - */ - public function userCanRead() { - global $wgUser, $wgGroupPermissions; - - static $useShortcut = null; - - # Initialize the $useShortcut boolean, to determine if we can skip quite a bit of code below - if ( is_null( $useShortcut ) ) { - global $wgRevokePermissions; - $useShortcut = true; - if ( empty( $wgGroupPermissions['*']['read'] ) ) { - # Not a public wiki, so no shortcut - $useShortcut = false; - } elseif ( !empty( $wgRevokePermissions ) ) { - /** - * Iterate through each group with permissions being revoked (key not included since we don't care - * what the group name is), then check if the read permission is being revoked. If it is, then - * we don't use the shortcut below since the user might not be able to read, even though anon - * reading is allowed. - */ - foreach ( $wgRevokePermissions as $perms ) { - if ( !empty( $perms['read'] ) ) { - # We might be removing the read right from the user, so no shortcut - $useShortcut = false; - break; - } - } - } - } - - $result = null; - wfRunHooks( 'userCan', array( &$this, &$wgUser, 'read', &$result ) ); - if ( $result !== null ) { - return $result; - } - - # Shortcut for public wikis, allows skipping quite a bit of code - if ( $useShortcut ) { - return true; - } - - if ( $wgUser->isAllowed( 'read' ) ) { - return true; - } else { - global $wgWhitelistRead; - - # Always grant access to the login page. - # Even anons need to be able to log in. - if ( $this->isSpecial( 'Userlogin' ) || $this->isSpecial( 'ChangePassword' ) ) { - return true; - } - - # Bail out if there isn't whitelist - if ( !is_array( $wgWhitelistRead ) ) { - return false; - } - - # Check for explicit whitelisting - $name = $this->getPrefixedText(); - $dbName = $this->getPrefixedDBKey(); - // Check with and without underscores - if ( in_array( $name, $wgWhitelistRead, true ) || in_array( $dbName, $wgWhitelistRead, true ) ) - return true; - - # Old settings might have the title prefixed with - # a colon for main-namespace pages - if ( $this->getNamespace() == NS_MAIN ) { - if ( in_array( ':' . $name, $wgWhitelistRead ) ) { - return true; - } - } - - # If it's a special page, ditch the subpage bit and check again - if ( $this->getNamespace() == NS_SPECIAL ) { - $name = $this->getDBkey(); - list( $name, /* $subpage */ ) = SpecialPageFactory::resolveAlias( $name ); - if ( $name === false ) { - # Invalid special page, but we show standard login required message - return false; - } - - $pure = SpecialPage::getTitleFor( $name )->getPrefixedText(); - if ( in_array( $pure, $wgWhitelistRead, true ) ) { - return true; - } - } - - } - return false; - } - /** * Is this the mainpage? * @note Title::newFromText seams to be sufficiently optimized by the title @@ -1933,6 +1945,57 @@ class Title { : false; } + /** + * Returns true if the title is inside the specified namespace. + * + * Please make use of this instead of comparing to getNamespace() + * This function is much more resistant to changes we may make + * to namespaces than code that makes direct comparisons. + * @param $ns The namespace + * @return bool + * @since 1.19 + */ + public function inNamespace( $ns ) { + return MWNamespace::equals( $this->getNamespace(), $ns ); + } + + /** + * Returns true if the title is inside one of the specified namespaces. + * + * @param ...$namespaces The namespaces to check for + * @return bool + * @since 1.19 + */ + public function inNamespaces( /* ... */ ) { + $namespaces = func_get_args(); + if ( count( $namespaces ) > 0 && is_array( $namespaces[0] ) ) { + $namespaces = $namespaces[0]; + } + + foreach ( $namespaces as $ns ) { + if ( $this->inNamespace( $ns ) ) { + return true; + } + } + + return false; + } + + /** + * Returns true if the title has the same subject namespace as the + * namespace specified. + * For example this method will take NS_USER and return true if namespace + * is either NS_USER or NS_USER_TALK since both of them have NS_USER + * as their subject namespace. + * + * This is MUCH simpler than individually testing for equivilance + * against both NS_USER and NS_USER_TALK, and is also forward compatible. + * @since 1.19 + */ + public function hasSubjectNamespace( $ns ) { + return MWNamespace::subjectEquals( $this->getNamespace(), $ns ); + } + /** * Does this have subpages? (Warning, usually requires an extra DB query.) * @@ -2038,7 +2101,10 @@ class Title { public function getSkinFromCssJsSubpage() { $subpage = explode( '/', $this->mTextform ); $subpage = $subpage[ count( $subpage ) - 1 ]; - return( str_replace( array( '.css', '.js' ), array( '', '' ), $subpage ) ); + $lastdot = strrpos( $subpage, '.' ); + if ( $lastdot === false ) + return $subpage; # Never happens: only called for names ending in '.css' or '.js' + return substr( $subpage, 0, $lastdot ); } /** @@ -2565,7 +2631,7 @@ class Title { */ public function invalidateCache() { if ( wfReadOnly() ) { - return; + return false; } $dbw = wfGetDB( DB_MASTER ); $success = $dbw->update( @@ -2826,7 +2892,7 @@ class Title { : $dbkey; // Any remaining initial :s are illegal. - if ( $dbkey !== '' && ':' == $dbkey { 0 } ) { + if ( $dbkey !== '' && ':' == $dbkey[0] ) { return false; } @@ -2853,10 +2919,6 @@ class Title { $this->mFragment = str_replace( '_', ' ', substr( $fragment, 1 ) ); } - public function setInterwiki( $interwiki ) { - $this->mInterwiki = $interwiki; - } - /** * Get a Title object associated with the talk page of this article * @@ -3127,9 +3189,7 @@ class Title { $errors = array(); - if ( $nt->getNamespace() != NS_FILE ) { - $errors[] = array( 'imagenocrossnamespace' ); - } + // wfFindFile( $nt ) / wfLocalFile( $nt ) is not allowed until below $file = wfLocalFile( $this ); if ( $file->exists() ) { @@ -3141,6 +3201,15 @@ class Title { } } + if ( $nt->getNamespace() != NS_FILE ) { + $errors[] = array( 'imagenocrossnamespace' ); + // From here we want to do checks on a file object, so if we can't + // create one, we must return. + return $errors; + } + + // wfFindFile( $nt ) / wfLocalFile( $nt ) is allowed below here + $destFile = wfLocalFile( $nt ); if ( !$wgUser->isAllowed( 'reupload-shared' ) && !$destFile->exists() && wfFindFile( $nt ) ) { $errors[] = array( 'file-exists-sharedrepo' ); @@ -3161,15 +3230,16 @@ class Title { * @return Mixed true on success, getUserPermissionsErrors()-like array on failure */ public function moveTo( &$nt, $auth = true, $reason = '', $createRedirect = true ) { - global $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase; - + global $wgUser; $err = $this->isValidMoveOperation( $nt, $auth, $reason ); if ( is_array( $err ) ) { + // Auto-block user's IP if the account was "hard" blocked + $wgUser->spreadAnyEditBlock(); return $err; } - // If it is a file, move it first. It is done before all other moving stuff is - // done because it's hard to revert + // If it is a file, move it first. + // It is done before all other moving stuff is done because it's hard to revert. $dbw = wfGetDB( DB_MASTER ); if ( $this->getNamespace() == NS_FILE ) { $file = wfLocalFile( $this ); @@ -3180,6 +3250,9 @@ class Title { } } } + // Clear RepoGroup process cache + RepoGroup::singleton()->clearCache( $this ); + RepoGroup::singleton()->clearCache( $nt ); # clear false negative cache $dbw->begin(); # If $file was a LocalFile, its transaction would have closed our own. $pageid = $this->getArticleID( self::GAID_FOR_UPDATE ); @@ -3187,7 +3260,7 @@ class Title { $pageCountChange = ( $createRedirect ? 1 : 0 ) - ( $nt->exists() ? 1 : 0 ); // Do the actual move - $err = $this->moveOverExistingRedirect( $nt, $reason, $createRedirect ); + $err = $this->moveToInternal( $nt, $reason, $createRedirect ); if ( is_array( $err ) ) { # @todo FIXME: What about the File we have already moved? $dbw->rollback(); @@ -3219,15 +3292,6 @@ class Title { ); } - if ( $wgEnableInterwikiTemplatesTracking && $wgGlobalDatabase ) { - $dbw2 = wfGetDB( DB_MASTER, array(), $wgGlobalDatabase ); - $dbw2->update( 'globaltemplatelinks', - array( 'gtl_from_namespace' => $nt->getNamespace(), - 'gtl_from_title' => $nt->getText() ), - array ( 'gtl_from_page' => $pageid ), - __METHOD__ ); - } - if ( $protected ) { # Protect the redirect title as the title used to be... $dbw->insertSelect( 'page_restrictions', 'page_restrictions', @@ -3298,16 +3362,15 @@ class Title { if ( $this->getArticleID() === 0 ) { MessageCache::singleton()->replace( $this->getDBkey(), false ); } else { - $oldarticle = new Article( $this ); - MessageCache::singleton()->replace( $this->getDBkey(), $oldarticle->getContent() ); + $rev = Revision::newFromTitle( $this ); + MessageCache::singleton()->replace( $this->getDBkey(), $rev->getText() ); } } if ( $nt->getNamespace() == NS_MEDIAWIKI ) { - $newarticle = new Article( $nt ); - MessageCache::singleton()->replace( $nt->getDBkey(), $newarticle->getContent() ); + $rev = Revision::newFromTitle( $nt ); + MessageCache::singleton()->replace( $nt->getDBkey(), $rev->getText() ); } - global $wgUser; wfRunHooks( 'TitleMoveComplete', array( &$this, &$nt, &$wgUser, $pageid, $redirid ) ); return true; } @@ -3321,8 +3384,8 @@ class Title { * @param $createRedirect Bool Whether to leave a redirect at the old title. Ignored * if the user doesn't have the suppressredirect right */ - private function moveOverExistingRedirect( &$nt, $reason = '', $createRedirect = true ) { - global $wgUser, $wgContLang, $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase; + private function moveToInternal( &$nt, $reason = '', $createRedirect = true ) { + global $wgUser, $wgContLang; if ( $nt->exists() ) { $moveOverRedirect = true; @@ -3381,6 +3444,7 @@ class Title { $dbw->delete( 'templatelinks', array( 'tl_from' => $newid ), __METHOD__ ); $dbw->delete( 'externallinks', array( 'el_from' => $newid ), __METHOD__ ); $dbw->delete( 'langlinks', array( 'll_from' => $newid ), __METHOD__ ); + $dbw->delete( 'iwlinks', array( 'iwl_from' => $newid ), __METHOD__ ); $dbw->delete( 'redirect', array( 'rd_from' => $newid ), __METHOD__ ); $dbw->delete( 'page_props', array( 'pp_page' => $newid ), __METHOD__ ); } @@ -3389,14 +3453,6 @@ class Title { array( 'rc_timestamp' => $rcts, 'rc_namespace' => $newns, 'rc_title' => $newdbk, 'rc_new' => 1 ), __METHOD__ ); - - if ( $wgEnableInterwikiTemplatesTracking && $wgGlobalDatabase ) { - $dbw2 = wfGetDB( DB_MASTER, array(), $wgGlobalDatabase ); - $dbw2->delete( 'globaltemplatelinks', - array( 'gtl_from_wiki' => wfGetID(), - 'gtl_from_page' => $newid ), - __METHOD__ ); - } } # Save a null revision in the page's history notifying of the move @@ -3420,7 +3476,7 @@ class Title { ); $nt->resetArticleID( $oldid ); - $article = new Article( $nt ); + $article = WikiPage::factory( $nt ); wfRunHooks( 'NewRevisionFromEditComplete', array( $article, $nullRevision, $latest, $wgUser ) ); $article->setCachedLastEditTime( $now ); @@ -3429,7 +3485,7 @@ class Title { if ( $createRedirect || !$wgUser->isAllowed( 'suppressredirect' ) ) { $mwRedir = MagicWord::get( 'redirect' ); $redirectText = $mwRedir->getSynonym( 0 ) . ' [[' . $nt->getPrefixedText() . "]]\n"; - $redirectArticle = new Article( $this ); + $redirectArticle = WikiPage::factory( $this ); $newid = $redirectArticle->insertOn( $dbw ); if ( $newid ) { // sanity $redirectRevision = new Revision( array( @@ -3604,6 +3660,9 @@ class Title { } # Get the article text $rev = Revision::newFromTitle( $nt ); + if( !is_object( $rev ) ){ + return false; + } $text = $rev->getText(); # Does the redirect point to the source? # Or is it a broken self-redirect, usually caused by namespace collisions? @@ -3949,7 +4008,7 @@ class Title { return $this->mDbkeyform == ''; case NS_MEDIAWIKI: // known system message - return $this->getDefaultMessageText() !== false; + return $this->hasSourceText() !== false; default: return false; } @@ -3979,8 +4038,13 @@ class Title { if ( $this->mNamespace == NS_MEDIAWIKI ) { // If the page doesn't exist but is a known system message, default - // message content will be displayed, same for language subpages - return $this->getDefaultMessageText() !== false; + // 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; + list( $name, $lang ) = MessageCache::singleton()->figureMessage( $wgContLang->lcfirst( $this->getText() ) ); + $message = wfMessage( $name )->inLanguage( $wgContLang )->useDatabase( false ); + return $message->exists(); } return false; @@ -4169,7 +4233,7 @@ class Title { * @return boolean */ public function isSpecial( $name ) { - if ( $this->getNamespace() == NS_SPECIAL ) { + if ( $this->isSpecialPage() ) { list( $thisName, /* $subpage */ ) = SpecialPageFactory::resolveAlias( $this->getDBkey() ); if ( $name == $thisName ) { return true; @@ -4185,10 +4249,10 @@ class Title { * @return Title */ public function fixSpecialName() { - if ( $this->getNamespace() == NS_SPECIAL ) { - list( $canonicalName, /*...*/ ) = SpecialPageFactory::resolveAlias( $this->mDbkeyform ); + if ( $this->isSpecialPage() ) { + list( $canonicalName, $par ) = SpecialPageFactory::resolveAlias( $this->mDbkeyform ); if ( $canonicalName ) { - $localName = SpecialPageFactory::getLocalNameFor( $canonicalName ); + $localName = SpecialPageFactory::getLocalNameFor( $canonicalName, $par ); if ( $localName != $this->mDbkeyform ) { return Title::makeTitle( NS_SPECIAL, $localName ); } @@ -4265,7 +4329,7 @@ class Title { /** * Get a backlink cache object * - * @return object BacklinkCache + * @return BacklinkCache */ function getBacklinkCache() { if ( is_null( $this->mBacklinkCache ) ) { @@ -4296,7 +4360,7 @@ class Title { * @return array applicable restriction types */ public function getRestrictionTypes() { - if ( $this->getNamespace() == NS_SPECIAL ) { + if ( $this->isSpecialPage() ) { return array(); } @@ -4373,7 +4437,7 @@ class Title { */ public function getPageLanguage() { global $wgLang; - if ( $this->getNamespace() == NS_SPECIAL ) { + if ( $this->isSpecialPage() ) { // special pages are in the user language return $wgLang; } elseif ( $this->isCssOrJsPage() ) {