X-Git-Url: http://git.cyclocoop.org/?a=blobdiff_plain;ds=sidebyside;f=includes%2FTitle.php;h=63d690ee177bb690daffe1f54f8e5cbf76235a27;hb=6c2f1f06a23b1702db85b28c7947ed7a9a0cb6f6;hp=051998c0ef43bd19079cc7e1e9bfe09adaa66e5d;hpb=7bb50c630a6b760c0cdc7662c44f8c3607954a19;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Title.php b/includes/Title.php index 051998c0ef..63d690ee17 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -1,15 +1,25 @@ mPrefixedText ) ) { // FIXME: bad usage of empty() ? + // @todo FIXME: Bad usage of empty() ? + if ( empty( $this->mPrefixedText ) ) { $s = $this->prefix( $this->mTextform ); $s = str_replace( '_', ' ', $s ); $this->mPrefixedText = $s; @@ -901,6 +911,7 @@ class Title { } } } + if ( $url === false ) { if ( $query == '-' ) { $query = ''; @@ -909,7 +920,7 @@ class Title { } } - // FIXME: this causes breakage in various places when we + // @todo FIXME: This causes breakage in various places when we // actually expected a local URL and end up with dupe prefixes. if ( $wgRequest->getVal( 'action' ) == 'render' ) { $url = $wgServer . $url; @@ -1172,11 +1183,12 @@ class Title { /** * Can $user perform $action on this page? * - * FIXME: This *does not* check throttles (User::pingLimiter()). + * @todo FIXME: This *does not* check throttles (User::pingLimiter()). * * @param $action String action that permission needs to be checked for * @param $user User to check - * @param $doExpensiveQueries Bool Set this to false to avoid doing unnecessary queries. + * @param $doExpensiveQueries Bool Set this to false to avoid doing unnecessary queries by + * skipping checks for cascading protections and user blocks. * @param $ignoreErrors Array of Strings Set this to a list of message keys whose corresponding errors may be ignored. * @return Array of arguments to wfMsg to explain permissions problems. */ @@ -1287,13 +1299,13 @@ class Title { if ( is_array( $result ) && count( $result ) && !is_array( $result[0] ) ) { // A single array representing an error $errors[] = $result; - } else if ( is_array( $result ) && is_array( $result[0] ) ) { + } elseif ( is_array( $result ) && is_array( $result[0] ) ) { // A nested array representing multiple errors $errors = array_merge( $errors, $result ); - } else if ( $result !== '' && is_string( $result ) ) { + } elseif ( $result !== '' && is_string( $result ) ) { // A string representing a message-id $errors[] = array( $result ); - } else if ( $result === false ) { + } elseif ( $result === false ) { // a generic "We don't want them to do that" $errors[] = array( 'badaccess-group0' ); } @@ -1380,9 +1392,9 @@ class Title { if ( $action != 'patrol' && !$user->isAllowed( 'editusercssjs' ) && !preg_match( '/^' . preg_quote( $user->getName(), '/' ) . '\//', $this->mTextform ) ) { if ( $this->isCssSubpage() && !$user->isAllowed( 'editusercss' ) ) { - $errors[] = array( 'customcssjsprotected' ); - } else if ( $this->isJsSubpage() && !$user->isAllowed( 'edituserjs' ) ) { - $errors[] = array( 'customcssjsprotected' ); + $errors[] = array( 'customcssprotected' ); + } elseif ( $this->isJsSubpage() && !$user->isAllowed( 'edituserjs' ) ) { + $errors[] = array( 'customjsprotected' ); } } @@ -1522,7 +1534,7 @@ class Title { * @return Array list of errors */ private function checkUserBlock( $action, $user, $errors, $doExpensiveQueries, $short ) { - if( $short && count( $errors ) > 0 ) { + if( !$doExpensiveQueries ) { return $errors; } @@ -1563,12 +1575,12 @@ class Title { $blockExpiry = $user->mBlock->mExpiry; $blockTimestamp = $wgLang->timeanddate( wfTimestamp( TS_MW, $user->mBlock->mTimestamp ), true ); if ( $blockExpiry == 'infinity' ) { - $blockExpiry = wfMessage( 'infiniteblock' ); + $blockExpiry = wfMessage( 'infiniteblock' )->text(); } else { $blockExpiry = $wgLang->timeanddate( wfTimestamp( TS_MW, $blockExpiry ), true ); } - $intended = $user->mBlock->getTarget(); + $intended = strval( $user->mBlock->getTarget() ); $errors[] = array( ( $block->mAuto ? 'autoblockedtext' : 'blockedtext' ), $link, $reason, $ip, $name, $blockid, $blockExpiry, $intended, $blockTimestamp ); @@ -1751,7 +1763,7 @@ class Title { # 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 @@ -1785,7 +1797,7 @@ class Title { # Always grant access to the login page. # Even anons need to be able to log in. - if ( $this->isSpecial( 'Userlogin' ) || $this->isSpecial( 'Resetpass' ) ) { + if ( $this->isSpecial( 'Userlogin' ) || $this->isSpecial( 'ChangePassword' ) ) { return true; } @@ -1812,7 +1824,7 @@ class Title { # If it's a special page, ditch the subpage bit and check again if ( $this->getNamespace() == NS_SPECIAL ) { $name = $this->getDBkey(); - list( $name, /* $subpage */ ) = SpecialPage::resolveAliasWithSubpage( $name ); + list( $name, /* $subpage */ ) = SpecialPageFactory::resolveAlias( $name ); if ( $name === false ) { # Invalid special page, but we show standard login required message return false; @@ -2026,7 +2038,7 @@ class Title { if ( isset( $this->mCascadeSources ) && $getPages ) { return array( $this->mCascadeSources, $this->mCascadingRestrictions ); - } else if ( isset( $this->mHasCascadingRestrictions ) && !$getPages ) { + } elseif ( isset( $this->mHasCascadingRestrictions ) && !$getPages ) { return array( $this->mHasCascadingRestrictions, $pagerestrictions ); } @@ -2498,7 +2510,7 @@ class Title { * @return String the prefixed text * @private */ - /* private */ function prefix( $name ) { + private function prefix( $name ) { $p = ''; if ( $this->mInterwiki != '' ) { $p = $this->mInterwiki . ':'; @@ -2569,8 +2581,6 @@ class Title { global $wgContLang, $wgLocalInterwiki; # Initialisation - $rxTc = self::getTitleInvalidRegex(); - $this->mInterwiki = $this->mFragment = ''; $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN @@ -2601,7 +2611,7 @@ class Title { # Initial colon indicates main namespace rather than specified default # but should not create invalid {ns,title} pairs such as {0,Project:Foo} - if ( ':' == $dbkey { 0 } ) { + if ( ':' == $dbkey[0] ) { $this->mNamespace = NS_MAIN; $dbkey = substr( $dbkey, 1 ); # remove the colon but continue processing $dbkey = trim( $dbkey, '_' ); # remove any subsequent whitespace @@ -2623,7 +2633,7 @@ class Title { if ( $wgContLang->getNsIndex( $x[1] ) ) { # Disallow Talk:File:x type titles... return false; - } else if ( Interwiki::isValidInterwiki( $x[1] ) ) { + } elseif ( Interwiki::isValidInterwiki( $x[1] ) ) { # Disallow Talk:Interwiki:x type titles... return false; } @@ -2672,7 +2682,7 @@ class Title { } $fragment = strstr( $dbkey, '#' ); if ( false !== $fragment ) { - $this->setFragment( preg_replace( '/^#_*/', '#', $fragment ) ); + $this->setFragment( $fragment ); $dbkey = substr( $dbkey, 0, strlen( $dbkey ) - strlen( $fragment ) ); # remove whitespace again: prevents "Foo_bar_#" # becoming "Foo_bar_" @@ -2680,6 +2690,7 @@ class Title { } # Reject illegal characters. + $rxTc = self::getTitleInvalidRegex(); if ( preg_match( $rxTc, $dbkey ) ) { return false; } @@ -3089,14 +3100,14 @@ class Title { } $dbw->begin(); # If $file was a LocalFile, its transaction would have closed our own. - $pageid = $this->getArticleID( GAID_FOR_UPDATE ); + $pageid = $this->getArticleID( self::GAID_FOR_UPDATE ); $protected = $this->isProtected(); $pageCountChange = ( $createRedirect ? 1 : 0 ) - ( $nt->exists() ? 1 : 0 ); // Do the actual move $err = $this->moveToInternal( $nt, $reason, $createRedirect ); if ( is_array( $err ) ) { - # FIXME: What about the File we have already moved? + # @todo FIXME: What about the File we have already moved? $dbw->rollback(); return $err; } @@ -3147,7 +3158,8 @@ class Title { if ( $reason ) { $comment .= wfMsgForContent( 'colon-separator' ) . $reason; } - $log->addEntry( 'move_prot', $nt, $comment, array( $this->getPrefixedText() ) ); // FIXME: $params? + // @todo FIXME: $params? + $log->addEntry( 'move_prot', $nt, $comment, array( $this->getPrefixedText() ) ); } # Update watchlists @@ -3167,7 +3179,7 @@ class Title { $u->doUpdate(); $dbw->commit(); - + # Update site_stats if ( $this->isContentPage() && !$nt->isContentPage() ) { # No longer a content page @@ -3279,9 +3291,6 @@ class Title { } $nullRevId = $nullRevision->insertOn( $dbw ); - $article = new Article( $this ); - wfRunHooks( 'NewRevisionFromEditComplete', array( $article, $nullRevision, $latest, $wgUser ) ); - # Change the name of the target page: $dbw->update( 'page', /* SET */ array( @@ -3295,6 +3304,9 @@ class Title { ); $nt->resetArticleID( $oldid ); + $article = new Article( $nt ); + wfRunHooks( 'NewRevisionFromEditComplete', array( $article, $nullRevision, $latest, $wgUser ) ); + # Recreate the redirect, this time in the other direction. if ( $createRedirect || !$wgUser->isAllowed( 'suppressredirect' ) ) { $mwRedir = MagicWord::get( 'redirect' ); @@ -3638,65 +3650,68 @@ class Title { * @return Revision|Null if page doesn't exist */ public function getFirstRevision( $flags = 0 ) { - $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); $pageId = $this->getArticleId( $flags ); - if ( !$pageId ) { - return null; - } - $row = $db->selectRow( 'revision', '*', - array( 'rev_page' => $pageId ), - __METHOD__, - array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 1 ) - ); - if ( !$row ) { - return null; - } else { - return new Revision( $row ); + if ( $pageId ) { + $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); + $row = $db->selectRow( 'revision', '*', + array( 'rev_page' => $pageId ), + __METHOD__, + array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 1 ) + ); + if ( $row ) { + return new Revision( $row ); + } } + return null; } /** - * Check if this is a new page + * Get the oldest revision timestamp of this page * - * @return bool + * @param $flags Int Title::GAID_FOR_UPDATE + * @return String: MW timestamp */ - public function isNewPage() { - $dbr = wfGetDB( DB_SLAVE ); - return (bool)$dbr->selectField( 'page', 'page_is_new', $this->pageCond(), __METHOD__ ); + public function getEarliestRevTime( $flags = 0 ) { + $rev = $this->getFirstRevision( $flags ); + return $rev ? $rev->getTimestamp() : null; } /** - * Get the oldest revision timestamp of this page + * Check if this is a new page * - * @return String: MW timestamp + * @return bool */ - public function getEarliestRevTime() { + public function isNewPage() { $dbr = wfGetDB( DB_SLAVE ); - if ( $this->exists() ) { - $min = $dbr->selectField( 'revision', - 'MIN(rev_timestamp)', - array( 'rev_page' => $this->getArticleId() ), - __METHOD__ ); - return wfTimestampOrNull( TS_MW, $min ); - } - return null; + return (bool)$dbr->selectField( 'page', 'page_is_new', $this->pageCond(), __METHOD__ ); } /** - * Get the number of revisions between the given revision IDs. + * Get the number of revisions between the given revision. * Used for diffs and other things that really need it. * - * @param $old Int Revision ID. - * @param $new Int Revision ID. - * @return Int Number of revisions between these IDs. + * @param $old int|Revision Old revision or rev ID (first before range) + * @param $new int|Revision New revision or rev ID (first after range) + * @return Int Number of revisions between these revisions. */ public function countRevisionsBetween( $old, $new ) { + if ( !( $old instanceof Revision ) ) { + $old = Revision::newFromTitle( $this, (int)$old ); + } + if ( !( $new instanceof Revision ) ) { + $new = Revision::newFromTitle( $this, (int)$new ); + } + if ( !$old || !$new ) { + return 0; // nothing to compare + } $dbr = wfGetDB( DB_SLAVE ); - return (int)$dbr->selectField( 'revision', 'count(*)', array( - 'rev_page' => intval( $this->getArticleId() ), - 'rev_id > ' . intval( $old ), - 'rev_id < ' . intval( $new ) - ), __METHOD__ + return (int)$dbr->selectField( 'revision', 'count(*)', + array( + 'rev_page' => $this->getArticleId(), + 'rev_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( $old->getTimestamp() ) ), + 'rev_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $new->getTimestamp() ) ) + ), + __METHOD__ ); } @@ -3704,23 +3719,31 @@ class Title { * Get the number of authors between the given revision IDs. * Used for diffs and other things that really need it. * - * @param $fromRevId Int Revision ID (first before range) - * @param $toRevId Int Revision ID (first after range) + * @param $old int|Revision Old revision or rev ID (first before range) + * @param $new int|Revision New revision or rev ID (first after range) * @param $limit Int Maximum number of authors - * @param $flags Int Title::GAID_FOR_UPDATE - * @return Int + * @return Int Number of revision authors between these revisions. */ - public function countAuthorsBetween( $fromRevId, $toRevId, $limit, $flags = 0 ) { - $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); - $res = $db->select( 'revision', 'DISTINCT rev_user_text', + public function countAuthorsBetween( $old, $new, $limit ) { + if ( !( $old instanceof Revision ) ) { + $old = Revision::newFromTitle( $this, (int)$old ); + } + if ( !( $new instanceof Revision ) ) { + $new = Revision::newFromTitle( $this, (int)$new ); + } + if ( !$old || !$new ) { + return 0; // nothing to compare + } + $dbr = wfGetDB( DB_SLAVE ); + $res = $dbr->select( 'revision', 'DISTINCT rev_user_text', array( 'rev_page' => $this->getArticleID(), - 'rev_id > ' . (int)$fromRevId, - 'rev_id < ' . (int)$toRevId + 'rev_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( $old->getTimestamp() ) ), + 'rev_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $new->getTimestamp() ) ) ), __METHOD__, - array( 'LIMIT' => $limit ) + array( 'LIMIT' => $limit + 1 ) // add one so caller knows it was truncated ); - return (int)$db->numRows( $res ); + return (int)$dbr->numRows( $res ); } /** @@ -3801,7 +3824,7 @@ class Title { return (bool)wfFindFile( $this ); case NS_SPECIAL: // valid special page - return SpecialPage::exists( $this->getDBkey() ); + return SpecialPageFactory::exists( $this->getDBkey() ); case NS_MAIN: // selflink, possibly with fragment return $this->mDbkeyform == ''; @@ -4028,7 +4051,7 @@ class Title { */ public function isSpecial( $name ) { if ( $this->getNamespace() == NS_SPECIAL ) { - list( $thisName, /* $subpage */ ) = SpecialPage::resolveAliasWithSubpage( $this->getDBkey() ); + list( $thisName, /* $subpage */ ) = SpecialPageFactory::resolveAlias( $this->getDBkey() ); if ( $name == $thisName ) { return true; } @@ -4044,9 +4067,9 @@ class Title { */ public function fixSpecialName() { if ( $this->getNamespace() == NS_SPECIAL ) { - $canonicalName = SpecialPage::resolveAlias( $this->mDbkeyform ); + list( $canonicalName, /*...*/ ) = SpecialPageFactory::resolveAlias( $this->mDbkeyform ); if ( $canonicalName ) { - $localName = SpecialPage::getLocalNameFor( $canonicalName ); + $localName = SpecialPageFactory::getLocalNameFor( $canonicalName ); if ( $localName != $this->mDbkeyform ) { return Title::makeTitle( NS_SPECIAL, $localName ); } @@ -4214,4 +4237,69 @@ class Title { } return $unprefixed; } + + /** + * Get the language in which the content of this page is written. + * Defaults to $wgContLang, but in certain cases it can be e.g. + * $wgLang (such as special pages, which are in the user language). + * + * @return object Language + */ + public function getPageLanguage() { + global $wgLang; + if ( $this->getNamespace() == NS_SPECIAL ) { + // special pages are in the user language + return $wgLang; + } elseif ( $this->isRedirect() ) { + // the arrow on a redirect page is aligned according to the user language + return $wgLang; + } elseif ( $this->isCssOrJsPage() ) { + // css/js should always be LTR and is, in fact, English + return wfGetLangObj( 'en' ); + } elseif ( $this->getNamespace() == NS_MEDIAWIKI ) { + // Parse mediawiki messages with correct target language + list( /* $unused */, $lang ) = MessageCache::singleton()->figureMessage( $this->getText() ); + return wfGetLangObj( $lang ); + } + global $wgContLang; + // If nothing special, it should be in the wiki content language + $pageLang = $wgContLang; + // Hook at the end because we don't want to override the above stuff + wfRunHooks( 'PageContentLanguage', array( $this, &$pageLang, $wgLang ) ); + return wfGetLangObj( $pageLang ); + } +} + +/** + * A BadTitle is generated in MediaWiki::parseTitle() if the title is invalid; the + * software uses this to display an error page. Internally it's basically a Title + * for an empty special page + */ +class BadTitle extends Title { + public function __construct(){ + $this->mTextform = ''; + $this->mUrlform = ''; + $this->mDbkeyform = ''; + $this->mNamespace = NS_SPECIAL; // Stops talk page link, etc, being shown + } + + public function exists(){ + return false; + } + + public function getPrefixedText(){ + return ''; + } + + public function getText(){ + return ''; + } + + public function getPrefixedURL(){ + return ''; + } + + public function getPrefixedDBKey(){ + return ''; + } }