* @file
*/
-/**
- * @todo: determine if it is really necessary to load this. Appears to be left over from pre-autoloader versions, and
- * is only really needed to provide access to constant UTF8_REPLACEMENT, which actually resides in UtfNormalDefines.php
- * and is loaded by UtfNormalUtil.php, which is loaded by UtfNormal.php.
- */
-if ( !class_exists( 'UtfNormal' ) ) {
- require_once( dirname( __FILE__ ) . '/normal/UtfNormal.php' );
-}
-
/**
* @deprecated This used to be a define, but was moved to
* Title::GAID_FOR_UPDATE in 1.17. This will probably be removed in 1.18
# Don't change the following default, NS_MAIN is hardcoded in several
# places. See bug 696.
var $mDefaultNamespace = NS_MAIN; // /< Namespace index when there is no namespace
- # Zero except in {{transclusion}} tags
+ # Zero except in {{transclusion}} tags
var $mWatched = null; // /< Is $wgUser watching this page? null if unfilled, accessed through userIsWatching()
var $mLength = -1; // /< The page length, 0 for special pages
var $mRedirect = null; // /< Is the article at this title a redirect?
return array();
}
$dbr = wfGetDB( DB_SLAVE );
-
+
$res = $dbr->select(
'page',
array(
*/
public static function newFromRedirectArray( $text ) {
global $wgMaxRedirects;
- // are redirects disabled?
- if ( $wgMaxRedirects < 1 ) {
- return null;
- }
$title = self::newFromRedirectInternal( $text );
if ( is_null( $title ) ) {
return null;
* @return Title
*/
protected static function newFromRedirectInternal( $text ) {
+ global $wgMaxRedirects;
+ if ( $wgMaxRedirects < 1 ) {
+ //redirects are disabled, so quit early
+ return null;
+ }
$redir = MagicWord::get( 'redirect' );
$text = trim( $text );
if ( $redir->matchStartAndRemove( $text ) ) {
return MWNamespace::getCanonicalName( $this->mNamespace );
}
}
+
+ if ( $wgContLang->needsGenderDistinction() &&
+ MWNamespace::hasGenderDistinction( $this->mNamespace ) ) {
+ $gender = GenderCache::singleton()->getGenderOf( $this->getText(), __METHOD__ );
+ return $wgContLang->getGenderNsText( $this->mNamespace, $gender );
+ }
+
return $wgContLang->getNsText( $this->mNamespace );
}
* @return String the URL
*/
public function getInternalURL( $query = '', $variant = false ) {
- global $wgInternalServer;
- $url = $wgInternalServer . $this->getLocalURL( $query, $variant );
+ global $wgInternalServer, $wgServer;
+ $server = $wgInternalServer !== false ? $wgInternalServer : $wgServer;
+ $url = $server . $this->getLocalURL( $query, $variant );
wfRunHooks( 'GetInternalURL', array( &$this, &$url, $query ) );
return $url;
}
/**
* Check restrictions on cascading pages.
- *
+ *
* @param $action String the action to check
* @param $user User to check
* @param $errors Array list of current errors
$errors[] = array( 'confirmedittext' );
}
- // Edit blocks should not affect reading. Account creation blocks handled at userlogin.
- if ( $action != 'read' && $action != 'createaccount' && $user->isBlockedFrom( $this ) ) {
+ 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 ) ){
+ // 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 ) {
$block = $user->mBlock;
// This is from OutputPage::blockedPage
}
$link = '[[' . $wgContLang->getNsText( NS_USER ) . ":{$name}|{$name}]]";
- $blockid = $block->mId;
+ $blockid = $block->getId();
$blockExpiry = $user->mBlock->mExpiry;
$blockTimestamp = $wgLang->timeanddate( wfTimestamp( TS_MW, $user->mBlock->mTimestamp ), true );
if ( $blockExpiry == 'infinity' ) {
- // Entry in database (table ipblocks) is 'infinity' but 'ipboptions' uses 'infinite' or 'indefinite'
- $scBlockExpiryOptions = wfMsg( 'ipboptions' );
-
- foreach ( explode( ',', $scBlockExpiryOptions ) as $option ) {
- if ( !strpos( $option, ':' ) )
- continue;
-
- list( $show, $value ) = explode( ':', $option );
-
- if ( $value == 'infinite' || $value == 'indefinite' ) {
- $blockExpiry = $show;
- break;
- }
- }
+ $blockExpiry = wfMessage( 'infiniteblock' )->text();
} else {
$blockExpiry = $wgLang->timeanddate( wfTimestamp( TS_MW, $blockExpiry ), true );
}
- $intended = $user->mBlock->mAddress;
+ $intended = strval( $user->mBlock->getTarget() );
$errors[] = array( ( $block->mAuto ? 'autoblockedtext' : 'blockedtext' ), $link, $reason, $ip, $name,
$blockid, $blockExpiry, $intended, $blockTimestamp );
$dbw = wfGetDB( DB_MASTER );
- $encodedExpiry = Block::encodeExpiry( $expiry, $dbw );
+ $encodedExpiry = $dbw->encodeExpiry( $expiry );
$expiry_description = '';
- if ( $encodedExpiry != 'infinity' ) {
+ if ( $encodedExpiry != $dbw->getInfinity() ) {
$expiry_description = ' (' . wfMsgForContent( 'protect-expiring', $wgContLang->timeanddate( $expiry ),
$wgContLang->date( $expiry ) , $wgContLang->time( $expiry ) ) . ')';
} else {
'pt_namespace' => $namespace,
'pt_title' => $title,
'pt_create_perm' => $create_perm,
- 'pt_timestamp' => Block::encodeExpiry( wfTimestampNow(), $dbw ),
+ 'pt_timestamp' => $dbw->encodeExpiry( wfTimestampNow() ),
'pt_expiry' => $encodedExpiry,
'pt_user' => $wgUser->getId(),
'pt_reason' => $reason,
* cache that we don't need to over-optimize by doing direct comparisons and
* acidentally creating new bugs where $title->equals( Title::newFromText() )
* ends up reporting something differently than $title->isMainPage();
- *
+ *
* @return Bool
*/
public function isMainPage() {
* Is this a *valid* .css or .js subpage of a user page?
*
* @return Bool
- * @deprecated @since 1.17
+ * @deprecated since 1.17
*/
public function isValidCssJsSubpage() {
return $this->isCssJsSubpage();
*/
public function userCanEditCssSubpage() {
global $wgUser;
- return ( ( $wgUser->isAllowed( 'editusercssjs' ) && $wgUser->isAllowed( 'editusercss' ) )
+ return ( ( $wgUser->isAllowedAll( 'editusercssjs', 'editusercss' ) )
|| preg_match( '/^' . preg_quote( $wgUser->getName(), '/' ) . '\//', $this->mTextform ) );
}
*/
public function userCanEditJsSubpage() {
global $wgUser;
- return ( ( $wgUser->isAllowed( 'editusercssjs' ) && $wgUser->isAllowed( 'edituserjs' ) )
- || preg_match( '/^' . preg_quote( $wgUser->getName(), '/' ) . '\//', $this->mTextform ) );
+ return ( ( $wgUser->isAllowedAll( 'editusercssjs', 'edituserjs' ) )
+ || preg_match( '/^' . preg_quote( $wgUser->getName(), '/' ) . '\//', $this->mTextform ) );
}
/**
* contains a array of unique groups.
*/
public function getCascadeProtectionSources( $getPages = true ) {
+ global $wgContLang;
$pagerestrictions = array();
if ( isset( $this->mCascadeSources ) && $getPages ) {
$purgeExpired = false;
foreach ( $res as $row ) {
- $expiry = Block::decodeExpiry( $row->pr_expiry );
+ $expiry = $wgContLang->formatExpiry( $row->pr_expiry, TS_MW );
if ( $expiry > $now ) {
if ( $getPages ) {
$page_id = $row->pr_page;
* restrictions from page table (pre 1.10)
*/
public function loadRestrictionsFromRows( $rows, $oldFashionedRestrictions = null ) {
+ global $wgContLang;
$dbr = wfGetDB( DB_SLAVE );
$restrictionTypes = $this->getRestrictionTypes();
foreach ( $restrictionTypes as $type ) {
$this->mRestrictions[$type] = array();
- $this->mRestrictionsExpiry[$type] = Block::decodeExpiry( '' );
+ $this->mRestrictionsExpiry[$type] = $wgContLang->formatExpiry( '', TS_MW );
}
$this->mCascadeRestriction = false;
// This code should be refactored, now that it's being used more generally,
// But I don't really see any harm in leaving it in Block for now -werdna
- $expiry = Block::decodeExpiry( $row->pr_expiry );
+ $expiry = $wgContLang->formatExpiry( $row->pr_expiry, TS_MW );
// Only apply the restrictions if they haven't expired!
if ( !$expiry || $expiry > $now ) {
* restrictions from page table (pre 1.10)
*/
public function loadRestrictions( $oldFashionedRestrictions = null ) {
+ global $wgContLang;
if ( !$this->mRestrictionsLoaded ) {
if ( $this->exists() ) {
$dbr = wfGetDB( DB_SLAVE );
- $res = $dbr->select( 'page_restrictions', '*',
- array( 'pr_page' => $this->getArticleId() ), __METHOD__ );
+ $res = $dbr->select(
+ 'page_restrictions',
+ '*',
+ array( 'pr_page' => $this->getArticleId() ),
+ __METHOD__
+ );
$this->loadRestrictionsFromResultWrapper( $res, $oldFashionedRestrictions );
} else {
if ( $title_protection ) {
$now = wfTimestampNow();
- $expiry = Block::decodeExpiry( $title_protection['pt_expiry'] );
+ $expiry = $wgContLang->formatExpiry( $title_protection['pt_expiry'], TS_MW );
if ( !$expiry || $expiry > $now ) {
// Apply the restrictions
$this->mTitleProtection = false;
}
} else {
- $this->mRestrictionsExpiry['create'] = Block::decodeExpiry( '' );
+ $this->mRestrictionsExpiry['create'] = $wgContLang->formatExpiry( '', TS_MW );
}
$this->mRestrictionsLoaded = true;
}
if ( $this->mInterwiki != '' ) {
$p = $this->mInterwiki . ':';
}
+
if ( 0 != $this->mNamespace ) {
$p .= $this->getNsText() . ':';
}
global $wgContLang, $wgLocalInterwiki;
# Initialisation
- $rxTc = self::getTitleInvalidRegex();
-
$this->mInterwiki = $this->mFragment = '';
$this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN
# Redundant interwiki prefix to the local wiki
if ( $wgLocalInterwiki !== false
- && 0 == strcasecmp( $this->mInterwiki, $wgLocalInterwiki ) )
+ && 0 == strcasecmp( $this->mInterwiki, $wgLocalInterwiki ) )
{
if ( $dbkey == '' ) {
# Can't have an empty self-link
}
$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_"
}
# Reject illegal characters.
+ $rxTc = self::getTitleInvalidRegex();
if ( preg_match( $rxTc, $dbkey ) ) {
return false;
}
# reachable due to the way web browsers deal with 'relative' URLs.
# Also, they conflict with subpage syntax. Forbid them explicitly.
if ( strpos( $dbkey, '.' ) !== false &&
- ( $dbkey === '.' || $dbkey === '..' ||
- strpos( $dbkey, './' ) === 0 ||
- strpos( $dbkey, '../' ) === 0 ||
- strpos( $dbkey, '/./' ) !== false ||
- strpos( $dbkey, '/../' ) !== false ||
- substr( $dbkey, -2 ) == '/.' ||
- substr( $dbkey, -3 ) == '/..' ) )
+ ( $dbkey === '.' || $dbkey === '..' ||
+ strpos( $dbkey, './' ) === 0 ||
+ strpos( $dbkey, '../' ) === 0 ||
+ strpos( $dbkey, '/./' ) !== false ||
+ strpos( $dbkey, '/../' ) !== false ||
+ substr( $dbkey, -2 ) == '/.' ||
+ substr( $dbkey, -3 ) == '/..' ) )
{
return false;
}
}
if ( ( $this->getDBkey() == '' ) ||
( !$oldid ) ||
- ( $nt->getDBkey() == '' ) ) {
+ ( $nt->getDBkey() == '' ) ) {
$errors[] = array( 'badarticleerror' );
}
// Image-specific checks
if ( $this->getNamespace() == NS_FILE ) {
- if ( $nt->getNamespace() != NS_FILE ) {
- $errors[] = array( 'imagenocrossnamespace' );
- }
- $file = wfLocalFile( $this );
- if ( $file->exists() ) {
- if ( $nt->getText() != wfStripIllegalFilenameChars( $nt->getText() ) ) {
- $errors[] = array( 'imageinvalidfilename' );
- }
- if ( !File::checkExtensionCompatibility( $file, $nt->getDBkey() ) ) {
- $errors[] = array( 'imagetypemismatch' );
- }
- }
- $destfile = wfLocalFile( $nt );
- if ( !$wgUser->isAllowed( 'reupload-shared' ) && !$destfile->exists() && wfFindFile( $nt ) ) {
- $errors[] = array( 'file-exists-sharedrepo' );
- }
+ $errors = array_merge( $errors, $this->validateFileMoveOperation( $nt ) );
}
if ( $nt->getNamespace() == NS_FILE && $this->getNamespace() != NS_FILE ) {
return $errors;
}
+ /**
+ * Check if the requested move target is a valid file move target
+ * @param Title $nt Target title
+ * @return array List of errors
+ */
+ protected function validateFileMoveOperation( $nt ) {
+ global $wgUser;
+
+ $errors = array();
+
+ if ( $nt->getNamespace() != NS_FILE ) {
+ $errors[] = array( 'imagenocrossnamespace' );
+ }
+
+ $file = wfLocalFile( $this );
+ if ( $file->exists() ) {
+ if ( $nt->getText() != wfStripIllegalFilenameChars( $nt->getText() ) ) {
+ $errors[] = array( 'imageinvalidfilename' );
+ }
+ if ( !File::checkExtensionCompatibility( $file, $nt->getDBkey() ) ) {
+ $errors[] = array( 'imagetypemismatch' );
+ }
+ }
+
+ $destFile = wfLocalFile( $nt );
+ if ( !$wgUser->isAllowed( 'reupload-shared' ) && !$destFile->exists() && wfFindFile( $nt ) ) {
+ $errors[] = array( 'file-exists-sharedrepo' );
+ }
+
+ return $errors;
+ }
+
/**
* Move a title to a new location
*
}
}
- $pageid = $this->getArticleID();
+ $dbw->begin(); # If $file was a LocalFile, its transaction would have closed our own.
+ $pageid = $this->getArticleID( 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?
+ $dbw->rollback();
return $err;
}
// Refresh the sortkey for this row. Be careful to avoid resetting
// cl_timestamp, which may disturb time-based lists on some sites.
- $prefix = $dbw->selectField(
+ $prefixes = $dbw->select(
'categorylinks',
- 'cl_sortkey_prefix',
+ array( 'cl_sortkey_prefix', 'cl_to' ),
array( 'cl_from' => $pageid ),
__METHOD__
);
- $dbw->update( 'categorylinks',
- array(
- 'cl_sortkey' => Collation::singleton()->getSortKey(
- $nt->getCategorySortkey( $prefix ) ),
- 'cl_timestamp=cl_timestamp' ),
- array( 'cl_from' => $pageid ),
- __METHOD__ );
+ foreach ( $prefixes as $prefixRow ) {
+ $prefix = $prefixRow->cl_sortkey_prefix;
+ $catTo = $prefixRow->cl_to;
+ $dbw->update( 'categorylinks',
+ array(
+ 'cl_sortkey' => Collation::singleton()->getSortKey(
+ $nt->getCategorySortkey( $prefix ) ),
+ 'cl_timestamp=cl_timestamp' ),
+ array(
+ 'cl_from' => $pageid,
+ 'cl_to' => $catTo ),
+ __METHOD__
+ );
+ }
if ( $protected ) {
# Protect the redirect title as the title used to be...
$u = new SearchUpdate( $redirid, $this->getPrefixedDBkey(), '' );
$u->doUpdate();
+ $dbw->commit();
+
# Update site_stats
if ( $this->isContentPage() && !$nt->isContentPage() ) {
# No longer a content page
if ( $reason ) {
$comment .= wfMsgForContent( 'colon-separator' ) . $reason;
}
- # Truncate for whole multibyte characters. +5 bytes for ellipsis
- $comment = $wgContLang->truncate( $comment, 250 );
+ # Truncate for whole multibyte characters.
+ $comment = $wgContLang->truncate( $comment, 255 );
$oldid = $this->getArticleID();
$latest = $this->getLatestRevID();
+ $oldns = $this->getNamespace();
+ $olddbk = $this->getDBkey();
+
$dbw = wfGetDB( DB_MASTER );
if ( $moveOverRedirect ) {
__METHOD__ );
$redirectSuppressed = false;
} else {
+ // Get rid of old new page entries in Special:NewPages and RC.
+ // Needs to be before $this->resetArticleID( 0 ).
+ $dbw->delete( 'recentchanges', array(
+ 'rc_timestamp' => $dbw->timestamp( $this->getEarliestRevTime() ),
+ 'rc_namespace' => $oldns,
+ 'rc_title' => $olddbk,
+ 'rc_new' => 1
+ ),
+ __METHOD__
+ );
+
$this->resetArticleID( 0 );
$redirectSuppressed = true;
}
* @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__
);
}
* 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 );
}
/**
/**
* Callback for usort() to do title sorts by (namespace, title)
- *
+ *
+ * @param $a Title
+ * @param $b Title
+ *
* @return Integer: result of string comparison, or namespace comparison
*/
public static function compare( $a, $b ) {
}
// Check cache first
$uid = $user->getId();
- if ( isset( $this->mNotificationTimestamp[$uid] ) ) {
+ // avoid isset here, as it'll return false for null entries
+ if ( array_key_exists( $uid, $this->mNotificationTimestamp ) ) {
return $this->mNotificationTimestamp[$uid];
}
if ( !$uid || !$wgShowUpdatedMarker ) {
// Spec: http://www.sixapart.com/pronet/docs/trackback_spec
return "<!--
<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"
- xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
- xmlns:trackback=\"http://madskills.com/public/xml/rss/module/trackback/\">
+ xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
+ xmlns:trackback=\"http://madskills.com/public/xml/rss/module/trackback/\">
<rdf:Description
rdf:about=\"$url\"
dc:identifier=\"$url\"
* @return array applicable restriction types
*/
public function getRestrictionTypes() {
- global $wgRestrictionTypes;
-
- $types = $this->exists() ? $wgRestrictionTypes : array( 'create' );
+ if ( $this->getNamespace() == NS_SPECIAL ) {
+ return array();
+ }
+
+ $types = self::getFilteredRestrictionTypes( $this->exists() );
if ( $this->getNamespace() != NS_FILE ) {
+ # Remove the upload restriction for non-file titles
$types = array_diff( $types, array( 'upload' ) );
}
-
+
wfRunHooks( 'TitleGetRestrictionTypes', array( $this, &$types ) );
-
+
+ wfDebug( __METHOD__ . ': applicable restriction types for ' .
+ $this->getPrefixedText() . ' are ' . implode( ',', $types ) . "\n" );
+
+ return $types;
+ }
+ /**
+ * Get a filtered list of all restriction types supported by this wiki.
+ * @param bool $exists True to get all restriction types that apply to
+ * titles that do exist, False for all restriction types that apply to
+ * titles that do not exist
+ * @return array
+ */
+ public static function getFilteredRestrictionTypes( $exists = true ) {
+ global $wgRestrictionTypes;
+ $types = $wgRestrictionTypes;
+ if ( $exists ) {
+ # Remove the create restriction for existing titles
+ $types = array_diff( $types, array( 'create' ) );
+ } else {
+ # Only the create and upload restrictions apply to non-existing titles
+ $types = array_intersect( $types, array( 'create', 'upload' ) );
+ }
return $types;
}
return $unprefixed;
}
}
+
+/**
+ * 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 '';
+ }
+}