2004-02-18 02:15:00 +00:00
|
|
|
<?php
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2005-04-12 02:07:16 +00:00
|
|
|
* See title.txt
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
* @file
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2007-04-05 02:30:29 +00:00
|
|
|
if ( !class_exists( 'UtfNormal' ) ) {
|
|
|
|
|
require_once( dirname(__FILE__) . '/normal/UtfNormal.php' );
|
|
|
|
|
}
|
2006-06-01 08:12:49 +00:00
|
|
|
|
2004-08-20 14:59:49 +00:00
|
|
|
define ( 'GAID_FOR_UPDATE', 1 );
|
|
|
|
|
|
2008-07-27 18:09:22 +00:00
|
|
|
/**
|
|
|
|
|
* Title::newFromText maintains a cache to avoid expensive re-normalization of
|
|
|
|
|
* commonly used titles. On a batch operation this can become a memory leak
|
|
|
|
|
* if not bounded. After hitting this many titles reset the cache.
|
|
|
|
|
*/
|
2005-01-15 07:08:37 +00:00
|
|
|
define( 'MW_TITLECACHE_MAX', 1000 );
|
|
|
|
|
|
2008-07-27 18:09:22 +00:00
|
|
|
/**
|
|
|
|
|
* Constants for pr_cascade bitfield
|
|
|
|
|
*/
|
2007-01-11 00:31:04 +00:00
|
|
|
define( 'CASCADE', 1 );
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Title class
|
|
|
|
|
* - Represents a title, which may contain an interwiki designation or namespace
|
2005-07-01 10:44:48 +00:00
|
|
|
* - Can fetch various kinds of data from the database, albeit inefficiently.
|
2004-09-02 23:28:24 +00:00
|
|
|
*
|
2004-09-03 23:00:01 +00:00
|
|
|
*/
|
2003-04-14 23:10:40 +00:00
|
|
|
class Title {
|
2006-06-08 13:08:22 +00:00
|
|
|
/**
|
|
|
|
|
* Static cache variables
|
|
|
|
|
*/
|
|
|
|
|
static private $titleCache=array();
|
|
|
|
|
static private $interwikiCache=array();
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* All member variables should be considered private
|
|
|
|
|
* Please use the accessor functions
|
|
|
|
|
*/
|
|
|
|
|
|
2007-05-08 09:09:46 +00:00
|
|
|
/**#@+
|
2006-06-10 18:28:50 +00:00
|
|
|
* @private
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2004-03-06 01:49:16 +00:00
|
|
|
|
2008-07-25 20:16:24 +00:00
|
|
|
var $mTextform = ''; # Text form (spaces not underscores) of the main part
|
|
|
|
|
var $mUrlform = ''; # URL-encoded form of the main part
|
|
|
|
|
var $mDbkeyform = ''; # Main part with underscores
|
|
|
|
|
var $mUserCaseDBKey; # DB key with the initial letter in the case specified by the user
|
|
|
|
|
var $mNamespace = NS_MAIN; # Namespace index, i.e. one of the NS_xxxx constants
|
|
|
|
|
var $mInterwiki = ''; # Interwiki prefix (or null string)
|
|
|
|
|
var $mFragment; # Title fragment (i.e. the bit after the #)
|
|
|
|
|
var $mArticleID = -1; # Article ID, fetched from the link cache on demand
|
|
|
|
|
var $mLatestID = false; # ID of most recent revision
|
|
|
|
|
var $mRestrictions = array(); # Array of groups allowed to edit this article
|
|
|
|
|
var $mOldRestrictions = false;
|
|
|
|
|
var $mCascadeRestriction; # Cascade restrictions on this page to included templates and images?
|
|
|
|
|
var $mRestrictionsExpiry; # When do the restrictions on this page expire?
|
|
|
|
|
var $mHasCascadingRestrictions; # Are cascading restrictions in effect on this page?
|
|
|
|
|
var $mCascadeRestrictionSources; # Where are the cascading restrictions coming from on this page?
|
|
|
|
|
var $mRestrictionsLoaded = false; # Boolean for initialisation on demand
|
|
|
|
|
var $mPrefixedText; # Text form including namespace/interwiki, initialised on demand
|
|
|
|
|
# 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
|
|
|
|
|
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?
|
2004-09-30 05:21:20 +00:00
|
|
|
/**#@-*/
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Constructor
|
2006-06-10 18:28:50 +00:00
|
|
|
* @private
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2008-07-25 20:16:24 +00:00
|
|
|
/* private */ function __construct() {}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Create a new Title from a prefixed DB key
|
|
|
|
|
* @param string $key The database key, which has underscores
|
|
|
|
|
* instead of spaces, possibly including namespace and
|
|
|
|
|
* interwiki prefixes
|
|
|
|
|
* @return Title the new object, or NULL on an error
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public static function newFromDBkey( $key ) {
|
2003-04-14 23:10:40 +00:00
|
|
|
$t = new Title();
|
|
|
|
|
$t->mDbkeyform = $key;
|
2003-10-01 10:26:26 +00:00
|
|
|
if( $t->secureAndSplit() )
|
|
|
|
|
return $t;
|
|
|
|
|
else
|
|
|
|
|
return NULL;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Create a new Title from text, such as what one would
|
|
|
|
|
* find in a link. Decodes any HTML entities in the text.
|
|
|
|
|
*
|
|
|
|
|
* @param string $text the link text; spaces, prefixes,
|
|
|
|
|
* and an initial ':' indicating the main namespace
|
|
|
|
|
* are accepted
|
|
|
|
|
* @param int $defaultNamespace the namespace to use if
|
|
|
|
|
* none is specified by a prefix
|
|
|
|
|
* @return Title the new object, or NULL on an error
|
|
|
|
|
*/
|
2006-07-10 15:08:51 +00:00
|
|
|
public static function newFromText( $text, $defaultNamespace = NS_MAIN ) {
|
2005-02-21 11:28:07 +00:00
|
|
|
if( is_object( $text ) ) {
|
2006-06-07 06:40:24 +00:00
|
|
|
throw new MWException( 'Title::newFromText given an object' );
|
2005-02-21 11:28:07 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-11-26 11:47:09 +00:00
|
|
|
/**
|
|
|
|
|
* Wiki pages often contain multiple links to the same page.
|
|
|
|
|
* Title normalization and parsing can become expensive on
|
|
|
|
|
* pages with many links, so we can save a little time by
|
|
|
|
|
* caching them.
|
|
|
|
|
*
|
|
|
|
|
* In theory these are value objects and won't get changed...
|
|
|
|
|
*/
|
2006-06-08 13:08:22 +00:00
|
|
|
if( $defaultNamespace == NS_MAIN && isset( Title::$titleCache[$text] ) ) {
|
|
|
|
|
return Title::$titleCache[$text];
|
2004-11-26 11:47:09 +00:00
|
|
|
}
|
2004-04-09 07:02:29 +00:00
|
|
|
|
2004-11-23 07:38:42 +00:00
|
|
|
/**
|
2005-05-31 11:54:36 +00:00
|
|
|
* Convert things like é ā or 〗 into real text...
|
2004-11-23 07:38:42 +00:00
|
|
|
*/
|
2005-05-31 11:54:36 +00:00
|
|
|
$filteredText = Sanitizer::decodeCharReferences( $text );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2006-07-11 14:11:23 +00:00
|
|
|
$t = new Title();
|
2004-11-26 11:47:09 +00:00
|
|
|
$t->mDbkeyform = str_replace( ' ', '_', $filteredText );
|
2004-04-09 07:02:29 +00:00
|
|
|
$t->mDefaultNamespace = $defaultNamespace;
|
|
|
|
|
|
2006-01-10 17:56:59 +00:00
|
|
|
static $cachedcount = 0 ;
|
2003-10-01 10:26:26 +00:00
|
|
|
if( $t->secureAndSplit() ) {
|
2005-01-28 05:10:05 +00:00
|
|
|
if( $defaultNamespace == NS_MAIN ) {
|
2006-01-10 17:56:59 +00:00
|
|
|
if( $cachedcount >= MW_TITLECACHE_MAX ) {
|
2005-01-15 07:08:37 +00:00
|
|
|
# Avoid memory leaks on mass operations...
|
2006-06-08 13:08:22 +00:00
|
|
|
Title::$titleCache = array();
|
2006-01-10 17:56:59 +00:00
|
|
|
$cachedcount=0;
|
2005-01-15 07:08:37 +00:00
|
|
|
}
|
2006-01-10 17:56:59 +00:00
|
|
|
$cachedcount++;
|
2006-06-08 13:08:22 +00:00
|
|
|
Title::$titleCache[$text] =& $t;
|
2004-11-26 11:47:09 +00:00
|
|
|
}
|
2003-10-01 10:26:26 +00:00
|
|
|
return $t;
|
|
|
|
|
} else {
|
2005-08-02 13:35:19 +00:00
|
|
|
$ret = NULL;
|
|
|
|
|
return $ret;
|
2003-10-01 10:26:26 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Create a new Title from URL-encoded text. Ensures that
|
|
|
|
|
* the given title's length does not exceed the maximum.
|
|
|
|
|
* @param string $url the title, as might be taken from a URL
|
|
|
|
|
* @return Title the new object, or NULL on an error
|
|
|
|
|
*/
|
2007-03-27 21:43:21 +00:00
|
|
|
public static function newFromURL( $url ) {
|
2006-01-05 05:27:16 +00:00
|
|
|
global $wgLegalTitleChars;
|
2003-04-14 23:10:40 +00:00
|
|
|
$t = new Title();
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2006-01-05 05:27:16 +00:00
|
|
|
# For compatibility with old buggy URLs. "+" is usually not valid in titles,
|
2004-05-30 06:43:26 +00:00
|
|
|
# but some URLs used it as a space replacement and they still come
|
|
|
|
|
# from some external search tools.
|
2006-01-05 05:27:16 +00:00
|
|
|
if ( strpos( $wgLegalTitleChars, '+' ) === false ) {
|
|
|
|
|
$url = str_replace( '+', ' ', $url );
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2006-01-05 05:27:16 +00:00
|
|
|
$t->mDbkeyform = str_replace( ' ', '_', $url );
|
2007-03-27 21:43:21 +00:00
|
|
|
if( $t->secureAndSplit() ) {
|
2003-10-01 10:26:26 +00:00
|
|
|
return $t;
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Create a new Title from an article ID
|
2005-05-04 00:33:08 +00:00
|
|
|
*
|
2004-12-19 08:00:50 +00:00
|
|
|
* @todo This is inefficiently implemented, the page row is requested
|
2005-05-04 00:33:08 +00:00
|
|
|
* but not used for anything else
|
|
|
|
|
*
|
2004-12-19 08:00:50 +00:00
|
|
|
* @param int $id the page_id corresponding to the Title to create
|
2008-05-11 20:24:15 +00:00
|
|
|
* @param int $flags, use GAID_FOR_UPDATE to use master
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return Title the new object, or NULL on an error
|
|
|
|
|
*/
|
2008-05-10 23:31:52 +00:00
|
|
|
public static function newFromID( $id, $flags = 0 ) {
|
2004-08-16 20:14:35 +00:00
|
|
|
$fname = 'Title::newFromID';
|
2008-05-11 20:22:49 +00:00
|
|
|
$db = ($flags & GAID_FOR_UPDATE) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
|
2008-05-10 23:31:52 +00:00
|
|
|
$row = $db->selectRow( 'page', array( 'page_namespace', 'page_title' ),
|
2004-12-19 08:00:50 +00:00
|
|
|
array( 'page_id' => $id ), $fname );
|
2004-01-17 05:49:39 +00:00
|
|
|
if ( $row !== false ) {
|
2004-12-19 08:00:50 +00:00
|
|
|
$title = Title::makeTitle( $row->page_namespace, $row->page_title );
|
2004-01-17 05:49:39 +00:00
|
|
|
} else {
|
|
|
|
|
$title = NULL;
|
|
|
|
|
}
|
|
|
|
|
return $title;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2006-06-18 12:42:16 +00:00
|
|
|
/**
|
2008-04-14 07:45:50 +00:00
|
|
|
* Make an array of titles from an array of IDs
|
2006-06-18 12:42:16 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public static function newFromIDs( $ids ) {
|
2008-01-17 12:33:35 +00:00
|
|
|
if ( !count( $ids ) ) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2006-06-18 12:42:16 +00:00
|
|
|
$res = $dbr->select( 'page', array( 'page_namespace', 'page_title' ),
|
|
|
|
|
'page_id IN (' . $dbr->makeList( $ids ) . ')', __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$titles = array();
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row ) {
|
2006-06-18 12:42:16 +00:00
|
|
|
$titles[] = Title::makeTitle( $row->page_namespace, $row->page_title );
|
|
|
|
|
}
|
|
|
|
|
return $titles;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-04-08 20:34:09 +00:00
|
|
|
/**
|
|
|
|
|
* Make a Title object from a DB row
|
|
|
|
|
* @param Row $row (needs at least page_title,page_namespace)
|
|
|
|
|
*/
|
|
|
|
|
public static function newFromRow( $row ) {
|
|
|
|
|
$t = self::makeTitle( $row->page_namespace, $row->page_title );
|
2008-04-09 05:21:00 +00:00
|
|
|
|
|
|
|
|
$t->mArticleID = isset($row->page_id) ? intval($row->page_id) : -1;
|
|
|
|
|
$t->mLength = isset($row->page_len) ? intval($row->page_len) : -1;
|
2008-04-09 16:32:14 +00:00
|
|
|
$t->mRedirect = isset($row->page_is_redirect) ? (bool)$row->page_is_redirect : NULL;
|
2008-04-09 05:21:00 +00:00
|
|
|
$t->mLatestID = isset($row->page_latest) ? $row->page_latest : false;
|
|
|
|
|
|
2008-04-08 20:34:09 +00:00
|
|
|
return $t;
|
|
|
|
|
}
|
2006-06-18 12:42:16 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Create a new Title from a namespace index and a DB key.
|
|
|
|
|
* It's assumed that $ns and $title are *valid*, for instance when
|
|
|
|
|
* they came directly from the database or a special page name.
|
2004-11-24 10:27:49 +00:00
|
|
|
* For convenience, spaces are converted to underscores so that
|
|
|
|
|
* eg user_text fields can be used directly.
|
|
|
|
|
*
|
2004-09-30 05:21:20 +00:00
|
|
|
* @param int $ns the namespace of the article
|
|
|
|
|
* @param string $title the unprefixed database key form
|
2008-07-24 16:25:19 +00:00
|
|
|
* @param string $fragment The link fragment (after the "#")
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return Title the new object
|
|
|
|
|
*/
|
2008-07-24 16:25:19 +00:00
|
|
|
public static function &makeTitle( $ns, $title, $fragment = '' ) {
|
2006-07-11 14:11:23 +00:00
|
|
|
$t = new Title();
|
2004-08-22 23:19:12 +00:00
|
|
|
$t->mInterwiki = '';
|
2008-07-24 16:25:19 +00:00
|
|
|
$t->mFragment = $fragment;
|
2007-05-19 01:38:25 +00:00
|
|
|
$t->mNamespace = $ns = intval( $ns );
|
2004-11-24 10:27:49 +00:00
|
|
|
$t->mDbkeyform = str_replace( ' ', '_', $title );
|
2004-09-11 09:35:24 +00:00
|
|
|
$t->mArticleID = ( $ns >= 0 ) ? -1 : 0;
|
2004-11-24 10:27:49 +00:00
|
|
|
$t->mUrlform = wfUrlencode( $t->mDbkeyform );
|
2004-08-22 23:19:12 +00:00
|
|
|
$t->mTextform = str_replace( '_', ' ', $title );
|
|
|
|
|
return $t;
|
2004-03-06 01:49:16 +00:00
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
|
|
|
|
|
/**
|
2006-07-17 22:15:10 +00:00
|
|
|
* Create a new Title from a namespace index and a DB key.
|
2004-09-30 05:21:20 +00:00
|
|
|
* The parameters will be checked for validity, which is a bit slower
|
|
|
|
|
* than makeTitle() but safer for user-provided data.
|
2005-05-04 00:33:08 +00:00
|
|
|
*
|
2004-09-30 05:21:20 +00:00
|
|
|
* @param int $ns the namespace of the article
|
|
|
|
|
* @param string $title the database key form
|
2008-07-24 16:25:19 +00:00
|
|
|
* @param string $fragment The link fragment (after the "#")
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return Title the new object, or NULL on an error
|
|
|
|
|
*/
|
2008-07-24 16:25:19 +00:00
|
|
|
public static function makeTitleSafe( $ns, $title, $fragment = '' ) {
|
2004-08-22 23:55:36 +00:00
|
|
|
$t = new Title();
|
2008-07-24 16:25:19 +00:00
|
|
|
$t->mDbkeyform = Title::makeName( $ns, $title, $fragment );
|
2004-08-22 23:55:36 +00:00
|
|
|
if( $t->secureAndSplit() ) {
|
|
|
|
|
return $t;
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Create a new Title for the Main Page
|
|
|
|
|
* @return Title the new object
|
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
public static function newMainPage() {
|
2008-02-13 06:13:03 +00:00
|
|
|
$title = Title::newFromText( wfMsgForContent( 'mainpage' ) );
|
|
|
|
|
// Don't give fatal errors if the message is broken
|
|
|
|
|
if ( !$title ) {
|
|
|
|
|
$title = Title::newFromText( 'Main Page' );
|
|
|
|
|
}
|
|
|
|
|
return $title;
|
2004-03-06 01:49:16 +00:00
|
|
|
}
|
2004-08-07 03:50:46 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2007-08-01 01:45:58 +00:00
|
|
|
* Extract a redirect destination from a string and return the
|
|
|
|
|
* Title, or null if the text doesn't contain a valid redirect
|
|
|
|
|
*
|
|
|
|
|
* @param string $text Text with possible redirect
|
|
|
|
|
* @return Title
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
public static function newFromRedirect( $text ) {
|
2007-08-01 01:45:58 +00:00
|
|
|
$redir = MagicWord::get( 'redirect' );
|
2008-03-13 14:08:47 +00:00
|
|
|
if( $redir->matchStart( trim($text) ) ) {
|
2007-08-01 01:45:58 +00:00
|
|
|
// Extract the first link and see if it's usable
|
2007-08-21 03:57:54 +00:00
|
|
|
$m = array();
|
2008-03-14 21:57:09 +00:00
|
|
|
if( preg_match( '!\[{2}(.*?)(?:\|.*?)?\]{2}!', $text, $m ) ) {
|
2007-08-01 01:45:58 +00:00
|
|
|
// Strip preceding colon used to "escape" categories, etc.
|
|
|
|
|
// and URL-decode links
|
2007-08-26 14:52:56 +00:00
|
|
|
if( strpos( $m[1], '%' ) !== false ) {
|
|
|
|
|
// Match behavior of inline link parsing here;
|
|
|
|
|
// don't interpret + as " " most of the time!
|
|
|
|
|
// It might be safe to just use rawurldecode instead, though.
|
|
|
|
|
$m[1] = urldecode( ltrim( $m[1], ':' ) );
|
|
|
|
|
}
|
2007-08-01 01:45:58 +00:00
|
|
|
$title = Title::newFromText( $m[1] );
|
|
|
|
|
// Redirects to Special:Userlogout are not permitted
|
|
|
|
|
if( $title instanceof Title && !$title->isSpecial( 'Userlogout' ) )
|
|
|
|
|
return $title;
|
2004-08-07 03:50:46 +00:00
|
|
|
}
|
|
|
|
|
}
|
2007-08-01 01:45:58 +00:00
|
|
|
return null;
|
2004-08-07 03:50:46 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-03-06 01:49:16 +00:00
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
|
# Static functions
|
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the prefixed DB key associated with an ID
|
2004-12-19 08:00:50 +00:00
|
|
|
* @param int $id the page_id of the article
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return Title an object representing the article, or NULL
|
|
|
|
|
* if no such article was found
|
|
|
|
|
*/
|
2008-07-27 18:09:22 +00:00
|
|
|
public static function nameOf( $id ) {
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2008-07-27 18:09:22 +00:00
|
|
|
$s = $dbr->selectRow( 'page', array( 'page_namespace','page_title' ), array( 'page_id' => $id ), __METHOD__ );
|
2004-07-10 03:09:26 +00:00
|
|
|
if ( $s === false ) { return NULL; }
|
2003-09-01 08:30:14 +00:00
|
|
|
|
2008-07-27 18:09:22 +00:00
|
|
|
$n = self::makeName( $s->page_namespace, $s->page_title );
|
2003-09-01 08:30:14 +00:00
|
|
|
return $n;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get a regex character class describing the legal characters in a link
|
|
|
|
|
* @return string the list of characters, not delimited
|
|
|
|
|
*/
|
2006-07-10 15:41:30 +00:00
|
|
|
public static function legalChars() {
|
2005-09-09 22:48:25 +00:00
|
|
|
global $wgLegalTitleChars;
|
|
|
|
|
return $wgLegalTitleChars;
|
2004-03-06 01:49:16 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get a string representation of a title suitable for
|
|
|
|
|
* including in a search index
|
|
|
|
|
*
|
|
|
|
|
* @param int $ns a namespace index
|
|
|
|
|
* @param string $title text-form main part
|
|
|
|
|
* @return string a stripped-down title string ready for the
|
|
|
|
|
* search index
|
|
|
|
|
*/
|
2007-01-09 19:56:23 +00:00
|
|
|
public static function indexTitle( $ns, $title ) {
|
2005-12-04 18:27:59 +00:00
|
|
|
global $wgContLang;
|
2004-03-06 01:49:16 +00:00
|
|
|
|
2004-08-16 20:14:35 +00:00
|
|
|
$lc = SearchEngine::legalSearchChars() . '&#;';
|
2004-09-24 16:45:31 +00:00
|
|
|
$t = $wgContLang->stripForSearch( $title );
|
2004-08-16 20:14:35 +00:00
|
|
|
$t = preg_replace( "/[^{$lc}]+/", ' ', $t );
|
2006-10-13 23:32:36 +00:00
|
|
|
$t = $wgContLang->lc( $t );
|
2004-03-06 01:49:16 +00:00
|
|
|
|
|
|
|
|
# Handle 's, s'
|
|
|
|
|
$t = preg_replace( "/([{$lc}]+)'s( |$)/", "\\1 \\1's ", $t );
|
|
|
|
|
$t = preg_replace( "/([{$lc}]+)s'( |$)/", "\\1s ", $t );
|
|
|
|
|
|
2004-08-16 20:14:35 +00:00
|
|
|
$t = preg_replace( "/\\s+/", ' ', $t );
|
2004-03-06 01:49:16 +00:00
|
|
|
|
2004-11-23 07:38:42 +00:00
|
|
|
if ( $ns == NS_IMAGE ) {
|
2004-03-06 01:49:16 +00:00
|
|
|
$t = preg_replace( "/ (png|gif|jpg|jpeg|ogg)$/", "", $t );
|
2003-05-16 13:36:37 +00:00
|
|
|
}
|
2004-03-06 01:49:16 +00:00
|
|
|
return trim( $t );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/*
|
|
|
|
|
* Make a prefixed DB key from a DB key and a namespace index
|
|
|
|
|
* @param int $ns numerical representation of the namespace
|
|
|
|
|
* @param string $title the DB key form the title
|
2008-07-24 16:25:19 +00:00
|
|
|
* @param string $fragment The link fragment (after the "#")
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return string the prefixed form of the title
|
|
|
|
|
*/
|
2008-07-24 16:25:19 +00:00
|
|
|
public static function makeName( $ns, $title, $fragment = '' ) {
|
2004-09-24 16:45:31 +00:00
|
|
|
global $wgContLang;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2008-07-24 16:25:19 +00:00
|
|
|
$namespace = $wgContLang->getNsText( $ns );
|
|
|
|
|
$name = $namespace == '' ? $title : "$namespace:$title";
|
|
|
|
|
if ( strval( $fragment ) != '' ) {
|
|
|
|
|
$name .= '#' . $fragment;
|
|
|
|
|
}
|
|
|
|
|
return $name;
|
2004-03-06 01:49:16 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Returns the URL associated with an interwiki prefix
|
|
|
|
|
* @param string $key the interwiki prefix (e.g. "MeatBall")
|
|
|
|
|
* @return the associated URL, containing "$1", which should be
|
|
|
|
|
* replaced by an article title
|
|
|
|
|
* @static (arguably)
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getInterwikiLink( $key ) {
|
2006-10-04 09:06:18 +00:00
|
|
|
global $wgMemc, $wgInterwikiExpiry;
|
2006-10-13 23:32:36 +00:00
|
|
|
global $wgInterwikiCache, $wgContLang;
|
2004-07-10 03:09:26 +00:00
|
|
|
$fname = 'Title::getInterwikiLink';
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2006-10-13 23:32:36 +00:00
|
|
|
$key = $wgContLang->lc( $key );
|
2005-09-03 01:13:35 +00:00
|
|
|
|
2006-10-04 09:06:18 +00:00
|
|
|
$k = wfMemcKey( 'interwiki', $key );
|
2006-06-08 13:08:22 +00:00
|
|
|
if( array_key_exists( $k, Title::$interwikiCache ) ) {
|
|
|
|
|
return Title::$interwikiCache[$k]->iw_url;
|
2004-11-23 07:38:42 +00:00
|
|
|
}
|
2003-11-24 19:41:16 +00:00
|
|
|
|
2006-01-21 16:23:45 +00:00
|
|
|
if ($wgInterwikiCache) {
|
2006-01-21 16:50:22 +00:00
|
|
|
return Title::getInterwikiCached( $key );
|
2006-01-21 16:23:45 +00:00
|
|
|
}
|
|
|
|
|
|
2005-07-01 10:44:48 +00:00
|
|
|
$s = $wgMemc->get( $k );
|
2004-05-04 12:37:29 +00:00
|
|
|
# Ignore old keys with no iw_local
|
2005-07-03 07:39:49 +00:00
|
|
|
if( $s && isset( $s->iw_local ) && isset($s->iw_trans)) {
|
2006-06-08 13:08:22 +00:00
|
|
|
Title::$interwikiCache[$k] = $s;
|
2004-01-12 06:21:09 +00:00
|
|
|
return $s->iw_url;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2004-11-23 07:38:42 +00:00
|
|
|
$res = $dbr->select( 'interwiki',
|
2005-07-03 07:15:53 +00:00
|
|
|
array( 'iw_url', 'iw_local', 'iw_trans' ),
|
2004-11-23 07:38:42 +00:00
|
|
|
array( 'iw_prefix' => $key ), $fname );
|
|
|
|
|
if( !$res ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-07-10 03:09:26 +00:00
|
|
|
$s = $dbr->fetchObject( $res );
|
2004-11-23 07:38:42 +00:00
|
|
|
if( !$s ) {
|
2004-07-10 03:09:26 +00:00
|
|
|
# Cache non-existence: create a blank object and save it to memcached
|
2003-08-21 11:20:38 +00:00
|
|
|
$s = (object)false;
|
2004-08-22 17:24:50 +00:00
|
|
|
$s->iw_url = '';
|
2004-07-10 03:09:26 +00:00
|
|
|
$s->iw_local = 0;
|
2005-07-03 07:15:53 +00:00
|
|
|
$s->iw_trans = 0;
|
2003-08-21 11:20:38 +00:00
|
|
|
}
|
2004-05-04 12:37:29 +00:00
|
|
|
$wgMemc->set( $k, $s, $wgInterwikiExpiry );
|
2006-06-08 13:08:22 +00:00
|
|
|
Title::$interwikiCache[$k] = $s;
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2003-08-21 11:20:38 +00:00
|
|
|
return $s->iw_url;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2006-01-21 16:23:45 +00:00
|
|
|
/**
|
|
|
|
|
* Fetch interwiki prefix data from local cache in constant database
|
|
|
|
|
*
|
|
|
|
|
* More logic is explained in DefaultSettings
|
|
|
|
|
*
|
|
|
|
|
* @return string URL of interwiki site
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public static function getInterwikiCached( $key ) {
|
2006-10-04 09:06:18 +00:00
|
|
|
global $wgInterwikiCache, $wgInterwikiScopes, $wgInterwikiFallbackSite;
|
2006-01-21 16:23:45 +00:00
|
|
|
static $db, $site;
|
2006-01-21 17:08:41 +00:00
|
|
|
|
2006-01-21 16:50:22 +00:00
|
|
|
if (!$db)
|
2006-01-21 16:23:45 +00:00
|
|
|
$db=dba_open($wgInterwikiCache,'r','cdb');
|
|
|
|
|
/* Resolve site name */
|
|
|
|
|
if ($wgInterwikiScopes>=3 and !$site) {
|
2006-10-04 09:06:18 +00:00
|
|
|
$site = dba_fetch('__sites:' . wfWikiID(), $db);
|
2006-01-21 16:23:45 +00:00
|
|
|
if ($site=="")
|
|
|
|
|
$site = $wgInterwikiFallbackSite;
|
|
|
|
|
}
|
2006-10-04 09:06:18 +00:00
|
|
|
$value = dba_fetch( wfMemcKey( $key ), $db);
|
2006-03-11 17:13:49 +00:00
|
|
|
if ($value=='' and $wgInterwikiScopes>=3) {
|
2006-01-21 16:23:45 +00:00
|
|
|
/* try site-level */
|
|
|
|
|
$value = dba_fetch("_{$site}:{$key}", $db);
|
|
|
|
|
}
|
2006-03-11 17:13:49 +00:00
|
|
|
if ($value=='' and $wgInterwikiScopes>=2) {
|
2006-01-21 16:23:45 +00:00
|
|
|
/* try globals */
|
2006-01-21 17:08:41 +00:00
|
|
|
$value = dba_fetch("__global:{$key}", $db);
|
2006-01-21 16:23:45 +00:00
|
|
|
}
|
|
|
|
|
if ($value=='undef')
|
|
|
|
|
$value='';
|
|
|
|
|
$s = (object)false;
|
|
|
|
|
$s->iw_url = '';
|
|
|
|
|
$s->iw_local = 0;
|
|
|
|
|
$s->iw_trans = 0;
|
|
|
|
|
if ($value!='') {
|
|
|
|
|
list($local,$url)=explode(' ',$value,2);
|
|
|
|
|
$s->iw_url=$url;
|
2006-01-21 17:08:41 +00:00
|
|
|
$s->iw_local=(int)$local;
|
2006-01-21 16:23:45 +00:00
|
|
|
}
|
2006-10-04 09:06:18 +00:00
|
|
|
Title::$interwikiCache[wfMemcKey( 'interwiki', $key )] = $s;
|
2006-01-21 16:23:45 +00:00
|
|
|
return $s->iw_url;
|
|
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Determine whether the object refers to a page within
|
2005-07-01 10:44:48 +00:00
|
|
|
* this project.
|
|
|
|
|
*
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return bool TRUE if this is an in-project interwiki link
|
|
|
|
|
* or a wikilink, FALSE otherwise
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isLocal() {
|
2004-08-16 20:14:35 +00:00
|
|
|
if ( $this->mInterwiki != '' ) {
|
2004-05-04 12:37:29 +00:00
|
|
|
# Make sure key is loaded into cache
|
|
|
|
|
$this->getInterwikiLink( $this->mInterwiki );
|
2006-10-04 09:06:18 +00:00
|
|
|
$k = wfMemcKey( 'interwiki', $this->mInterwiki );
|
2006-06-08 13:08:22 +00:00
|
|
|
return (bool)(Title::$interwikiCache[$k]->iw_local);
|
2004-05-04 12:37:29 +00:00
|
|
|
} else {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-03 07:15:53 +00:00
|
|
|
/**
|
|
|
|
|
* Determine whether the object refers to a page within
|
|
|
|
|
* this project and is transcludable.
|
|
|
|
|
*
|
|
|
|
|
* @return bool TRUE if this is transcludable
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isTrans() {
|
2006-02-01 04:41:53 +00:00
|
|
|
if ($this->mInterwiki == '')
|
2005-07-03 07:15:53 +00:00
|
|
|
return false;
|
|
|
|
|
# Make sure key is loaded into cache
|
|
|
|
|
$this->getInterwikiLink( $this->mInterwiki );
|
2006-10-04 09:06:18 +00:00
|
|
|
$k = wfMemcKey( 'interwiki', $this->mInterwiki );
|
2006-06-08 13:08:22 +00:00
|
|
|
return (bool)(Title::$interwikiCache[$k]->iw_trans);
|
2005-07-03 07:15:53 +00:00
|
|
|
}
|
|
|
|
|
|
2006-12-08 06:09:15 +00:00
|
|
|
/**
|
|
|
|
|
* Escape a text fragment, say from a link, for a URL
|
|
|
|
|
*/
|
|
|
|
|
static function escapeFragmentForURL( $fragment ) {
|
2006-12-09 15:32:16 +00:00
|
|
|
$fragment = str_replace( ' ', '_', $fragment );
|
2006-12-08 06:09:15 +00:00
|
|
|
$fragment = urlencode( Sanitizer::decodeCharReferences( $fragment ) );
|
|
|
|
|
$replaceArray = array(
|
|
|
|
|
'%3A' => ':',
|
|
|
|
|
'%' => '.'
|
|
|
|
|
);
|
|
|
|
|
return strtr( $fragment, $replaceArray );
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-06 01:49:16 +00:00
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
|
# Other stuff
|
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/** Simple accessors */
|
|
|
|
|
/**
|
|
|
|
|
* Get the text form (spaces not underscores) of the main part
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getText() { return $this->mTextform; }
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the URL-encoded form of the main part
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getPartialURL() { return $this->mUrlform; }
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the main part with underscores
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getDBkey() { return $this->mDbkeyform; }
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the namespace index, i.e. one of the NS_xxxx constants
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getNamespace() { return $this->mNamespace; }
|
2005-08-27 03:47:47 +00:00
|
|
|
/**
|
|
|
|
|
* Get the namespace text
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getNsText() {
|
2006-12-31 03:04:49 +00:00
|
|
|
global $wgContLang, $wgCanonicalNamespaceNames;
|
|
|
|
|
|
|
|
|
|
if ( '' != $this->mInterwiki ) {
|
|
|
|
|
// This probably shouldn't even happen. ohh man, oh yuck.
|
|
|
|
|
// But for interwiki transclusion it sometimes does.
|
|
|
|
|
// Shit. Shit shit shit.
|
|
|
|
|
//
|
|
|
|
|
// Use the canonical namespaces if possible to try to
|
|
|
|
|
// resolve a foreign namespace.
|
|
|
|
|
if( isset( $wgCanonicalNamespaceNames[$this->mNamespace] ) ) {
|
|
|
|
|
return $wgCanonicalNamespaceNames[$this->mNamespace];
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-08-27 03:56:58 +00:00
|
|
|
return $wgContLang->getNsText( $this->mNamespace );
|
|
|
|
|
}
|
2007-06-03 10:44:27 +00:00
|
|
|
/**
|
|
|
|
|
* Get the DB key with the initial letter case as specified by the user
|
|
|
|
|
*/
|
|
|
|
|
function getUserCaseDBKey() {
|
|
|
|
|
return $this->mUserCaseDBKey;
|
|
|
|
|
}
|
2005-08-27 03:56:58 +00:00
|
|
|
/**
|
|
|
|
|
* Get the namespace text of the subject (rather than talk) page
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getSubjectNsText() {
|
2005-08-27 03:56:58 +00:00
|
|
|
global $wgContLang;
|
2008-03-21 23:13:34 +00:00
|
|
|
return $wgContLang->getNsText( MWNamespace::getSubject( $this->mNamespace ) );
|
2005-08-27 03:47:47 +00:00
|
|
|
}
|
2005-08-27 03:56:58 +00:00
|
|
|
|
2006-04-12 15:38:17 +00:00
|
|
|
/**
|
|
|
|
|
* Get the namespace text of the talk page
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getTalkNsText() {
|
2006-04-12 15:38:17 +00:00
|
|
|
global $wgContLang;
|
2008-03-21 23:13:34 +00:00
|
|
|
return( $wgContLang->getNsText( MWNamespace::getTalk( $this->mNamespace ) ) );
|
2006-04-12 15:38:17 +00:00
|
|
|
}
|
2007-04-16 15:24:04 +00:00
|
|
|
|
2006-04-12 15:38:17 +00:00
|
|
|
/**
|
|
|
|
|
* Could this title have a corresponding talk page?
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function canTalk() {
|
2008-03-21 23:13:34 +00:00
|
|
|
return( MWNamespace::canTalk( $this->mNamespace ) );
|
2006-04-12 15:38:17 +00:00
|
|
|
}
|
2007-04-16 15:24:04 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the interwiki prefix (or null string)
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getInterwiki() { return $this->mInterwiki; }
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2006-12-08 06:09:15 +00:00
|
|
|
* Get the Title fragment (i.e. the bit after the #) in text form
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getFragment() { return $this->mFragment; }
|
2006-12-08 06:09:15 +00:00
|
|
|
/**
|
|
|
|
|
* Get the fragment in URL form, including the "#" character if there is one
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getFragmentForURL() {
|
2006-12-08 06:09:15 +00:00
|
|
|
if ( $this->mFragment == '' ) {
|
|
|
|
|
return '';
|
|
|
|
|
} else {
|
|
|
|
|
return '#' . Title::escapeFragmentForURL( $this->mFragment );
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the default namespace index, for when there is no namespace
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getDefaultNamespace() { return $this->mDefaultNamespace; }
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get title for search index
|
|
|
|
|
* @return string a stripped-down title string ready for the
|
|
|
|
|
* search index
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getIndexTitle() {
|
2003-04-14 23:10:40 +00:00
|
|
|
return Title::indexTitle( $this->mNamespace, $this->mTextform );
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the prefixed database key form
|
|
|
|
|
* @return string the prefixed title, with underscores and
|
|
|
|
|
* any interwiki and namespace prefixes
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getPrefixedDBkey() {
|
2003-04-14 23:10:40 +00:00
|
|
|
$s = $this->prefix( $this->mDbkeyform );
|
2004-08-16 20:14:35 +00:00
|
|
|
$s = str_replace( ' ', '_', $s );
|
2003-04-14 23:10:40 +00:00
|
|
|
return $s;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the prefixed title with spaces.
|
|
|
|
|
* This is the form usually used for display
|
|
|
|
|
* @return string the prefixed title, with spaces
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getPrefixedText() {
|
2005-10-09 20:51:34 +00:00
|
|
|
if ( empty( $this->mPrefixedText ) ) { // FIXME: bad usage of empty() ?
|
2003-10-22 23:56:49 +00:00
|
|
|
$s = $this->prefix( $this->mTextform );
|
2004-08-16 20:14:35 +00:00
|
|
|
$s = str_replace( '_', ' ', $s );
|
2003-10-22 23:56:49 +00:00
|
|
|
$this->mPrefixedText = $s;
|
|
|
|
|
}
|
2004-10-08 04:27:07 +00:00
|
|
|
return $this->mPrefixedText;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the prefixed title with spaces, plus any fragment
|
|
|
|
|
* (part beginning with '#')
|
|
|
|
|
* @return string the prefixed title, with spaces and
|
|
|
|
|
* the fragment, including '#'
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getFullText() {
|
2004-07-29 04:48:42 +00:00
|
|
|
$text = $this->getPrefixedText();
|
|
|
|
|
if( '' != $this->mFragment ) {
|
|
|
|
|
$text .= '#' . $this->mFragment;
|
|
|
|
|
}
|
2004-10-08 04:27:07 +00:00
|
|
|
return $text;
|
2004-07-29 04:48:42 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2006-05-14 03:51:36 +00:00
|
|
|
/**
|
|
|
|
|
* Get the base name, i.e. the leftmost parts before the /
|
|
|
|
|
* @return string Base name
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getBaseText() {
|
2008-05-23 22:00:14 +00:00
|
|
|
if( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
|
2006-05-14 03:51:36 +00:00
|
|
|
return $this->getText();
|
|
|
|
|
}
|
2008-05-23 22:00:14 +00:00
|
|
|
|
|
|
|
|
$parts = explode( '/', $this->getText() );
|
|
|
|
|
# Don't discard the real title if there's no subpage involved
|
|
|
|
|
if( count( $parts ) > 1 )
|
|
|
|
|
unset( $parts[ count( $parts ) - 1 ] );
|
|
|
|
|
return implode( '/', $parts );
|
2008-02-04 19:53:21 +00:00
|
|
|
}
|
2006-05-14 03:51:36 +00:00
|
|
|
|
2006-03-04 23:29:46 +00:00
|
|
|
/**
|
|
|
|
|
* Get the lowest-level subpage name, i.e. the rightmost part after /
|
|
|
|
|
* @return string Subpage name
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getSubpageText() {
|
2008-05-23 22:00:14 +00:00
|
|
|
if( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
|
2006-03-04 23:29:46 +00:00
|
|
|
return( $this->mTextform );
|
|
|
|
|
}
|
2008-05-23 22:00:14 +00:00
|
|
|
$parts = explode( '/', $this->mTextform );
|
|
|
|
|
return( $parts[ count( $parts ) - 1 ] );
|
2006-03-04 23:29:46 +00:00
|
|
|
}
|
2007-04-16 15:24:04 +00:00
|
|
|
|
2006-04-02 16:19:29 +00:00
|
|
|
/**
|
|
|
|
|
* Get a URL-encoded form of the subpage text
|
|
|
|
|
* @return string URL-encoded subpage name
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getSubpageUrlForm() {
|
2006-04-02 16:19:29 +00:00
|
|
|
$text = $this->getSubpageText();
|
|
|
|
|
$text = wfUrlencode( str_replace( ' ', '_', $text ) );
|
|
|
|
|
$text = str_replace( '%28', '(', str_replace( '%29', ')', $text ) ); # Clean up the URL; per below, this might not be safe
|
|
|
|
|
return( $text );
|
|
|
|
|
}
|
2006-03-04 23:29:46 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get a URL-encoded title (not an actual URL) including interwiki
|
|
|
|
|
* @return string the URL-encoded form
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getPrefixedURL() {
|
2003-04-14 23:10:40 +00:00
|
|
|
$s = $this->prefix( $this->mDbkeyform );
|
2004-08-16 20:14:35 +00:00
|
|
|
$s = str_replace( ' ', '_', $s );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-03-06 01:49:16 +00:00
|
|
|
$s = wfUrlencode ( $s ) ;
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2003-04-14 23:10:40 +00:00
|
|
|
# Cleaning up URL to make it look nice -- is this safe?
|
2004-08-16 20:14:35 +00:00
|
|
|
$s = str_replace( '%28', '(', $s );
|
|
|
|
|
$s = str_replace( '%29', ')', $s );
|
2004-03-06 01:49:16 +00:00
|
|
|
|
2003-04-14 23:10:40 +00:00
|
|
|
return $s;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get a real URL referring to this title, with interwiki link and
|
|
|
|
|
* fragment
|
|
|
|
|
*
|
|
|
|
|
* @param string $query an optional query string, not used
|
|
|
|
|
* for interwiki links
|
2006-10-12 10:34:49 +00:00
|
|
|
* @param string $variant language variant of url (for sr, zh..)
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return string the URL
|
|
|
|
|
*/
|
2008-05-14 18:28:52 +00:00
|
|
|
public function getFullURL( $query = '', $variant = false ) {
|
2006-01-12 10:06:54 +00:00
|
|
|
global $wgContLang, $wgServer, $wgRequest;
|
2008-05-09 23:52:04 +00:00
|
|
|
|
2004-08-16 20:14:35 +00:00
|
|
|
if ( '' == $this->mInterwiki ) {
|
2006-10-12 10:34:49 +00:00
|
|
|
$url = $this->getLocalUrl( $query, $variant );
|
2008-05-09 23:52:04 +00:00
|
|
|
|
2006-01-12 10:06:54 +00:00
|
|
|
// Ugly quick hack to avoid duplicate prefixes (bug 4571 etc)
|
|
|
|
|
// Correct fix would be to move the prepending elsewhere.
|
|
|
|
|
if ($wgRequest->getVal('action') != 'render') {
|
|
|
|
|
$url = $wgServer . $url;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
} else {
|
2004-07-29 04:48:42 +00:00
|
|
|
$baseUrl = $this->getInterwikiLink( $this->mInterwiki );
|
2008-05-09 23:52:04 +00:00
|
|
|
|
2006-12-31 03:04:49 +00:00
|
|
|
$namespace = wfUrlencode( $this->getNsText() );
|
2005-10-22 16:25:05 +00:00
|
|
|
if ( '' != $namespace ) {
|
|
|
|
|
# Can this actually happen? Interwikis shouldn't be parsed.
|
2006-12-31 03:04:49 +00:00
|
|
|
# Yes! It can in interwiki transclusion. But... it probably shouldn't.
|
2005-10-22 16:25:05 +00:00
|
|
|
$namespace .= ':';
|
2004-07-29 04:48:42 +00:00
|
|
|
}
|
2005-10-22 16:25:05 +00:00
|
|
|
$url = str_replace( '$1', $namespace . $this->mUrlform, $baseUrl );
|
2007-03-26 14:33:08 +00:00
|
|
|
$url = wfAppendQuery( $url, $query );
|
2005-03-27 16:05:33 +00:00
|
|
|
}
|
2006-05-01 16:06:14 +00:00
|
|
|
|
|
|
|
|
# Finally, add the fragment.
|
2006-12-08 06:09:15 +00:00
|
|
|
$url .= $this->getFragmentForURL();
|
2006-05-01 16:06:14 +00:00
|
|
|
|
2005-10-22 16:25:05 +00:00
|
|
|
wfRunHooks( 'GetFullURL', array( &$this, &$url, $query ) );
|
|
|
|
|
return $url;
|
2005-03-27 16:05:33 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2005-07-04 04:20:07 +00:00
|
|
|
* Get a URL with no fragment or server name. If this page is generated
|
|
|
|
|
* with action=render, $wgServer is prepended.
|
2004-09-30 05:21:20 +00:00
|
|
|
* @param string $query an optional query string; if not specified,
|
|
|
|
|
* $wgArticlePath will be used.
|
2006-10-12 10:34:49 +00:00
|
|
|
* @param string $variant language variant of url (for sr, zh..)
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return string the URL
|
|
|
|
|
*/
|
2008-05-14 18:28:52 +00:00
|
|
|
public function getLocalURL( $query = '', $variant = false ) {
|
2005-10-22 16:25:05 +00:00
|
|
|
global $wgArticlePath, $wgScript, $wgServer, $wgRequest;
|
2006-10-12 10:34:49 +00:00
|
|
|
global $wgVariantArticlePath, $wgContLang, $wgUser;
|
2008-05-14 18:28:52 +00:00
|
|
|
|
2006-10-12 10:34:49 +00:00
|
|
|
// internal links should point to same variant as current page (only anonymous users)
|
|
|
|
|
if($variant == false && $wgContLang->hasVariants() && !$wgUser->isLoggedIn()){
|
|
|
|
|
$pref = $wgContLang->getPreferredVariant(false);
|
|
|
|
|
if($pref != $wgContLang->getCode())
|
|
|
|
|
$variant = $pref;
|
|
|
|
|
}
|
2008-05-09 23:52:04 +00:00
|
|
|
|
2005-07-03 08:17:18 +00:00
|
|
|
if ( $this->isExternal() ) {
|
2005-10-22 16:25:05 +00:00
|
|
|
$url = $this->getFullURL();
|
2006-02-01 04:41:53 +00:00
|
|
|
if ( $query ) {
|
2006-03-11 17:13:49 +00:00
|
|
|
// This is currently only used for edit section links in the
|
|
|
|
|
// context of interwiki transclusion. In theory we should
|
2006-02-01 04:41:53 +00:00
|
|
|
// append the query to the end of any existing query string,
|
|
|
|
|
// but interwiki transclusion is already broken in that case.
|
|
|
|
|
$url .= "?$query";
|
|
|
|
|
}
|
2004-03-06 01:49:16 +00:00
|
|
|
} else {
|
2005-10-22 16:25:05 +00:00
|
|
|
$dbkey = wfUrlencode( $this->getPrefixedDBkey() );
|
|
|
|
|
if ( $query == '' ) {
|
2008-01-24 01:59:35 +00:00
|
|
|
if( $variant != false && $wgContLang->hasVariants() ) {
|
|
|
|
|
if( $wgVariantArticlePath == false ) {
|
2006-10-12 10:34:49 +00:00
|
|
|
$variantArticlePath = "$wgScript?title=$1&variant=$2"; // default
|
2007-04-16 15:24:04 +00:00
|
|
|
} else {
|
2006-10-12 10:34:49 +00:00
|
|
|
$variantArticlePath = $wgVariantArticlePath;
|
2007-04-16 15:24:04 +00:00
|
|
|
}
|
2006-10-12 20:45:49 +00:00
|
|
|
$url = str_replace( '$2', urlencode( $variant ), $variantArticlePath );
|
|
|
|
|
$url = str_replace( '$1', $dbkey, $url );
|
2008-01-24 01:59:35 +00:00
|
|
|
} else {
|
2006-10-12 10:34:49 +00:00
|
|
|
$url = str_replace( '$1', $dbkey, $wgArticlePath );
|
2007-04-16 15:24:04 +00:00
|
|
|
}
|
2005-10-22 16:25:05 +00:00
|
|
|
} else {
|
|
|
|
|
global $wgActionPaths;
|
|
|
|
|
$url = false;
|
2006-11-29 11:43:58 +00:00
|
|
|
$matches = array();
|
2005-10-22 16:25:05 +00:00
|
|
|
if( !empty( $wgActionPaths ) &&
|
2006-01-07 13:09:30 +00:00
|
|
|
preg_match( '/^(.*&|)action=([^&]*)(&(.*)|)$/', $query, $matches ) )
|
2005-10-22 16:25:05 +00:00
|
|
|
{
|
|
|
|
|
$action = urldecode( $matches[2] );
|
|
|
|
|
if( isset( $wgActionPaths[$action] ) ) {
|
|
|
|
|
$query = $matches[1];
|
|
|
|
|
if( isset( $matches[4] ) ) $query .= $matches[4];
|
|
|
|
|
$url = str_replace( '$1', $dbkey, $wgActionPaths[$action] );
|
2008-05-09 23:52:04 +00:00
|
|
|
if( $query != '' ) $url .= '?' . $query;
|
2005-10-22 16:25:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( $url === false ) {
|
|
|
|
|
if ( $query == '-' ) {
|
|
|
|
|
$query = '';
|
|
|
|
|
}
|
|
|
|
|
$url = "{$wgScript}?title={$dbkey}&{$query}";
|
2005-02-28 07:07:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-05-09 23:52:04 +00:00
|
|
|
|
2006-01-12 10:06:54 +00:00
|
|
|
// 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') {
|
2005-10-22 16:25:05 +00:00
|
|
|
$url = $wgServer . $url;
|
2004-03-06 01:49:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
2005-10-22 16:25:05 +00:00
|
|
|
wfRunHooks( 'GetLocalURL', array( &$this, &$url, $query ) );
|
|
|
|
|
return $url;
|
2004-03-06 01:49:16 +00:00
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get an HTML-escaped version of the URL form, suitable for
|
|
|
|
|
* using in a link, without a server name or fragment
|
|
|
|
|
* @param string $query an optional query string
|
|
|
|
|
* @return string the URL
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function escapeLocalURL( $query = '' ) {
|
2004-08-13 18:45:03 +00:00
|
|
|
return htmlspecialchars( $this->getLocalURL( $query ) );
|
2004-03-07 07:26:56 +00:00
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get an HTML-escaped version of the URL form, suitable for
|
|
|
|
|
* using in a link, including the server name and fragment
|
|
|
|
|
*
|
|
|
|
|
* @return string the URL
|
|
|
|
|
* @param string $query an optional query string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function escapeFullURL( $query = '' ) {
|
2004-08-13 18:45:03 +00:00
|
|
|
return htmlspecialchars( $this->getFullURL( $query ) );
|
2004-03-07 07:26:56 +00:00
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
|
2005-07-01 10:44:48 +00:00
|
|
|
/**
|
2004-09-30 05:21:20 +00:00
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* @param string $query an optional query string
|
2006-10-12 10:34:49 +00:00
|
|
|
* @param string $variant language variant of url (for sr, zh..)
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return string the URL
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getInternalURL( $query = '', $variant = false ) {
|
2004-03-07 07:26:56 +00:00
|
|
|
global $wgInternalServer;
|
2006-10-12 10:34:49 +00:00
|
|
|
$url = $wgInternalServer . $this->getLocalURL( $query, $variant );
|
2005-12-26 07:14:42 +00:00
|
|
|
wfRunHooks( 'GetInternalURL', array( &$this, &$url, $query ) );
|
|
|
|
|
return $url;
|
2004-03-07 07:26:56 +00:00
|
|
|
}
|
2004-03-06 01:49:16 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the edit URL for this Title
|
|
|
|
|
* @return string the URL, or a null string if this is an
|
|
|
|
|
* interwiki link
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getEditURL() {
|
2004-08-16 20:14:35 +00:00
|
|
|
if ( '' != $this->mInterwiki ) { return ''; }
|
|
|
|
|
$s = $this->getLocalURL( 'action=edit' );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
|
|
|
|
return $s;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the HTML-escaped displayable text form.
|
|
|
|
|
* Used for the title field in <a> tags.
|
|
|
|
|
* @return string the text, including any prefixes
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getEscapedText() {
|
2004-08-13 18:45:03 +00:00
|
|
|
return htmlspecialchars( $this->getPrefixedText() );
|
2003-10-22 23:56:49 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Is this Title interwiki?
|
|
|
|
|
* @return boolean
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isExternal() { return ( '' != $this->mInterwiki ); }
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2006-02-06 09:49:28 +00:00
|
|
|
/**
|
|
|
|
|
* Is this page "semi-protected" - the *only* protection is autoconfirm?
|
|
|
|
|
*
|
|
|
|
|
* @param string Action to check (default: edit)
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isSemiProtected( $action = 'edit' ) {
|
2006-12-27 07:47:10 +00:00
|
|
|
if( $this->exists() ) {
|
2006-12-30 19:49:30 +00:00
|
|
|
$restrictions = $this->getRestrictions( $action );
|
|
|
|
|
if( count( $restrictions ) > 0 ) {
|
|
|
|
|
foreach( $restrictions as $restriction ) {
|
|
|
|
|
if( strtolower( $restriction ) != 'autoconfirmed' )
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
# Not protected
|
|
|
|
|
return false;
|
2006-02-06 09:49:28 +00:00
|
|
|
}
|
2006-12-27 07:48:01 +00:00
|
|
|
return true;
|
2006-12-27 07:47:10 +00:00
|
|
|
} else {
|
|
|
|
|
# If it doesn't exist, it can't be protected
|
|
|
|
|
return false;
|
2006-02-06 09:49:28 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Does the title correspond to a protected article?
|
2004-11-24 12:55:48 +00:00
|
|
|
* @param string $what the action the page is protected from,
|
2007-11-15 14:47:40 +00:00
|
|
|
* by default checks move and edit
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return boolean
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isProtected( $action = '' ) {
|
2008-03-04 21:27:23 +00:00
|
|
|
global $wgRestrictionLevels, $wgRestrictionTypes;
|
2007-01-12 04:43:33 +00:00
|
|
|
|
2007-01-20 19:17:45 +00:00
|
|
|
# Special pages have inherent protection
|
|
|
|
|
if( $this->getNamespace() == NS_SPECIAL )
|
|
|
|
|
return true;
|
2007-01-12 04:43:33 +00:00
|
|
|
|
2008-03-04 21:27:23 +00:00
|
|
|
# Check regular protection levels
|
2008-04-14 07:45:50 +00:00
|
|
|
foreach( $wgRestrictionTypes as $type ){
|
2008-03-04 21:27:23 +00:00
|
|
|
if( $action == $type || $action == '' ) {
|
|
|
|
|
$r = $this->getRestrictions( $type );
|
|
|
|
|
foreach( $wgRestrictionLevels as $level ) {
|
|
|
|
|
if( in_array( $level, $r ) && $level != '' ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2006-01-18 03:24:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
}
|
2006-01-18 03:24:21 +00:00
|
|
|
|
2003-04-14 23:10:40 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2008-03-02 13:57:56 +00:00
|
|
|
* Is $wgUser watching this page?
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return boolean
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function userIsWatching() {
|
2003-04-14 23:10:40 +00:00
|
|
|
global $wgUser;
|
|
|
|
|
|
2005-05-14 17:55:04 +00:00
|
|
|
if ( is_null( $this->mWatched ) ) {
|
2006-11-27 22:55:12 +00:00
|
|
|
if ( NS_SPECIAL == $this->mNamespace || !$wgUser->isLoggedIn()) {
|
2005-05-14 17:55:04 +00:00
|
|
|
$this->mWatched = false;
|
|
|
|
|
} else {
|
|
|
|
|
$this->mWatched = $wgUser->isWatched( $this );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $this->mWatched;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2007-11-15 14:47:40 +00:00
|
|
|
/**
|
2007-01-13 03:22:20 +00:00
|
|
|
* Can $wgUser perform $action on this page?
|
|
|
|
|
* This skips potentially expensive cascading permission checks.
|
|
|
|
|
*
|
|
|
|
|
* Suitable for use for nonessential UI controls in common cases, but
|
|
|
|
|
* _not_ for functional access control.
|
|
|
|
|
*
|
|
|
|
|
* May provide false positives, but should never provide a false negative.
|
|
|
|
|
*
|
Revert r38196, r38204 -- "(bugs 6089, 13079) Show edit section links for transcluded template if, and only if the user can edit it, made Title::getUserPermissionsErrorsInternal() public so that it can be used in Parser and it can pass the User object from ParserOptions. " & co
Cause regression in 19 parser test cases, looks like messing up the tooltips for section edit links.
19 previously failing test(s) now PASSING! :)
* Bug 6563: Edit link generation for section shown by <includeonly> [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Bug 6563: Edit link generation for section suppressed by <includeonly> [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Basic section headings [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Section headings with TOC [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Handling of sections up to level 6 and beyond [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC regression (bug 9764) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC with wgMaxTocLevel=3 (bug 6204) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Resolving duplicate section names [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Resolving duplicate section names with differing case (bug 10721) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Template with sections, __NOTOC__ [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Link inside a section heading [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC regression (bug 12077) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Fuzz testing: Parser14 [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Fuzz testing: Parser14-table [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Inclusion of !userCanEdit() content [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Out-of-order TOC heading levels [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* -{}- tags within headlines (within html for parserConvert()) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Morwen/13: Unclosed link followed by heading [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* HHP2.2: Heuristics for headings in preprocessor parenthetical structures [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
2008-07-29 23:56:30 +00:00
|
|
|
* @param string $action action that permission needs to be checked for
|
2007-01-13 03:22:20 +00:00
|
|
|
* @return boolean
|
|
|
|
|
*/
|
Revert r38196, r38204 -- "(bugs 6089, 13079) Show edit section links for transcluded template if, and only if the user can edit it, made Title::getUserPermissionsErrorsInternal() public so that it can be used in Parser and it can pass the User object from ParserOptions. " & co
Cause regression in 19 parser test cases, looks like messing up the tooltips for section edit links.
19 previously failing test(s) now PASSING! :)
* Bug 6563: Edit link generation for section shown by <includeonly> [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Bug 6563: Edit link generation for section suppressed by <includeonly> [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Basic section headings [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Section headings with TOC [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Handling of sections up to level 6 and beyond [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC regression (bug 9764) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC with wgMaxTocLevel=3 (bug 6204) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Resolving duplicate section names [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Resolving duplicate section names with differing case (bug 10721) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Template with sections, __NOTOC__ [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Link inside a section heading [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC regression (bug 12077) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Fuzz testing: Parser14 [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Fuzz testing: Parser14-table [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Inclusion of !userCanEdit() content [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Out-of-order TOC heading levels [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* -{}- tags within headlines (within html for parserConvert()) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Morwen/13: Unclosed link followed by heading [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* HHP2.2: Heuristics for headings in preprocessor parenthetical structures [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
2008-07-29 23:56:30 +00:00
|
|
|
public function quickUserCan( $action ) {
|
|
|
|
|
return $this->userCan( $action, false );
|
2007-01-13 02:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
2007-07-07 04:18:44 +00:00
|
|
|
/**
|
|
|
|
|
* Determines if $wgUser is unable to edit this page because it has been protected
|
|
|
|
|
* by $wgNamespaceProtection.
|
2007-11-15 14:47:40 +00:00
|
|
|
*
|
2007-07-07 04:18:44 +00:00
|
|
|
* @return boolean
|
|
|
|
|
*/
|
2007-07-07 04:53:35 +00:00
|
|
|
public function isNamespaceProtected() {
|
2007-07-07 04:18:44 +00:00
|
|
|
global $wgNamespaceProtection, $wgUser;
|
2007-07-07 04:53:35 +00:00
|
|
|
if( isset( $wgNamespaceProtection[ $this->mNamespace ] ) ) {
|
|
|
|
|
foreach( (array)$wgNamespaceProtection[ $this->mNamespace ] as $right ) {
|
|
|
|
|
if( $right != '' && !$wgUser->isAllowed( $right ) )
|
2007-07-07 04:18:44 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2007-08-03 09:27:28 +00:00
|
|
|
|
2007-11-15 14:47:40 +00:00
|
|
|
/**
|
2007-01-13 03:22:20 +00:00
|
|
|
* Can $wgUser perform $action on this page?
|
Revert r38196, r38204 -- "(bugs 6089, 13079) Show edit section links for transcluded template if, and only if the user can edit it, made Title::getUserPermissionsErrorsInternal() public so that it can be used in Parser and it can pass the User object from ParserOptions. " & co
Cause regression in 19 parser test cases, looks like messing up the tooltips for section edit links.
19 previously failing test(s) now PASSING! :)
* Bug 6563: Edit link generation for section shown by <includeonly> [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Bug 6563: Edit link generation for section suppressed by <includeonly> [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Basic section headings [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Section headings with TOC [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Handling of sections up to level 6 and beyond [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC regression (bug 9764) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC with wgMaxTocLevel=3 (bug 6204) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Resolving duplicate section names [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Resolving duplicate section names with differing case (bug 10721) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Template with sections, __NOTOC__ [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Link inside a section heading [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC regression (bug 12077) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Fuzz testing: Parser14 [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Fuzz testing: Parser14-table [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Inclusion of !userCanEdit() content [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Out-of-order TOC heading levels [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* -{}- tags within headlines (within html for parserConvert()) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Morwen/13: Unclosed link followed by heading [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* HHP2.2: Heuristics for headings in preprocessor parenthetical structures [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
2008-07-29 23:56:30 +00:00
|
|
|
* @param string $action action that permission needs to be checked for
|
|
|
|
|
* @param bool $doExpensiveQueries Set this to false to avoid doing unnecessary queries.
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return boolean
|
2004-11-24 12:55:48 +00:00
|
|
|
*/
|
Revert r38196, r38204 -- "(bugs 6089, 13079) Show edit section links for transcluded template if, and only if the user can edit it, made Title::getUserPermissionsErrorsInternal() public so that it can be used in Parser and it can pass the User object from ParserOptions. " & co
Cause regression in 19 parser test cases, looks like messing up the tooltips for section edit links.
19 previously failing test(s) now PASSING! :)
* Bug 6563: Edit link generation for section shown by <includeonly> [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Bug 6563: Edit link generation for section suppressed by <includeonly> [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Basic section headings [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Section headings with TOC [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Handling of sections up to level 6 and beyond [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC regression (bug 9764) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC with wgMaxTocLevel=3 (bug 6204) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Resolving duplicate section names [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Resolving duplicate section names with differing case (bug 10721) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Template with sections, __NOTOC__ [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Link inside a section heading [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* TOC regression (bug 12077) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Fuzz testing: Parser14 [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Fuzz testing: Parser14-table [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Inclusion of !userCanEdit() content [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Out-of-order TOC heading levels [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* -{}- tags within headlines (within html for parserConvert()) [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* Morwen/13: Unclosed link followed by heading [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
* HHP2.2: Heuristics for headings in preprocessor parenthetical structures [Fixed between 29-Jul-2008 22:42:06, 1.14alpha (r38207) and 29-Jul-2008 23:54:51, 1.14alpha (r38207)]
2008-07-29 23:56:30 +00:00
|
|
|
public function userCan( $action, $doExpensiveQueries = true ) {
|
|
|
|
|
global $wgUser;
|
|
|
|
|
return ( $this->getUserPermissionsErrorsInternal( $action, $wgUser, $doExpensiveQueries ) === array());
|
2007-08-01 10:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
2007-11-15 14:47:40 +00:00
|
|
|
/**
|
2008-01-13 22:26:08 +00:00
|
|
|
* Can $user perform $action on this page?
|
|
|
|
|
*
|
|
|
|
|
* FIXME: This *does not* check throttles (User::pingLimiter()).
|
2008-01-13 22:23:36 +00:00
|
|
|
*
|
2007-08-01 10:19:26 +00:00
|
|
|
* @param string $action action that permission needs to be checked for
|
2008-03-02 21:51:58 +00:00
|
|
|
* @param User $user user to check
|
2007-08-01 10:19:26 +00:00
|
|
|
* @param bool $doExpensiveQueries Set this to false to avoid doing unnecessary queries.
|
2008-06-27 06:24:42 +00:00
|
|
|
* @param array $ignoreErrors Set this to a list of message keys whose corresponding errors may be ignored.
|
2007-08-01 10:19:26 +00:00
|
|
|
* @return array Array of arrays of the arguments to wfMsg to explain permissions problems.
|
2007-10-11 07:11:51 +00:00
|
|
|
*/
|
2008-06-27 06:24:42 +00:00
|
|
|
public function getUserPermissionsErrors( $action, $user, $doExpensiveQueries = true, $ignoreErrors = array() ) {
|
2008-06-05 14:05:35 +00:00
|
|
|
if( !StubObject::isRealObject( $user ) ) {
|
|
|
|
|
//Since StubObject is always used on globals, we can unstub $wgUser here and set $user = $wgUser
|
|
|
|
|
global $wgUser;
|
|
|
|
|
$wgUser->_unstub( '', 5 );
|
|
|
|
|
$user = $wgUser;
|
|
|
|
|
}
|
2007-08-01 10:19:26 +00:00
|
|
|
$errors = $this->getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries );
|
|
|
|
|
|
|
|
|
|
global $wgContLang;
|
|
|
|
|
global $wgLang;
|
2008-03-02 21:51:58 +00:00
|
|
|
global $wgEmailConfirmToEdit;
|
2007-08-03 09:27:28 +00:00
|
|
|
|
2008-05-29 17:50:09 +00:00
|
|
|
if ( $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount' ) {
|
2007-08-03 09:27:28 +00:00
|
|
|
$errors[] = array( 'confirmedittext' );
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-07 13:12:38 +00:00
|
|
|
if ( $user->isBlockedFrom( $this ) && $action != 'createaccount' ) {
|
2007-08-01 10:19:26 +00:00
|
|
|
$block = $user->mBlock;
|
|
|
|
|
|
|
|
|
|
// This is from OutputPage::blockedPage
|
|
|
|
|
// Copied at r23888 by werdna
|
|
|
|
|
|
|
|
|
|
$id = $user->blockedBy();
|
|
|
|
|
$reason = $user->blockedFor();
|
2007-11-15 14:42:20 +00:00
|
|
|
if( $reason == '' ) {
|
|
|
|
|
$reason = wfMsg( 'blockednoreason' );
|
|
|
|
|
}
|
2007-08-01 10:19:26 +00:00
|
|
|
$ip = wfGetIP();
|
|
|
|
|
|
|
|
|
|
if ( is_numeric( $id ) ) {
|
|
|
|
|
$name = User::whoIs( $id );
|
|
|
|
|
} else {
|
|
|
|
|
$name = $id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$link = '[[' . $wgContLang->getNsText( NS_USER ) . ":{$name}|{$name}]]";
|
|
|
|
|
$blockid = $block->mId;
|
|
|
|
|
$blockExpiry = $user->mBlock->mExpiry;
|
2007-09-10 03:01:09 +00:00
|
|
|
$blockTimestamp = $wgLang->timeanddate( wfTimestamp( TS_MW, $user->mBlock->mTimestamp ), true );
|
2007-08-01 10:19:26 +00:00
|
|
|
|
|
|
|
|
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, ':' ) == false )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
list ($show, $value) = explode( ":", $option );
|
|
|
|
|
|
|
|
|
|
if ( $value == 'infinite' || $value == 'indefinite' ) {
|
|
|
|
|
$blockExpiry = $show;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$blockExpiry = $wgLang->timeanddate( wfTimestamp( TS_MW, $blockExpiry ), true );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$intended = $user->mBlock->mAddress;
|
|
|
|
|
|
2008-04-28 17:30:07 +00:00
|
|
|
$errors[] = array( ($block->mAuto ? 'autoblockedtext' : 'blockedtext'), $link, $reason, $ip, $name,
|
|
|
|
|
$blockid, $blockExpiry, $intended, $blockTimestamp );
|
2007-08-01 10:19:26 +00:00
|
|
|
}
|
2008-06-27 06:24:42 +00:00
|
|
|
|
|
|
|
|
// Remove the errors being ignored.
|
|
|
|
|
|
|
|
|
|
foreach( $errors as $index => $error ) {
|
|
|
|
|
$error_key = is_array($error) ? $error[0] : $error;
|
|
|
|
|
|
|
|
|
|
if (in_array( $error_key, $ignoreErrors )) {
|
|
|
|
|
unset($errors[$index]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-08-01 10:19:26 +00:00
|
|
|
|
|
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-01-13 22:23:36 +00:00
|
|
|
* 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
|
|
|
|
|
* checks on wfReadOnly() and blocks)
|
|
|
|
|
*
|
2007-08-01 10:19:26 +00:00
|
|
|
* @param string $action action that permission needs to be checked for
|
2008-03-02 21:51:58 +00:00
|
|
|
* @param User $user user to check
|
2007-08-01 10:19:26 +00:00
|
|
|
* @param bool $doExpensiveQueries Set this to false to avoid doing unnecessary queries.
|
|
|
|
|
* @return array Array of arrays of the arguments to wfMsg to explain permissions problems.
|
|
|
|
|
*/
|
2008-07-29 20:35:11 +00:00
|
|
|
private function getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries = true ) {
|
2008-01-13 22:23:36 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2005-04-12 04:03:21 +00:00
|
|
|
|
2007-08-01 10:19:26 +00:00
|
|
|
$errors = array();
|
2006-02-05 18:47:40 +00:00
|
|
|
|
2007-10-10 09:56:47 +00:00
|
|
|
// Use getUserPermissionsErrors instead
|
2007-08-01 10:19:26 +00:00
|
|
|
if ( !wfRunHooks( 'userCan', array( &$this, &$user, $action, &$result ) ) ) {
|
2008-04-28 17:30:07 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2007-08-01 10:19:26 +00:00
|
|
|
return $result ? array() : array( array( 'badaccess-group0' ) );
|
2006-02-05 18:47:40 +00:00
|
|
|
}
|
|
|
|
|
|
2007-10-10 09:56:47 +00:00
|
|
|
if (!wfRunHooks( 'getUserPermissionsErrors', array( &$this, &$user, $action, &$result ) ) ) {
|
|
|
|
|
if ($result != array() && is_array($result) && !is_array($result[0]))
|
|
|
|
|
$errors[] = $result; # A single array representing an error
|
2007-10-10 14:54:46 +00:00
|
|
|
else if (is_array($result) && is_array($result[0]))
|
2007-10-10 09:56:47 +00:00
|
|
|
$errors = array_merge( $errors, $result ); # A nested array representing multiple errors
|
|
|
|
|
else if ($result != '' && $result != null && $result !== true && $result !== false)
|
|
|
|
|
$errors[] = array($result); # A string representing a message-id
|
|
|
|
|
else if ($result === false )
|
|
|
|
|
$errors[] = array('badaccess-group0'); # a generic "We don't want them to do that"
|
|
|
|
|
}
|
2008-01-14 13:50:55 +00:00
|
|
|
if ($doExpensiveQueries && !wfRunHooks( 'getUserPermissionsErrorsExpensive', array( &$this, &$user, $action, &$result ) ) ) {
|
|
|
|
|
if ($result != array() && is_array($result) && !is_array($result[0]))
|
|
|
|
|
$errors[] = $result; # A single array representing an error
|
|
|
|
|
else if (is_array($result) && is_array($result[0]))
|
|
|
|
|
$errors = array_merge( $errors, $result ); # A nested array representing multiple errors
|
|
|
|
|
else if ($result != '' && $result != null && $result !== true && $result !== false)
|
|
|
|
|
$errors[] = array($result); # A string representing a message-id
|
|
|
|
|
else if ($result === false )
|
|
|
|
|
$errors[] = array('badaccess-group0'); # a generic "We don't want them to do that"
|
|
|
|
|
}
|
2008-05-23 10:34:11 +00:00
|
|
|
|
|
|
|
|
$specialOKActions = array( 'createaccount', 'execute' );
|
|
|
|
|
if( NS_SPECIAL == $this->mNamespace && !in_array( $action, $specialOKActions) ) {
|
2007-08-01 10:19:26 +00:00
|
|
|
$errors[] = array('ns-specialprotected');
|
2004-10-27 07:37:35 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-07-07 04:18:44 +00:00
|
|
|
if ( $this->isNamespaceProtected() ) {
|
2007-08-16 07:05:38 +00:00
|
|
|
$ns = $this->getNamespace() == NS_MAIN
|
|
|
|
|
? wfMsg( 'nstab-main' )
|
|
|
|
|
: $this->getNsText();
|
2008-04-14 07:45:50 +00:00
|
|
|
$errors[] = (NS_MEDIAWIKI == $this->mNamespace
|
|
|
|
|
? array('protectedinterface')
|
2007-08-16 07:05:38 +00:00
|
|
|
: array( 'namespaceprotected', $ns ) );
|
2004-10-27 07:37:35 +00:00
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2004-10-27 07:37:35 +00:00
|
|
|
if( $this->mDbkeyform == '_' ) {
|
|
|
|
|
# FIXME: Is this necessary? Shouldn't be allowed anyway...
|
2007-08-01 10:19:26 +00:00
|
|
|
$errors[] = array('badaccess-group0');
|
2004-10-27 07:37:35 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-04-28 19:30:21 +00:00
|
|
|
# protect css/js subpages of user pages
|
|
|
|
|
# XXX: this might be better using restrictions
|
2004-05-10 13:15:28 +00:00
|
|
|
# XXX: Find a way to work around the php bug that prevents using $this->userCanEditCssJsSubpage() from working
|
2006-12-12 23:13:14 +00:00
|
|
|
if( $this->isCssJsSubpage()
|
2007-09-10 08:10:48 +00:00
|
|
|
&& !$user->isAllowed('editusercssjs')
|
2007-08-01 10:19:26 +00:00
|
|
|
&& !preg_match('/^'.preg_quote($user->getName(), '/').'\//', $this->mTextform) ) {
|
|
|
|
|
$errors[] = array('customcssjsprotected');
|
2004-10-27 07:37:35 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-03-14 22:57:32 +00:00
|
|
|
if ( $doExpensiveQueries && !$this->isCssJsSubpage() ) {
|
2007-01-10 23:32:38 +00:00
|
|
|
# We /could/ use the protection level on the source page, but it's fairly ugly
|
|
|
|
|
# as we have to establish a precedence hierarchy for pages included by multiple
|
|
|
|
|
# cascade-protected pages. So just restrict it to people with 'protect' permission,
|
|
|
|
|
# as they could remove the protection anyway.
|
2007-03-14 22:57:32 +00:00
|
|
|
list( $cascadingSources, $restrictions ) = $this->getCascadeProtectionSources();
|
|
|
|
|
# Cascading protection depends on more than this page...
|
|
|
|
|
# Several cascading protected pages may include this page...
|
|
|
|
|
# Check each cascading level
|
|
|
|
|
# This is only for protection restrictions, not for all actions
|
|
|
|
|
if( $cascadingSources > 0 && isset($restrictions[$action]) ) {
|
|
|
|
|
foreach( $restrictions[$action] as $right ) {
|
|
|
|
|
$right = ( $right == 'sysop' ) ? 'protect' : $right;
|
2007-08-01 10:19:26 +00:00
|
|
|
if( '' != $right && !$user->isAllowed( $right ) ) {
|
|
|
|
|
$pages = '';
|
2007-08-21 03:57:54 +00:00
|
|
|
foreach( $cascadingSources as $page )
|
2007-08-01 10:19:26 +00:00
|
|
|
$pages .= '* [[:' . $page->getPrefixedText() . "]]\n";
|
2007-08-09 22:13:44 +00:00
|
|
|
$errors[] = array( 'cascadeprotected', count( $cascadingSources ), $pages );
|
2007-03-14 22:57:32 +00:00
|
|
|
}
|
|
|
|
|
}
|
2007-01-10 23:32:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2004-11-24 12:55:48 +00:00
|
|
|
foreach( $this->getRestrictions($action) as $right ) {
|
2005-05-14 05:38:01 +00:00
|
|
|
// Backwards compatibility, rewrite sysop -> protect
|
|
|
|
|
if ( $right == 'sysop' ) {
|
2008-03-02 19:26:59 +00:00
|
|
|
$right = 'protect';
|
2005-05-14 05:38:01 +00:00
|
|
|
}
|
2007-08-01 10:19:26 +00:00
|
|
|
if( '' != $right && !$user->isAllowed( $right ) ) {
|
2008-06-21 03:17:35 +00:00
|
|
|
//Users with 'editprotected' permission can edit protected pages
|
|
|
|
|
if( $action=='edit' && $user->isAllowed( 'editprotected' ) ) {
|
|
|
|
|
//Users with 'editprotected' permission cannot edit protected pages
|
|
|
|
|
//with cascading option turned on.
|
|
|
|
|
if($this->mCascadeRestriction) {
|
|
|
|
|
$errors[] = array( 'protectedpagetext', $right );
|
|
|
|
|
} else {
|
|
|
|
|
//Nothing, user can edit!
|
|
|
|
|
}
|
2008-03-19 11:23:03 +00:00
|
|
|
} else {
|
|
|
|
|
$errors[] = array( 'protectedpagetext', $right );
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2008-01-02 01:13:41 +00:00
|
|
|
if ($action == 'protect') {
|
2007-12-01 09:08:43 +00:00
|
|
|
if ($this->getUserPermissionsErrors('edit', $user) != array()) {
|
|
|
|
|
$errors[] = array( 'protect-cantedit' ); // If they can't edit, they shouldn't protect.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-14 07:45:50 +00:00
|
|
|
if ($action == 'create') {
|
2007-12-11 09:51:56 +00:00
|
|
|
$title_protection = $this->getTitleProtection();
|
|
|
|
|
|
|
|
|
|
if (is_array($title_protection)) {
|
|
|
|
|
extract($title_protection);
|
|
|
|
|
|
|
|
|
|
if ($pt_create_perm == 'sysop')
|
|
|
|
|
$pt_create_perm = 'protect';
|
|
|
|
|
|
|
|
|
|
if ($pt_create_perm == '' || !$user->isAllowed($pt_create_perm)) {
|
2007-12-12 19:47:05 +00:00
|
|
|
$errors[] = array ( 'titleprotected', User::whoIs($pt_user), $pt_reason );
|
2007-12-11 09:51:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-01 10:19:26 +00:00
|
|
|
if( ( $this->isTalkPage() && !$user->isAllowed( 'createtalk' ) ) ||
|
|
|
|
|
( !$this->isTalkPage() && !$user->isAllowed( 'createpage' ) ) ) {
|
|
|
|
|
$errors[] = $user->isAnon() ? array ('nocreatetext') : array ('nocreate-loggedin');
|
2005-12-05 05:37:10 +00:00
|
|
|
}
|
2007-08-31 21:33:44 +00:00
|
|
|
} elseif( $action == 'move' && !( $this->isMovable() && $user->isAllowed( 'move' ) ) ) {
|
2007-08-01 10:19:26 +00:00
|
|
|
$errors[] = $user->isAnon() ? array ( 'movenologintext' ) : array ('movenotallowed');
|
2008-01-11 20:51:53 +00:00
|
|
|
} elseif ( !$user->isAllowed( $action ) ) {
|
2007-08-01 10:19:26 +00:00
|
|
|
$return = null;
|
2007-12-01 09:08:43 +00:00
|
|
|
$groups = array();
|
2007-08-01 10:19:26 +00:00
|
|
|
global $wgGroupPermissions;
|
2008-01-02 01:13:41 +00:00
|
|
|
foreach( $wgGroupPermissions as $key => $value ) {
|
|
|
|
|
if( isset( $value[$action] ) && $value[$action] == true ) {
|
|
|
|
|
$groupName = User::getGroupName( $key );
|
|
|
|
|
$groupPage = User::getGroupPage( $key );
|
|
|
|
|
if( $groupPage ) {
|
|
|
|
|
$groups[] = '[['.$groupPage->getPrefixedText().'|'.$groupName.']]';
|
|
|
|
|
} else {
|
|
|
|
|
$groups[] = $groupName;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$n = count( $groups );
|
|
|
|
|
$groups = implode( ', ', $groups );
|
|
|
|
|
switch( $n ) {
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
case 2:
|
|
|
|
|
$return = array( "badaccess-group$n", $groups );
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
$return = array( 'badaccess-groups', $groups );
|
|
|
|
|
}
|
2007-08-01 10:19:26 +00:00
|
|
|
$errors[] = $return;
|
2007-07-11 08:43:21 +00:00
|
|
|
}
|
|
|
|
|
|
2008-01-13 22:23:36 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2007-08-01 10:19:26 +00:00
|
|
|
return $errors;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
|
2007-12-11 09:51:56 +00:00
|
|
|
/**
|
|
|
|
|
* Is this title subject to title protection?
|
2007-12-16 19:57:40 +00:00
|
|
|
* @return mixed An associative array representing any existent title
|
|
|
|
|
* protection, or false if there's none.
|
2007-12-11 09:51:56 +00:00
|
|
|
*/
|
2008-01-11 04:55:48 +00:00
|
|
|
private function getTitleProtection() {
|
2008-01-10 22:15:33 +00:00
|
|
|
// Can't protect pages in special namespaces
|
2008-01-11 05:06:10 +00:00
|
|
|
if ( $this->getNamespace() < 0 ) {
|
2008-01-10 22:15:33 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-11 04:41:11 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2008-04-14 07:45:50 +00:00
|
|
|
$res = $dbr->select( 'protected_titles', '*',
|
2008-01-14 09:13:04 +00:00
|
|
|
array ('pt_namespace' => $this->getNamespace(), 'pt_title' => $this->getDBkey()) );
|
2007-12-11 09:51:56 +00:00
|
|
|
|
|
|
|
|
if ($row = $dbr->fetchRow( $res )) {
|
|
|
|
|
return $row;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function updateTitleProtection( $create_perm, $reason, $expiry ) {
|
|
|
|
|
global $wgGroupPermissions,$wgUser,$wgContLang;
|
|
|
|
|
|
|
|
|
|
if ($create_perm == implode(',',$this->getRestrictions('create'))
|
|
|
|
|
&& $expiry == $this->mRestrictionsExpiry) {
|
|
|
|
|
// No change
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-14 09:13:04 +00:00
|
|
|
list ($namespace, $title) = array( $this->getNamespace(), $this->getDBkey() );
|
2007-12-11 09:51:56 +00:00
|
|
|
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
|
|
|
|
|
$encodedExpiry = Block::encodeExpiry($expiry, $dbw );
|
|
|
|
|
|
|
|
|
|
$expiry_description = '';
|
|
|
|
|
if ( $encodedExpiry != 'infinity' ) {
|
|
|
|
|
$expiry_description = ' (' . wfMsgForContent( 'protect-expiring', $wgContLang->timeanddate( $expiry ) ).')';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Update protection table
|
|
|
|
|
if ($create_perm != '' ) {
|
|
|
|
|
$dbw->replace( 'protected_titles', array(array('pt_namespace', 'pt_title')),
|
|
|
|
|
array( 'pt_namespace' => $namespace, 'pt_title' => $title
|
|
|
|
|
, 'pt_create_perm' => $create_perm
|
|
|
|
|
, 'pt_timestamp' => Block::encodeExpiry(wfTimestampNow(), $dbw)
|
|
|
|
|
, 'pt_expiry' => $encodedExpiry
|
2008-05-22 16:39:43 +00:00
|
|
|
, 'pt_user' => $wgUser->getId(), 'pt_reason' => $reason ), __METHOD__ );
|
2007-12-11 09:51:56 +00:00
|
|
|
} else {
|
|
|
|
|
$dbw->delete( 'protected_titles', array( 'pt_namespace' => $namespace,
|
|
|
|
|
'pt_title' => $title ), __METHOD__ );
|
|
|
|
|
}
|
|
|
|
|
# Update the protection log
|
|
|
|
|
$log = new LogPage( 'protect' );
|
|
|
|
|
|
|
|
|
|
if( $create_perm ) {
|
|
|
|
|
$log->addEntry( $this->mRestrictions['create'] ? 'modify' : 'protect', $this, trim( $reason . " [create=$create_perm] $expiry_description" ) );
|
|
|
|
|
} else {
|
|
|
|
|
$log->addEntry( 'unprotect', $this, $reason );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Remove any title protection (due to page existing
|
|
|
|
|
*/
|
|
|
|
|
public function deleteTitleProtection() {
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
|
2008-04-14 07:45:50 +00:00
|
|
|
$dbw->delete( 'protected_titles',
|
2008-01-14 09:13:04 +00:00
|
|
|
array ('pt_namespace' => $this->getNamespace(), 'pt_title' => $this->getDBkey()), __METHOD__ );
|
2007-12-11 09:51:56 +00:00
|
|
|
}
|
|
|
|
|
|
2004-11-24 12:55:48 +00:00
|
|
|
/**
|
|
|
|
|
* Can $wgUser edit this page?
|
|
|
|
|
* @return boolean
|
2007-01-13 03:22:20 +00:00
|
|
|
* @deprecated use userCan('edit')
|
2004-11-24 12:55:48 +00:00
|
|
|
*/
|
2007-01-13 03:22:20 +00:00
|
|
|
public function userCanEdit( $doExpensiveQueries = true ) {
|
2007-01-13 02:37:02 +00:00
|
|
|
return $this->userCan( 'edit', $doExpensiveQueries );
|
|
|
|
|
}
|
|
|
|
|
|
2006-07-01 10:54:31 +00:00
|
|
|
/**
|
|
|
|
|
* Can $wgUser create this page?
|
|
|
|
|
* @return boolean
|
2007-01-13 03:22:20 +00:00
|
|
|
* @deprecated use userCan('create')
|
2006-07-01 10:54:31 +00:00
|
|
|
*/
|
2007-01-13 03:22:20 +00:00
|
|
|
public function userCanCreate( $doExpensiveQueries = true ) {
|
2007-01-13 02:37:02 +00:00
|
|
|
return $this->userCan( 'create', $doExpensiveQueries );
|
2006-07-01 10:54:31 +00:00
|
|
|
}
|
|
|
|
|
|
2004-11-24 12:55:48 +00:00
|
|
|
/**
|
|
|
|
|
* Can $wgUser move this page?
|
|
|
|
|
* @return boolean
|
2007-01-13 03:22:20 +00:00
|
|
|
* @deprecated use userCan('move')
|
2005-07-01 10:44:48 +00:00
|
|
|
*/
|
2007-01-13 03:22:20 +00:00
|
|
|
public function userCanMove( $doExpensiveQueries = true ) {
|
2007-01-13 02:37:02 +00:00
|
|
|
return $this->userCan( 'move', $doExpensiveQueries );
|
2004-11-24 12:55:48 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 04:34:46 +00:00
|
|
|
/**
|
2005-04-25 13:09:29 +00:00
|
|
|
* Would anybody with sufficient privileges be able to move this page?
|
|
|
|
|
* Some pages just aren't movable.
|
2005-04-25 04:34:46 +00:00
|
|
|
*
|
|
|
|
|
* @return boolean
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isMovable() {
|
2008-03-21 23:13:34 +00:00
|
|
|
return MWNamespace::isMovable( $this->getNamespace() )
|
2005-04-25 09:25:06 +00:00
|
|
|
&& $this->getInterwiki() == '';
|
2005-04-25 04:34:46 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Can $wgUser read this page?
|
|
|
|
|
* @return boolean
|
2007-04-04 05:22:37 +00:00
|
|
|
* @todo fold these checks into userCan()
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-01-13 03:22:20 +00:00
|
|
|
public function userCanRead() {
|
2008-03-24 13:47:16 +00:00
|
|
|
global $wgUser, $wgGroupPermissions;
|
2008-03-04 21:27:23 +00:00
|
|
|
|
2006-04-05 09:20:41 +00:00
|
|
|
$result = null;
|
2006-04-05 09:16:28 +00:00
|
|
|
wfRunHooks( 'userCan', array( &$this, &$wgUser, 'read', &$result ) );
|
|
|
|
|
if ( $result !== null ) {
|
2006-02-05 18:47:40 +00:00
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-24 13:47:16 +00:00
|
|
|
# Shortcut for public wikis, allows skipping quite a bit of code
|
|
|
|
|
if ($wgGroupPermissions['*']['read'])
|
|
|
|
|
return true;
|
|
|
|
|
|
2007-06-28 22:34:36 +00:00
|
|
|
if( $wgUser->isAllowed( 'read' ) ) {
|
2004-10-24 19:14:48 +00:00
|
|
|
return true;
|
|
|
|
|
} else {
|
2004-10-27 07:37:35 +00:00
|
|
|
global $wgWhitelistRead;
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2008-04-14 07:45:50 +00:00
|
|
|
/**
|
2006-10-15 06:36:01 +00:00
|
|
|
* Always grant access to the login page.
|
|
|
|
|
* Even anons need to be able to log in.
|
|
|
|
|
*/
|
2006-12-23 06:45:30 +00:00
|
|
|
if( $this->isSpecial( 'Userlogin' ) || $this->isSpecial( 'Resetpass' ) ) {
|
2004-10-27 07:37:35 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2007-09-11 14:46:04 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Bail out if there isn't whitelist
|
|
|
|
|
*/
|
|
|
|
|
if( !is_array($wgWhitelistRead) ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-03-04 21:27:23 +00:00
|
|
|
|
2007-06-28 22:34:36 +00:00
|
|
|
/**
|
|
|
|
|
* Check for explicit whitelisting
|
|
|
|
|
*/
|
2004-10-27 07:37:35 +00:00
|
|
|
$name = $this->getPrefixedText();
|
2008-05-16 20:06:19 +00:00
|
|
|
$dbName = $this->getPrefixedDBKey();
|
|
|
|
|
// Check with and without underscores
|
|
|
|
|
if( in_array($name,$wgWhitelistRead,true) || in_array($dbName,$wgWhitelistRead,true) )
|
2004-10-27 07:37:35 +00:00
|
|
|
return true;
|
2008-03-04 21:27:23 +00:00
|
|
|
|
2007-06-28 22:34:36 +00:00
|
|
|
/**
|
|
|
|
|
* Old settings might have the title prefixed with
|
|
|
|
|
* a colon for main-namespace pages
|
|
|
|
|
*/
|
2007-09-11 14:46:04 +00:00
|
|
|
if( $this->getNamespace() == NS_MAIN ) {
|
2007-06-28 22:34:36 +00:00
|
|
|
if( in_array( ':' . $name, $wgWhitelistRead ) )
|
2004-10-27 07:37:35 +00:00
|
|
|
return true;
|
2004-10-24 19:14:48 +00:00
|
|
|
}
|
2008-03-04 21:27:23 +00:00
|
|
|
|
2007-06-28 22:34:36 +00:00
|
|
|
/**
|
|
|
|
|
* If it's a special page, ditch the subpage bit
|
|
|
|
|
* and check again
|
|
|
|
|
*/
|
|
|
|
|
if( $this->getNamespace() == NS_SPECIAL ) {
|
2008-01-14 09:13:04 +00:00
|
|
|
$name = $this->getDBkey();
|
2007-08-21 03:57:54 +00:00
|
|
|
list( $name, /* $subpage */) = SpecialPage::resolveAliasWithSubpage( $name );
|
2007-11-15 16:32:41 +00:00
|
|
|
if ( $name === false ) {
|
|
|
|
|
# Invalid special page, but we show standard login required message
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-28 22:34:36 +00:00
|
|
|
$pure = SpecialPage::getTitleFor( $name )->getPrefixedText();
|
|
|
|
|
if( in_array( $pure, $wgWhitelistRead, true ) )
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-11 09:47:41 +00:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-02-21 11:28:07 +00:00
|
|
|
/**
|
|
|
|
|
* Is this a talk page of some sort?
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isTalkPage() {
|
2008-03-21 23:13:34 +00:00
|
|
|
return MWNamespace::isTalk( $this->getNamespace() );
|
2005-02-21 11:28:07 +00:00
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
|
2006-12-12 19:14:29 +00:00
|
|
|
/**
|
|
|
|
|
* Is this a subpage?
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isSubpage() {
|
2008-05-23 22:00:14 +00:00
|
|
|
return MWNamespace::hasSubpages( $this->mNamespace )
|
2008-05-23 22:20:09 +00:00
|
|
|
? strpos( $this->getText(), '/' ) !== false
|
2008-05-23 22:00:14 +00:00
|
|
|
: false;
|
2006-12-12 19:14:29 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-05-23 01:11:17 +00:00
|
|
|
/**
|
|
|
|
|
* Does this have subpages? (Warning, usually requires an extra DB query.)
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function hasSubpages() {
|
2008-05-23 22:00:14 +00:00
|
|
|
if( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
|
2008-05-23 01:11:17 +00:00
|
|
|
# Duh
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# We dynamically add a member variable for the purpose of this method
|
|
|
|
|
# alone to cache the result. There's no point in having it hanging
|
|
|
|
|
# around uninitialized in every Title object; therefore we only add it
|
|
|
|
|
# if needed and don't declare it statically.
|
|
|
|
|
if( isset( $this->mHasSubpages ) ) {
|
|
|
|
|
return $this->mHasSubpages;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$db = wfGetDB( DB_SLAVE );
|
|
|
|
|
return $this->mHasSubpages = (bool)$db->selectField( 'page', '1',
|
|
|
|
|
"page_namespace = {$this->mNamespace} AND page_title LIKE '"
|
|
|
|
|
. $db->escapeLike( $this->mDbkeyform ) . "/%'",
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-29 04:31:19 +00:00
|
|
|
/**
|
|
|
|
|
* Could this page contain custom CSS or JavaScript, based
|
|
|
|
|
* on the title?
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function isCssOrJsPage() {
|
|
|
|
|
return $this->mNamespace == NS_MEDIAWIKI
|
|
|
|
|
&& preg_match( '!\.(?:css|js)$!u', $this->mTextform ) > 0;
|
|
|
|
|
}
|
2006-12-12 19:14:29 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Is this a .css or .js subpage of a user page?
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isCssJsSubpage() {
|
2007-04-13 00:23:49 +00:00
|
|
|
return ( NS_USER == $this->mNamespace and preg_match("/\\/.*\\.(?:css|js)$/", $this->mTextform ) );
|
2004-05-10 13:15:28 +00:00
|
|
|
}
|
2006-02-23 14:37:51 +00:00
|
|
|
/**
|
|
|
|
|
* Is this a *valid* .css or .js subpage of a user page?
|
|
|
|
|
* Check that the corresponding skin exists
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isValidCssJsSubpage() {
|
2006-07-02 15:57:59 +00:00
|
|
|
if ( $this->isCssJsSubpage() ) {
|
|
|
|
|
$skinNames = Skin::getSkinNames();
|
|
|
|
|
return array_key_exists( $this->getSkinFromCssJsSubpage(), $skinNames );
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2006-02-23 14:37:51 +00:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Trim down a .css or .js subpage title to get the corresponding skin name
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getSkinFromCssJsSubpage() {
|
2006-02-23 14:37:51 +00:00
|
|
|
$subpage = explode( '/', $this->mTextform );
|
|
|
|
|
$subpage = $subpage[ count( $subpage ) - 1 ];
|
|
|
|
|
return( str_replace( array( '.css', '.js' ), array( '', '' ), $subpage ) );
|
|
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Is this a .css subpage of a user page?
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isCssSubpage() {
|
2008-03-04 21:27:23 +00:00
|
|
|
return ( NS_USER == $this->mNamespace && preg_match("/\\/.*\\.css$/", $this->mTextform ) );
|
2004-05-10 13:15:28 +00:00
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Is this a .js subpage of a user page?
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isJsSubpage() {
|
2008-03-04 21:27:23 +00:00
|
|
|
return ( NS_USER == $this->mNamespace && preg_match("/\\/.*\\.js$/", $this->mTextform ) );
|
2004-05-10 13:15:28 +00:00
|
|
|
}
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Protect css/js subpages of user pages: can $wgUser edit
|
|
|
|
|
* this page?
|
|
|
|
|
*
|
|
|
|
|
* @return boolean
|
|
|
|
|
* @todo XXX: this might be better using restrictions
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function userCanEditCssJsSubpage() {
|
2004-05-10 13:15:28 +00:00
|
|
|
global $wgUser;
|
2008-03-04 21:27:23 +00:00
|
|
|
return ( $wgUser->isAllowed('editusercssjs') || preg_match('/^'.preg_quote($wgUser->getName(), '/').'\//', $this->mTextform) );
|
2004-05-10 13:15:28 +00:00
|
|
|
}
|
|
|
|
|
|
2007-01-12 07:31:34 +00:00
|
|
|
/**
|
|
|
|
|
* Cascading protection: Return true if cascading restrictions apply to this page, false if not.
|
|
|
|
|
*
|
|
|
|
|
* @return bool If the page is subject to cascading restrictions.
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isCascadeProtected() {
|
2007-08-21 03:57:54 +00:00
|
|
|
list( $sources, /* $restrictions */ ) = $this->getCascadeProtectionSources( false );
|
2007-03-14 22:57:32 +00:00
|
|
|
return ( $sources > 0 );
|
2007-01-12 07:31:34 +00:00
|
|
|
}
|
|
|
|
|
|
2007-01-10 23:32:38 +00:00
|
|
|
/**
|
2007-01-12 04:43:33 +00:00
|
|
|
* Cascading protection: Get the source of any cascading restrictions on this page.
|
|
|
|
|
*
|
2007-01-12 07:31:34 +00:00
|
|
|
* @param $get_pages bool Whether or not to retrieve the actual pages that the restrictions have come from.
|
2007-03-14 22:57:32 +00:00
|
|
|
* @return array( mixed title array, restriction array)
|
|
|
|
|
* Array of the Title objects of the pages from which cascading restrictions have come, false for none, or true if such restrictions exist, but $get_pages was not set.
|
|
|
|
|
* The restriction array is an array of each type, each of which contains an array of unique groups
|
2007-01-12 04:43:33 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getCascadeProtectionSources( $get_pages = true ) {
|
2008-06-11 21:36:07 +00:00
|
|
|
global $wgRestrictionTypes;
|
2007-03-14 22:57:32 +00:00
|
|
|
|
|
|
|
|
# Define our dimension of restrictions types
|
|
|
|
|
$pagerestrictions = array();
|
|
|
|
|
foreach( $wgRestrictionTypes as $action )
|
|
|
|
|
$pagerestrictions[$action] = array();
|
|
|
|
|
|
2007-01-12 07:31:34 +00:00
|
|
|
if ( isset( $this->mCascadeSources ) && $get_pages ) {
|
2007-03-14 22:57:32 +00:00
|
|
|
return array( $this->mCascadeSources, $this->mCascadingRestrictions );
|
2007-01-12 07:31:34 +00:00
|
|
|
} else if ( isset( $this->mHasCascadingRestrictions ) && !$get_pages ) {
|
2007-03-14 22:57:32 +00:00
|
|
|
return array( $this->mHasCascadingRestrictions, $pagerestrictions );
|
2007-01-12 04:43:33 +00:00
|
|
|
}
|
|
|
|
|
|
2007-01-12 08:37:07 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
|
2008-06-21 03:17:35 +00:00
|
|
|
$dbr = wfGetDb( DB_SLAVE );
|
2007-01-12 04:43:33 +00:00
|
|
|
|
|
|
|
|
if ( $this->getNamespace() == NS_IMAGE ) {
|
2007-01-12 09:10:30 +00:00
|
|
|
$tables = array ('imagelinks', 'page_restrictions');
|
2007-01-22 19:52:32 +00:00
|
|
|
$where_clauses = array(
|
|
|
|
|
'il_to' => $this->getDBkey(),
|
|
|
|
|
'il_from=pr_page',
|
|
|
|
|
'pr_cascade' => 1 );
|
2007-01-12 04:43:33 +00:00
|
|
|
} else {
|
2007-01-12 09:10:30 +00:00
|
|
|
$tables = array ('templatelinks', 'page_restrictions');
|
2007-01-22 19:52:32 +00:00
|
|
|
$where_clauses = array(
|
|
|
|
|
'tl_namespace' => $this->getNamespace(),
|
|
|
|
|
'tl_title' => $this->getDBkey(),
|
|
|
|
|
'tl_from=pr_page',
|
|
|
|
|
'pr_cascade' => 1 );
|
2007-01-12 04:43:33 +00:00
|
|
|
}
|
|
|
|
|
|
2007-01-12 08:37:07 +00:00
|
|
|
if ( $get_pages ) {
|
2007-03-14 22:57:32 +00:00
|
|
|
$cols = array('pr_page', 'page_namespace', 'page_title', 'pr_expiry', 'pr_type', 'pr_level' );
|
2007-01-12 08:37:07 +00:00
|
|
|
$where_clauses[] = 'page_id=pr_page';
|
2007-01-12 09:10:30 +00:00
|
|
|
$tables[] = 'page';
|
2007-01-12 12:46:01 +00:00
|
|
|
} else {
|
2007-01-22 19:52:32 +00:00
|
|
|
$cols = array( 'pr_expiry' );
|
2007-01-12 08:37:07 +00:00
|
|
|
}
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2007-01-22 19:52:32 +00:00
|
|
|
$res = $dbr->select( $tables, $cols, $where_clauses, __METHOD__ );
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2007-01-22 19:52:32 +00:00
|
|
|
$sources = $get_pages ? array() : false;
|
|
|
|
|
$now = wfTimestampNow();
|
|
|
|
|
$purgeExpired = false;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row ) {
|
2007-01-22 19:52:32 +00:00
|
|
|
$expiry = Block::decodeExpiry( $row->pr_expiry );
|
|
|
|
|
if( $expiry > $now ) {
|
|
|
|
|
if ($get_pages) {
|
2007-01-12 07:31:34 +00:00
|
|
|
$page_id = $row->pr_page;
|
2007-01-12 08:37:07 +00:00
|
|
|
$page_ns = $row->page_namespace;
|
|
|
|
|
$page_title = $row->page_title;
|
|
|
|
|
$sources[$page_id] = Title::makeTitle($page_ns, $page_title);
|
2007-03-14 22:57:32 +00:00
|
|
|
# Add groups needed for each restriction type if its not already there
|
|
|
|
|
# Make sure this restriction type still exists
|
|
|
|
|
if ( isset($pagerestrictions[$row->pr_type]) && !in_array($row->pr_level, $pagerestrictions[$row->pr_type]) ) {
|
|
|
|
|
$pagerestrictions[$row->pr_type][]=$row->pr_level;
|
|
|
|
|
}
|
2007-01-22 19:52:32 +00:00
|
|
|
} else {
|
|
|
|
|
$sources = true;
|
2007-01-12 07:31:34 +00:00
|
|
|
}
|
2007-01-12 09:10:30 +00:00
|
|
|
} else {
|
2007-01-22 19:52:32 +00:00
|
|
|
// Trigger lazy purge of expired restrictions from the db
|
|
|
|
|
$purgeExpired = true;
|
2007-01-12 09:10:30 +00:00
|
|
|
}
|
2007-01-22 19:52:32 +00:00
|
|
|
}
|
|
|
|
|
if( $purgeExpired ) {
|
|
|
|
|
Title::purgeExpiredRestrictions();
|
2007-01-10 23:32:38 +00:00
|
|
|
}
|
|
|
|
|
|
2007-01-12 08:37:07 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2007-01-12 08:37:07 +00:00
|
|
|
if ( $get_pages ) {
|
|
|
|
|
$this->mCascadeSources = $sources;
|
2007-03-14 22:57:32 +00:00
|
|
|
$this->mCascadingRestrictions = $pagerestrictions;
|
2007-01-12 09:10:30 +00:00
|
|
|
} else {
|
2007-01-12 08:37:07 +00:00
|
|
|
$this->mHasCascadingRestrictions = $sources;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-14 22:57:32 +00:00
|
|
|
return array( $sources, $pagerestrictions );
|
2007-01-10 23:32:38 +00:00
|
|
|
}
|
|
|
|
|
|
2007-01-11 00:31:04 +00:00
|
|
|
function areRestrictionsCascading() {
|
2007-01-10 23:32:38 +00:00
|
|
|
if (!$this->mRestrictionsLoaded) {
|
|
|
|
|
$this->loadRestrictions();
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-11 00:31:04 +00:00
|
|
|
return $this->mCascadeRestriction;
|
2007-01-10 23:32:38 +00:00
|
|
|
}
|
|
|
|
|
|
2004-11-24 12:55:48 +00:00
|
|
|
/**
|
|
|
|
|
* Loads a string into mRestrictions array
|
2007-01-10 23:32:38 +00:00
|
|
|
* @param resource $res restrictions as an SQL result.
|
2004-11-24 12:55:48 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
private function loadRestrictionsFromRow( $res, $oldFashionedRestrictions = NULL ) {
|
2008-03-04 21:27:23 +00:00
|
|
|
global $wgRestrictionTypes;
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
|
|
|
|
|
foreach( $wgRestrictionTypes as $type ){
|
|
|
|
|
$this->mRestrictions[$type] = array();
|
|
|
|
|
}
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2008-02-26 20:41:21 +00:00
|
|
|
$this->mCascadeRestriction = false;
|
|
|
|
|
$this->mRestrictionsExpiry = Block::decodeExpiry('');
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2007-01-12 01:44:33 +00:00
|
|
|
# Backwards-compatibility: also load the restrictions from the page record (old format).
|
|
|
|
|
|
2008-04-29 19:18:58 +00:00
|
|
|
if ( $oldFashionedRestrictions === NULL ) {
|
2008-05-28 17:50:17 +00:00
|
|
|
$oldFashionedRestrictions = $dbr->selectField( 'page', 'page_restrictions',
|
|
|
|
|
array( 'page_id' => $this->getArticleId() ), __METHOD__ );
|
2007-01-12 01:44:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($oldFashionedRestrictions != '') {
|
|
|
|
|
|
|
|
|
|
foreach( explode( ':', trim( $oldFashionedRestrictions ) ) as $restrict ) {
|
|
|
|
|
$temp = explode( '=', trim( $restrict ) );
|
|
|
|
|
if(count($temp) == 1) {
|
|
|
|
|
// old old format should be treated as edit/move restriction
|
2008-03-04 21:27:23 +00:00
|
|
|
$this->mRestrictions['edit'] = explode( ',', trim( $temp[0] ) );
|
|
|
|
|
$this->mRestrictions['move'] = explode( ',', trim( $temp[0] ) );
|
2007-01-12 01:44:33 +00:00
|
|
|
} else {
|
|
|
|
|
$this->mRestrictions[$temp[0]] = explode( ',', trim( $temp[1] ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->mOldRestrictions = true;
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2007-01-12 01:44:33 +00:00
|
|
|
}
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2007-01-22 19:52:32 +00:00
|
|
|
if( $dbr->numRows( $res ) ) {
|
2007-01-12 01:44:33 +00:00
|
|
|
# Current system - load second to make them override.
|
2007-01-22 19:52:32 +00:00
|
|
|
$now = wfTimestampNow();
|
|
|
|
|
$purgeExpired = false;
|
2007-01-22 08:26:41 +00:00
|
|
|
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row ) {
|
2007-01-12 01:44:33 +00:00
|
|
|
# Cycle through all the restrictions.
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-03-04 21:27:23 +00:00
|
|
|
// Don't take care of restrictions types that aren't in $wgRestrictionTypes
|
|
|
|
|
if( !in_array( $row->pr_type, $wgRestrictionTypes ) )
|
|
|
|
|
continue;
|
2007-01-22 08:26:41 +00:00
|
|
|
|
|
|
|
|
// 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
|
2007-01-22 19:52:32 +00:00
|
|
|
$expiry = Block::decodeExpiry( $row->pr_expiry );
|
2007-01-22 08:26:41 +00:00
|
|
|
|
|
|
|
|
// Only apply the restrictions if they haven't expired!
|
2007-01-22 19:52:32 +00:00
|
|
|
if ( !$expiry || $expiry > $now ) {
|
|
|
|
|
$this->mRestrictionsExpiry = $expiry;
|
2007-01-22 08:26:41 +00:00
|
|
|
$this->mRestrictions[$row->pr_type] = explode( ',', trim( $row->pr_level ) );
|
2007-03-14 22:57:32 +00:00
|
|
|
|
2007-01-22 08:26:41 +00:00
|
|
|
$this->mCascadeRestriction |= $row->pr_cascade;
|
2007-01-22 19:52:32 +00:00
|
|
|
} else {
|
|
|
|
|
// Trigger a lazy purge of expired restrictions
|
|
|
|
|
$purgeExpired = true;
|
2007-01-22 08:26:41 +00:00
|
|
|
}
|
2007-01-12 01:44:33 +00:00
|
|
|
}
|
2007-04-16 15:24:04 +00:00
|
|
|
|
2007-01-22 19:52:32 +00:00
|
|
|
if( $purgeExpired ) {
|
|
|
|
|
Title::purgeExpiredRestrictions();
|
|
|
|
|
}
|
2004-11-24 12:55:48 +00:00
|
|
|
}
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2007-01-12 06:17:13 +00:00
|
|
|
$this->mRestrictionsLoaded = true;
|
2004-11-24 12:55:48 +00:00
|
|
|
}
|
|
|
|
|
|
2007-04-16 15:24:04 +00:00
|
|
|
public function loadRestrictions( $oldFashionedRestrictions = NULL ) {
|
2007-01-10 23:32:38 +00:00
|
|
|
if( !$this->mRestrictionsLoaded ) {
|
2007-12-11 09:51:56 +00:00
|
|
|
if ($this->exists()) {
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
|
|
|
|
|
$res = $dbr->select( 'page_restrictions', '*',
|
|
|
|
|
array ( 'pr_page' => $this->getArticleId() ), __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$this->loadRestrictionsFromRow( $res, $oldFashionedRestrictions );
|
|
|
|
|
} else {
|
|
|
|
|
$title_protection = $this->getTitleProtection();
|
2007-04-16 15:24:04 +00:00
|
|
|
|
2007-12-11 09:51:56 +00:00
|
|
|
if (is_array($title_protection)) {
|
|
|
|
|
extract($title_protection);
|
2007-01-12 01:44:33 +00:00
|
|
|
|
2007-12-11 09:51:56 +00:00
|
|
|
$now = wfTimestampNow();
|
|
|
|
|
$expiry = Block::decodeExpiry($pt_expiry);
|
|
|
|
|
|
|
|
|
|
if (!$expiry || $expiry > $now) {
|
|
|
|
|
// Apply the restrictions
|
|
|
|
|
$this->mRestrictionsExpiry = $expiry;
|
|
|
|
|
$this->mRestrictions['create'] = explode(',', trim($pt_create_perm) );
|
|
|
|
|
} else { // Get rid of the old restrictions
|
|
|
|
|
Title::purgeExpiredRestrictions();
|
|
|
|
|
}
|
2008-07-03 12:25:52 +00:00
|
|
|
} else {
|
|
|
|
|
$this->mRestrictionsExpiry = Block::decodeExpiry('');
|
2007-12-11 09:51:56 +00:00
|
|
|
}
|
|
|
|
|
$this->mRestrictionsLoaded = true;
|
|
|
|
|
}
|
2007-01-10 23:32:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-16 15:24:04 +00:00
|
|
|
/**
|
2007-01-22 08:26:41 +00:00
|
|
|
* Purge expired restrictions from the page_restrictions table
|
|
|
|
|
*/
|
|
|
|
|
static function purgeExpiredRestrictions() {
|
2007-01-22 18:59:08 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
$dbw->delete( 'page_restrictions',
|
|
|
|
|
array( 'pr_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ),
|
|
|
|
|
__METHOD__ );
|
2007-12-11 09:51:56 +00:00
|
|
|
|
|
|
|
|
$dbw->delete( 'protected_titles',
|
|
|
|
|
array( 'pt_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ),
|
|
|
|
|
__METHOD__ );
|
2007-01-22 08:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Accessor/initialisation for mRestrictions
|
2006-12-30 19:49:30 +00:00
|
|
|
*
|
2005-07-01 10:44:48 +00:00
|
|
|
* @param string $action action that permission needs to be checked for
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return array the array of groups allowed to edit this article
|
|
|
|
|
*/
|
2007-10-18 14:55:48 +00:00
|
|
|
public function getRestrictions( $action ) {
|
2007-12-11 09:51:56 +00:00
|
|
|
if( !$this->mRestrictionsLoaded ) {
|
|
|
|
|
$this->loadRestrictions();
|
2004-11-24 22:31:48 +00:00
|
|
|
}
|
2007-12-11 09:51:56 +00:00
|
|
|
return isset( $this->mRestrictions[$action] )
|
|
|
|
|
? $this->mRestrictions[$action]
|
|
|
|
|
: array();
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Is there a version of this page in the deletion archive?
|
|
|
|
|
* @return int the number of archived revisions
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isDeleted() {
|
2004-07-10 03:09:26 +00:00
|
|
|
$fname = 'Title::isDeleted';
|
2005-06-25 13:40:38 +00:00
|
|
|
if ( $this->getNamespace() < 0 ) {
|
|
|
|
|
$n = 0;
|
|
|
|
|
} else {
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2005-07-01 10:44:48 +00:00
|
|
|
$n = $dbr->selectField( 'archive', 'COUNT(*)', array( 'ar_namespace' => $this->getNamespace(),
|
2005-06-25 13:40:38 +00:00
|
|
|
'ar_title' => $this->getDBkey() ), $fname );
|
2006-06-16 01:16:45 +00:00
|
|
|
if( $this->getNamespace() == NS_IMAGE ) {
|
|
|
|
|
$n += $dbr->selectField( 'filearchive', 'COUNT(*)',
|
|
|
|
|
array( 'fa_name' => $this->getDBkey() ), $fname );
|
|
|
|
|
}
|
2005-06-25 13:40:38 +00:00
|
|
|
}
|
2004-07-10 03:09:26 +00:00
|
|
|
return (int)$n;
|
2003-08-31 22:21:50 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the article ID for this Title from the link cache,
|
|
|
|
|
* adding it if necessary
|
|
|
|
|
* @param int $flags a bit field; may be GAID_FOR_UPDATE to select
|
|
|
|
|
* for update
|
|
|
|
|
* @return int the ID
|
|
|
|
|
*/
|
2007-01-09 02:45:09 +00:00
|
|
|
public function getArticleID( $flags = 0 ) {
|
2008-04-09 18:23:34 +00:00
|
|
|
$linkCache = LinkCache::singleton();
|
2004-08-20 14:59:49 +00:00
|
|
|
if ( $flags & GAID_FOR_UPDATE ) {
|
2006-01-05 02:05:53 +00:00
|
|
|
$oldUpdate = $linkCache->forUpdate( true );
|
|
|
|
|
$this->mArticleID = $linkCache->addLinkObj( $this );
|
|
|
|
|
$linkCache->forUpdate( $oldUpdate );
|
2004-08-20 14:59:49 +00:00
|
|
|
} else {
|
|
|
|
|
if ( -1 == $this->mArticleID ) {
|
2006-01-05 02:05:53 +00:00
|
|
|
$this->mArticleID = $linkCache->addLinkObj( $this );
|
2004-08-20 14:59:49 +00:00
|
|
|
}
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
return $this->mArticleID;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-04-09 05:21:00 +00:00
|
|
|
/**
|
|
|
|
|
* Is this an article that is a redirect page?
|
|
|
|
|
* Uses link cache, adding it if necessary
|
|
|
|
|
* @param int $flags a bit field; may be GAID_FOR_UPDATE to select for update
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function isRedirect( $flags = 0 ) {
|
2008-04-09 16:32:14 +00:00
|
|
|
if( !is_null($this->mRedirect) )
|
|
|
|
|
return $this->mRedirect;
|
2008-04-14 07:45:50 +00:00
|
|
|
# Zero for special pages.
|
2008-04-09 05:21:00 +00:00
|
|
|
# Also, calling getArticleID() loads the field from cache!
|
|
|
|
|
if( !$this->getArticleID($flags) || $this->getNamespace() == NS_SPECIAL ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-04-09 18:23:34 +00:00
|
|
|
$linkCache = LinkCache::singleton();
|
2008-04-09 16:32:14 +00:00
|
|
|
$this->mRedirect = (bool)$linkCache->getGoodLinkFieldObj( $this, 'redirect' );
|
2008-04-09 05:21:00 +00:00
|
|
|
|
2008-04-09 16:32:14 +00:00
|
|
|
return $this->mRedirect;
|
2008-04-09 05:21:00 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-04-09 05:21:00 +00:00
|
|
|
/**
|
|
|
|
|
* What is the length of this page?
|
|
|
|
|
* Uses link cache, adding it if necessary
|
|
|
|
|
* @param int $flags a bit field; may be GAID_FOR_UPDATE to select for update
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function getLength( $flags = 0 ) {
|
2008-04-09 16:32:14 +00:00
|
|
|
if( $this->mLength != -1 )
|
|
|
|
|
return $this->mLength;
|
2008-04-14 07:45:50 +00:00
|
|
|
# Zero for special pages.
|
2008-04-09 05:21:00 +00:00
|
|
|
# Also, calling getArticleID() loads the field from cache!
|
|
|
|
|
if( !$this->getArticleID($flags) || $this->getNamespace() == NS_SPECIAL ) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2008-04-09 18:23:34 +00:00
|
|
|
$linkCache = LinkCache::singleton();
|
2008-04-09 16:32:14 +00:00
|
|
|
$this->mLength = intval( $linkCache->getGoodLinkFieldObj( $this, 'length' ) );
|
2008-04-09 05:21:00 +00:00
|
|
|
|
2008-04-09 16:32:14 +00:00
|
|
|
return $this->mLength;
|
2008-04-09 05:21:00 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2008-05-06 14:54:17 +00:00
|
|
|
/**
|
|
|
|
|
* What is the page_latest field for this page?
|
|
|
|
|
* @param int $flags a bit field; may be GAID_FOR_UPDATE to select for update
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
|
|
|
|
public function getLatestRevID( $flags = 0 ) {
|
2005-07-01 10:44:48 +00:00
|
|
|
if ($this->mLatestID !== false)
|
|
|
|
|
return $this->mLatestID;
|
|
|
|
|
|
2008-06-21 03:17:35 +00:00
|
|
|
$db = ($flags & GAID_FOR_UPDATE) ? wfGetDB(DB_MASTER) : wfGetDB(DB_SLAVE);
|
2005-07-01 10:44:48 +00:00
|
|
|
return $this->mLatestID = $db->selectField( 'revision',
|
|
|
|
|
"max(rev_id)",
|
2008-05-21 23:17:30 +00:00
|
|
|
array('rev_page' => $this->getArticleID($flags)),
|
2005-07-01 10:44:48 +00:00
|
|
|
'Title::getLatestRevID' );
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* This clears some fields in this object, and clears any associated
|
2006-01-05 02:05:53 +00:00
|
|
|
* keys in the "bad links" section of the link cache.
|
2004-09-30 05:21:20 +00:00
|
|
|
*
|
|
|
|
|
* - This is called from Article::insertNewArticle() to allow
|
2004-12-19 08:00:50 +00:00
|
|
|
* loading of the new page_id. It's also called from
|
2004-09-30 05:21:20 +00:00
|
|
|
* Article::doDeleteArticle()
|
|
|
|
|
*
|
|
|
|
|
* @param int $newid the new Article ID
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function resetArticleID( $newid ) {
|
2008-04-09 18:23:34 +00:00
|
|
|
$linkCache = LinkCache::singleton();
|
2006-01-05 02:05:53 +00:00
|
|
|
$linkCache->clearBadLink( $this->getPrefixedDBkey() );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
|
|
|
|
if ( 0 == $newid ) { $this->mArticleID = -1; }
|
|
|
|
|
else { $this->mArticleID = $newid; }
|
|
|
|
|
$this->mRestrictionsLoaded = false;
|
|
|
|
|
$this->mRestrictions = array();
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2004-12-19 08:00:50 +00:00
|
|
|
* Updates page_touched for this page; called from LinksUpdate.php
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return bool true if the update succeded
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function invalidateCache() {
|
2005-07-17 19:34:58 +00:00
|
|
|
global $wgUseFileCache;
|
|
|
|
|
|
2005-04-12 04:03:21 +00:00
|
|
|
if ( wfReadOnly() ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2005-07-01 10:44:48 +00:00
|
|
|
$success = $dbw->update( 'page',
|
|
|
|
|
array( /* SET */
|
2004-12-19 08:00:50 +00:00
|
|
|
'page_touched' => $dbw->timestamp()
|
2005-07-01 10:44:48 +00:00
|
|
|
), array( /* WHERE */
|
2004-12-19 08:00:50 +00:00
|
|
|
'page_namespace' => $this->getNamespace() ,
|
|
|
|
|
'page_title' => $this->getDBkey()
|
2004-07-10 03:09:26 +00:00
|
|
|
), 'Title::invalidateCache'
|
|
|
|
|
);
|
2005-07-17 19:34:58 +00:00
|
|
|
|
|
|
|
|
if ($wgUseFileCache) {
|
2006-10-11 08:25:26 +00:00
|
|
|
$cache = new HTMLFileCache($this);
|
2005-07-17 19:34:58 +00:00
|
|
|
@unlink($cache->fileCacheName());
|
|
|
|
|
}
|
|
|
|
|
|
2004-07-10 03:09:26 +00:00
|
|
|
return $success;
|
2003-11-09 11:45:12 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Prefix some arbitrary text with the namespace or interwiki prefix
|
|
|
|
|
* of this object
|
|
|
|
|
*
|
|
|
|
|
* @param string $name the text
|
|
|
|
|
* @return string the prefixed text
|
2006-06-10 18:28:50 +00:00
|
|
|
* @private
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2004-08-16 20:14:35 +00:00
|
|
|
/* private */ function prefix( $name ) {
|
|
|
|
|
$p = '';
|
|
|
|
|
if ( '' != $this->mInterwiki ) {
|
|
|
|
|
$p = $this->mInterwiki . ':';
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
if ( 0 != $this->mNamespace ) {
|
2006-12-31 03:04:49 +00:00
|
|
|
$p .= $this->getNsText() . ':';
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
return $p . $name;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Secure and split - main initialisation function for this object
|
|
|
|
|
*
|
|
|
|
|
* Assumes that mDbkeyform has been set, and is urldecoded
|
|
|
|
|
* and uses underscores, but not otherwise munged. This function
|
|
|
|
|
* removes illegal characters, splits off the interwiki and
|
|
|
|
|
* namespace prefixes, sets the other forms, and canonicalizes
|
|
|
|
|
* everything.
|
|
|
|
|
* @return bool true on success
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
private function secureAndSplit() {
|
2004-09-24 16:45:31 +00:00
|
|
|
global $wgContLang, $wgLocalInterwiki, $wgCapitalLinks;
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2003-10-22 23:56:49 +00:00
|
|
|
# Initialisation
|
2004-11-27 08:31:21 +00:00
|
|
|
static $rxTc = false;
|
|
|
|
|
if( !$rxTc ) {
|
2007-12-28 21:34:49 +00:00
|
|
|
# Matching titles will be held as illegal.
|
|
|
|
|
$rxTc = '/' .
|
|
|
|
|
# Any character not allowed is forbidden...
|
|
|
|
|
'[^' . Title::legalChars() . ']' .
|
|
|
|
|
# URL percent encoding sequences interfere with the ability
|
|
|
|
|
# to round-trip titles -- you can't link to them consistently.
|
|
|
|
|
'|%[0-9A-Fa-f]{2}' .
|
|
|
|
|
# XML/HTML character references produce similar issues.
|
|
|
|
|
'|&[A-Za-z0-9\x80-\xff]+;' .
|
|
|
|
|
'|&#[0-9]+;' .
|
|
|
|
|
'|&#x[0-9A-Fa-f]+;' .
|
|
|
|
|
'/S';
|
2003-10-22 23:56:49 +00:00
|
|
|
}
|
|
|
|
|
|
2004-08-16 20:14:35 +00:00
|
|
|
$this->mInterwiki = $this->mFragment = '';
|
2004-03-20 15:03:26 +00:00
|
|
|
$this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2006-12-23 00:28:48 +00:00
|
|
|
$dbkey = $this->mDbkeyform;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2006-12-23 00:28:48 +00:00
|
|
|
# Strip Unicode bidi override characters.
|
|
|
|
|
# Sometimes they slip into cut-n-pasted page titles, where the
|
|
|
|
|
# override chars get included in list displays.
|
|
|
|
|
$dbkey = str_replace( "\xE2\x80\x8E", '', $dbkey ); // 200E LEFT-TO-RIGHT MARK
|
|
|
|
|
$dbkey = str_replace( "\xE2\x80\x8F", '', $dbkey ); // 200F RIGHT-TO-LEFT MARK
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2003-12-11 12:43:13 +00:00
|
|
|
# Clean up whitespace
|
|
|
|
|
#
|
2006-12-23 00:28:48 +00:00
|
|
|
$dbkey = preg_replace( '/[ _]+/', '_', $dbkey );
|
2006-12-08 06:09:15 +00:00
|
|
|
$dbkey = trim( $dbkey, '_' );
|
2004-04-09 00:45:15 +00:00
|
|
|
|
2006-12-08 06:09:15 +00:00
|
|
|
if ( '' == $dbkey ) {
|
2003-10-01 10:26:26 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2006-12-08 06:09:15 +00:00
|
|
|
if( false !== strpos( $dbkey, UTF8_REPLACEMENT ) ) {
|
2004-09-03 06:12:57 +00:00
|
|
|
# Contained illegal UTF-8 sequences or forbidden Unicode chars.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2006-12-08 06:09:15 +00:00
|
|
|
$this->mDbkeyform = $dbkey;
|
2004-03-06 01:49:16 +00:00
|
|
|
|
2005-08-20 15:30:22 +00:00
|
|
|
# Initial colon indicates main namespace rather than specified default
|
|
|
|
|
# but should not create invalid {ns,title} pairs such as {0,Project:Foo}
|
2006-12-08 06:09:15 +00:00
|
|
|
if ( ':' == $dbkey{0} ) {
|
2004-03-20 15:03:26 +00:00
|
|
|
$this->mNamespace = NS_MAIN;
|
2006-12-08 06:09:15 +00:00
|
|
|
$dbkey = substr( $dbkey, 1 ); # remove the colon but continue processing
|
2007-05-04 14:30:02 +00:00
|
|
|
$dbkey = trim( $dbkey, '_' ); # remove any subsequent whitespace
|
2005-08-20 15:30:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Namespace or interwiki prefix
|
|
|
|
|
$firstPass = true;
|
|
|
|
|
do {
|
2006-11-29 11:43:58 +00:00
|
|
|
$m = array();
|
2006-12-08 06:09:15 +00:00
|
|
|
if ( preg_match( "/^(.+?)_*:_*(.*)$/S", $dbkey, $m ) ) {
|
2005-08-20 15:30:22 +00:00
|
|
|
$p = $m[1];
|
2007-04-19 18:47:04 +00:00
|
|
|
if ( $ns = $wgContLang->getNsIndex( $p )) {
|
2005-08-20 15:30:22 +00:00
|
|
|
# Ordinary namespace
|
2006-12-08 06:09:15 +00:00
|
|
|
$dbkey = $m[2];
|
2005-08-20 15:30:22 +00:00
|
|
|
$this->mNamespace = $ns;
|
|
|
|
|
} elseif( $this->getInterwikiLink( $p ) ) {
|
|
|
|
|
if( !$firstPass ) {
|
|
|
|
|
# Can't make a local interwiki link to an interwiki link.
|
|
|
|
|
# That's just crazy!
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Interwiki link
|
2006-12-08 06:09:15 +00:00
|
|
|
$dbkey = $m[2];
|
2006-10-13 23:32:36 +00:00
|
|
|
$this->mInterwiki = $wgContLang->lc( $p );
|
2005-08-20 15:30:22 +00:00
|
|
|
|
|
|
|
|
# Redundant interwiki prefix to the local wiki
|
|
|
|
|
if ( 0 == strcasecmp( $this->mInterwiki, $wgLocalInterwiki ) ) {
|
2006-12-08 06:09:15 +00:00
|
|
|
if( $dbkey == '' ) {
|
2005-08-20 15:30:22 +00:00
|
|
|
# Can't have an empty self-link
|
2004-11-27 08:31:21 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2005-08-20 15:30:22 +00:00
|
|
|
$this->mInterwiki = '';
|
|
|
|
|
$firstPass = false;
|
|
|
|
|
# Do another namespace split...
|
|
|
|
|
continue;
|
2003-10-22 23:56:49 +00:00
|
|
|
}
|
2006-02-01 04:41:53 +00:00
|
|
|
|
2006-03-11 17:13:49 +00:00
|
|
|
# If there's an initial colon after the interwiki, that also
|
2006-02-01 04:41:53 +00:00
|
|
|
# resets the default namespace
|
2006-12-08 06:09:15 +00:00
|
|
|
if ( $dbkey !== '' && $dbkey[0] == ':' ) {
|
2006-02-01 04:41:53 +00:00
|
|
|
$this->mNamespace = NS_MAIN;
|
2006-12-08 06:09:15 +00:00
|
|
|
$dbkey = substr( $dbkey, 1 );
|
2006-02-01 04:41:53 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2005-08-20 15:30:22 +00:00
|
|
|
# If there's no recognized interwiki or namespace,
|
|
|
|
|
# then let the colon expression be part of the title.
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
} while( true );
|
2004-03-06 01:49:16 +00:00
|
|
|
|
2003-04-14 23:10:40 +00:00
|
|
|
# We already know that some pages won't be in the database!
|
|
|
|
|
#
|
2006-11-27 22:55:12 +00:00
|
|
|
if ( '' != $this->mInterwiki || NS_SPECIAL == $this->mNamespace ) {
|
2003-04-14 23:10:40 +00:00
|
|
|
$this->mArticleID = 0;
|
|
|
|
|
}
|
2006-12-08 06:09:15 +00:00
|
|
|
$fragment = strstr( $dbkey, '#' );
|
2007-03-27 21:43:21 +00:00
|
|
|
if ( false !== $fragment ) {
|
2006-12-08 06:09:15 +00:00
|
|
|
$this->setFragment( $fragment );
|
|
|
|
|
$dbkey = substr( $dbkey, 0, strlen( $dbkey ) - strlen( $fragment ) );
|
2004-09-14 05:35:34 +00:00
|
|
|
# remove whitespace again: prevents "Foo_bar_#"
|
|
|
|
|
# becoming "Foo_bar_"
|
2006-12-08 06:09:15 +00:00
|
|
|
$dbkey = preg_replace( '/_*$/', '', $dbkey );
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
2003-12-11 18:39:03 +00:00
|
|
|
# Reject illegal characters.
|
|
|
|
|
#
|
2007-03-27 21:43:21 +00:00
|
|
|
if( preg_match( $rxTc, $dbkey ) ) {
|
2003-12-11 18:39:03 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-11-23 07:38:42 +00:00
|
|
|
/**
|
|
|
|
|
* Pages with "/./" or "/../" appearing in the URLs will
|
|
|
|
|
* often be unreachable due to the way web browsers deal
|
|
|
|
|
* with 'relative' URLs. Forbid them explicitly.
|
|
|
|
|
*/
|
2006-12-08 06:09:15 +00:00
|
|
|
if ( strpos( $dbkey, '.' ) !== false &&
|
|
|
|
|
( $dbkey === '.' || $dbkey === '..' ||
|
|
|
|
|
strpos( $dbkey, './' ) === 0 ||
|
|
|
|
|
strpos( $dbkey, '../' ) === 0 ||
|
|
|
|
|
strpos( $dbkey, '/./' ) !== false ||
|
2008-02-12 22:45:10 +00:00
|
|
|
strpos( $dbkey, '/../' ) !== false ||
|
|
|
|
|
substr( $dbkey, -2 ) == '/.' ||
|
|
|
|
|
substr( $dbkey, -3 ) == '/..' ) )
|
2004-06-24 21:33:43 +00:00
|
|
|
{
|
2004-02-24 00:09:03 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-03-08 22:14:53 +00:00
|
|
|
/**
|
|
|
|
|
* Magic tilde sequences? Nu-uh!
|
|
|
|
|
*/
|
|
|
|
|
if( strpos( $dbkey, '~~~' ) !== false ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2003-12-11 18:39:03 +00:00
|
|
|
|
2006-12-08 06:09:15 +00:00
|
|
|
/**
|
|
|
|
|
* Limit the size of titles to 255 bytes.
|
|
|
|
|
* This is typically the size of the underlying database field.
|
|
|
|
|
* We make an exception for special pages, which don't need to be stored
|
2008-04-14 07:45:50 +00:00
|
|
|
* in the database, and may edge over 255 bytes due to subpage syntax
|
2006-12-08 06:09:15 +00:00
|
|
|
* for long titles, e.g. [[Special:Block/Long name]]
|
|
|
|
|
*/
|
|
|
|
|
if ( ( $this->mNamespace != NS_SPECIAL && strlen( $dbkey ) > 255 ) ||
|
2008-04-14 07:45:50 +00:00
|
|
|
strlen( $dbkey ) > 512 )
|
2006-12-08 06:09:15 +00:00
|
|
|
{
|
2004-10-05 00:21:52 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2004-11-23 07:38:42 +00:00
|
|
|
/**
|
|
|
|
|
* Normally, all wiki links are forced to have
|
|
|
|
|
* an initial capital letter so [[foo]] and [[Foo]]
|
|
|
|
|
* point to the same place.
|
|
|
|
|
*
|
|
|
|
|
* Don't force it for interwikis, since the other
|
|
|
|
|
* site might be case-sensitive.
|
|
|
|
|
*/
|
2007-06-03 10:44:27 +00:00
|
|
|
$this->mUserCaseDBKey = $dbkey;
|
2004-08-16 20:14:35 +00:00
|
|
|
if( $wgCapitalLinks && $this->mInterwiki == '') {
|
2006-12-08 06:09:15 +00:00
|
|
|
$dbkey = $wgContLang->ucfirst( $dbkey );
|
2004-04-05 04:02:04 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-01-16 08:46:24 +00:00
|
|
|
/**
|
|
|
|
|
* Can't make a link to a namespace alone...
|
|
|
|
|
* "empty" local links can only be self-links
|
|
|
|
|
* with a fragment identifier.
|
|
|
|
|
*/
|
2006-12-08 06:09:15 +00:00
|
|
|
if( $dbkey == '' &&
|
2005-01-16 08:46:24 +00:00
|
|
|
$this->mInterwiki == '' &&
|
|
|
|
|
$this->mNamespace != NS_MAIN ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2007-09-04 04:13:53 +00:00
|
|
|
// Allow IPv6 usernames to start with '::' by canonicalizing IPv6 titles.
|
2008-04-14 07:45:50 +00:00
|
|
|
// IP names are not allowed for accounts, and can only be referring to
|
|
|
|
|
// edits from the IP. Given '::' abbreviations and caps/lowercaps,
|
|
|
|
|
// there are numerous ways to present the same IP. Having sp:contribs scan
|
|
|
|
|
// them all is silly and having some show the edits and others not is
|
2007-09-04 15:05:08 +00:00
|
|
|
// inconsistent. Same for talk/userpages. Keep them normalized instead.
|
2008-04-14 07:45:50 +00:00
|
|
|
$dbkey = ($this->mNamespace == NS_USER || $this->mNamespace == NS_USER_TALK) ?
|
2007-09-07 11:01:46 +00:00
|
|
|
IP::sanitizeIP( $dbkey ) : $dbkey;
|
2006-04-30 05:04:38 +00:00
|
|
|
// Any remaining initial :s are illegal.
|
2006-12-08 06:09:15 +00:00
|
|
|
if ( $dbkey !== '' && ':' == $dbkey{0} ) {
|
2006-04-30 05:04:38 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2004-03-06 01:49:16 +00:00
|
|
|
# Fill fields
|
2006-12-08 06:09:15 +00:00
|
|
|
$this->mDbkeyform = $dbkey;
|
|
|
|
|
$this->mUrlform = wfUrlencode( $dbkey );
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2006-12-08 06:09:15 +00:00
|
|
|
$this->mTextform = str_replace( '_', ' ', $dbkey );
|
2008-03-03 19:54:22 +00:00
|
|
|
|
|
|
|
|
return true;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2006-12-08 06:09:15 +00:00
|
|
|
/**
|
|
|
|
|
* Set the fragment for this title
|
|
|
|
|
* This is kind of bad, since except for this rarely-used function, Title objects
|
2008-04-14 07:45:50 +00:00
|
|
|
* are immutable. The reason this is here is because it's better than setting the
|
2006-12-08 06:09:15 +00:00
|
|
|
* members directly, which is what Linker::formatComment was doing previously.
|
|
|
|
|
*
|
|
|
|
|
* @param string $fragment text
|
2007-04-04 05:22:37 +00:00
|
|
|
* @todo clarify whether access is supposed to be public (was marked as "kind of public")
|
2006-12-08 06:09:15 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function setFragment( $fragment ) {
|
2006-12-09 15:32:16 +00:00
|
|
|
$this->mFragment = str_replace( '_', ' ', substr( $fragment, 1 ) );
|
2006-12-08 06:09:15 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get a Title object associated with the talk page of this article
|
|
|
|
|
* @return Title the object for the talk page
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getTalkPage() {
|
2008-03-21 23:13:34 +00:00
|
|
|
return Title::makeTitle( MWNamespace::getTalk( $this->getNamespace() ), $this->getDBkey() );
|
2003-11-20 06:57:00 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get a title object associated with the subject page of this
|
|
|
|
|
* talk page
|
|
|
|
|
*
|
|
|
|
|
* @return Title the object for the subject page
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getSubjectPage() {
|
2008-03-21 23:13:34 +00:00
|
|
|
return Title::makeTitle( MWNamespace::getSubject( $this->getNamespace() ), $this->getDBkey() );
|
2003-11-20 06:57:00 +00:00
|
|
|
}
|
2004-03-20 15:03:26 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get an array of Title objects linking to this Title
|
2005-05-04 00:33:08 +00:00
|
|
|
* Also stores the IDs in the link cache.
|
2004-09-30 05:21:20 +00:00
|
|
|
*
|
2006-06-18 12:42:16 +00:00
|
|
|
* WARNING: do not use this function on arbitrary user-supplied titles!
|
|
|
|
|
* On heavily-used templates it will max out the memory.
|
|
|
|
|
*
|
2005-07-01 10:44:48 +00:00
|
|
|
* @param string $options may be FOR UPDATE
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return array the Title objects linking here
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getLinksTo( $options = '', $table = 'pagelinks', $prefix = 'pl' ) {
|
2008-04-09 18:23:34 +00:00
|
|
|
$linkCache = LinkCache::singleton();
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-07-10 03:09:26 +00:00
|
|
|
if ( $options ) {
|
2007-01-22 23:50:42 +00:00
|
|
|
$db = wfGetDB( DB_MASTER );
|
2004-07-10 03:09:26 +00:00
|
|
|
} else {
|
2007-01-22 23:50:42 +00:00
|
|
|
$db = wfGetDB( DB_SLAVE );
|
2004-07-10 03:09:26 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-12-30 09:33:11 +00:00
|
|
|
$res = $db->select( array( 'page', $table ),
|
2008-04-08 20:34:09 +00:00
|
|
|
array( 'page_namespace', 'page_title', 'page_id', 'page_len', 'page_is_redirect' ),
|
2005-05-26 10:23:36 +00:00
|
|
|
array(
|
2005-12-30 09:33:11 +00:00
|
|
|
"{$prefix}_from=page_id",
|
|
|
|
|
"{$prefix}_namespace" => $this->getNamespace(),
|
2008-01-14 09:26:36 +00:00
|
|
|
"{$prefix}_title" => $this->getDBkey() ),
|
2008-07-27 18:59:46 +00:00
|
|
|
__METHOD__,
|
2005-05-26 10:23:36 +00:00
|
|
|
$options );
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-03-20 15:03:26 +00:00
|
|
|
$retVal = array();
|
2004-07-10 03:09:26 +00:00
|
|
|
if ( $db->numRows( $res ) ) {
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row ) {
|
2004-12-19 08:00:50 +00:00
|
|
|
if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
|
2008-04-09 05:21:00 +00:00
|
|
|
$linkCache->addGoodLinkObj( $row->page_id, $titleObj, $row->page_len, $row->page_is_redirect );
|
2004-05-30 22:38:13 +00:00
|
|
|
$retVal[] = $titleObj;
|
|
|
|
|
}
|
2004-03-20 15:03:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
2004-07-10 03:09:26 +00:00
|
|
|
$db->freeResult( $res );
|
2004-03-20 15:03:26 +00:00
|
|
|
return $retVal;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-30 09:33:11 +00:00
|
|
|
/**
|
|
|
|
|
* Get an array of Title objects using this Title as a template
|
|
|
|
|
* Also stores the IDs in the link cache.
|
|
|
|
|
*
|
2006-06-18 12:42:16 +00:00
|
|
|
* WARNING: do not use this function on arbitrary user-supplied titles!
|
|
|
|
|
* On heavily-used templates it will max out the memory.
|
|
|
|
|
*
|
2005-12-30 09:33:11 +00:00
|
|
|
* @param string $options may be FOR UPDATE
|
|
|
|
|
* @return array the Title objects linking here
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getTemplateLinksTo( $options = '' ) {
|
2005-12-30 09:33:11 +00:00
|
|
|
return $this->getLinksTo( $options, 'templatelinks', 'tl' );
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-24 04:13:47 +00:00
|
|
|
/**
|
|
|
|
|
* Get an array of Title objects referring to non-existent articles linked from this page
|
|
|
|
|
*
|
2007-09-14 04:21:36 +00:00
|
|
|
* @todo check if needed (used only in SpecialBrokenRedirects.php, and should use redirect table in this case)
|
2005-07-01 10:44:48 +00:00
|
|
|
* @param string $options may be FOR UPDATE
|
2005-04-24 04:13:47 +00:00
|
|
|
* @return array the Title objects
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getBrokenLinksFrom( $options = '' ) {
|
2007-09-14 04:21:36 +00:00
|
|
|
if ( $this->getArticleId() == 0 ) {
|
|
|
|
|
# All links from article ID 0 are false positives
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-24 04:13:47 +00:00
|
|
|
if ( $options ) {
|
2007-01-22 23:50:42 +00:00
|
|
|
$db = wfGetDB( DB_MASTER );
|
2005-04-24 04:13:47 +00:00
|
|
|
} else {
|
2007-01-22 23:50:42 +00:00
|
|
|
$db = wfGetDB( DB_SLAVE );
|
2005-04-24 04:13:47 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-05-26 10:23:36 +00:00
|
|
|
$res = $db->safeQuery(
|
|
|
|
|
"SELECT pl_namespace, pl_title
|
|
|
|
|
FROM !
|
|
|
|
|
LEFT JOIN !
|
|
|
|
|
ON pl_namespace=page_namespace
|
|
|
|
|
AND pl_title=page_title
|
|
|
|
|
WHERE pl_from=?
|
|
|
|
|
AND page_namespace IS NULL
|
2006-03-07 01:10:39 +00:00
|
|
|
!",
|
2005-05-26 10:23:36 +00:00
|
|
|
$db->tableName( 'pagelinks' ),
|
|
|
|
|
$db->tableName( 'page' ),
|
|
|
|
|
$this->getArticleId(),
|
|
|
|
|
$options );
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-04-24 04:13:47 +00:00
|
|
|
$retVal = array();
|
|
|
|
|
if ( $db->numRows( $res ) ) {
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row ) {
|
2005-05-26 10:23:36 +00:00
|
|
|
$retVal[] = Title::makeTitle( $row->pl_namespace, $row->pl_title );
|
2005-04-24 04:13:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$db->freeResult( $res );
|
|
|
|
|
return $retVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get a list of URLs to purge from the Squid cache when this
|
|
|
|
|
* page changes
|
|
|
|
|
*
|
|
|
|
|
* @return array the URLs
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getSquidURLs() {
|
2006-10-12 10:34:49 +00:00
|
|
|
global $wgContLang;
|
|
|
|
|
|
|
|
|
|
$urls = array(
|
2004-03-20 15:03:26 +00:00
|
|
|
$this->getInternalURL(),
|
2004-08-16 20:14:35 +00:00
|
|
|
$this->getInternalURL( 'action=history' )
|
2004-03-20 15:03:26 +00:00
|
|
|
);
|
2006-10-12 10:34:49 +00:00
|
|
|
|
|
|
|
|
// purge variant urls as well
|
|
|
|
|
if($wgContLang->hasVariants()){
|
|
|
|
|
$variants = $wgContLang->getVariants();
|
|
|
|
|
foreach($variants as $vCode){
|
|
|
|
|
if($vCode==$wgContLang->getCode()) continue; // we don't want default variant
|
|
|
|
|
$urls[] = $this->getInternalURL('',$vCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $urls;
|
2004-03-20 15:03:26 +00:00
|
|
|
}
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2007-04-16 15:24:04 +00:00
|
|
|
public function purgeSquid() {
|
2006-06-18 12:42:16 +00:00
|
|
|
global $wgUseSquid;
|
|
|
|
|
if ( $wgUseSquid ) {
|
|
|
|
|
$urls = $this->getSquidURLs();
|
|
|
|
|
$u = new SquidUpdate( $urls );
|
|
|
|
|
$u->doUpdate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Move this page without authentication
|
|
|
|
|
* @param Title &$nt the new page Title
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function moveNoAuth( &$nt ) {
|
2004-03-23 10:22:49 +00:00
|
|
|
return $this->moveTo( $nt, false );
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2005-04-25 09:25:06 +00:00
|
|
|
* Check whether a given move operation would be valid.
|
2008-05-27 14:42:51 +00:00
|
|
|
* Returns true if ok, or a getUserPermissionsErrors()-like array otherwise
|
2004-09-30 05:21:20 +00:00
|
|
|
* @param Title &$nt the new title
|
|
|
|
|
* @param bool $auth indicates whether $wgUser's permissions
|
|
|
|
|
* should be checked
|
2008-06-24 13:03:16 +00:00
|
|
|
* @param string $reason is the log summary of the move, used for spam checking
|
2008-05-27 14:42:51 +00:00
|
|
|
* @return mixed True on success, getUserPermissionsErrors()-like array on failure
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2008-06-24 13:03:16 +00:00
|
|
|
public function isValidMoveOperation( &$nt, $auth = true, $reason = '' ) {
|
2008-05-27 16:03:21 +00:00
|
|
|
$errors = array();
|
2008-05-27 16:23:23 +00:00
|
|
|
if( !$nt ) {
|
2008-05-27 16:03:21 +00:00
|
|
|
// Normally we'd add this to $errors, but we'll get
|
|
|
|
|
// lots of syntax errors if $nt is not an object
|
2008-05-27 14:42:51 +00:00
|
|
|
return array(array('badtitletext'));
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2005-04-25 09:25:06 +00:00
|
|
|
if( $this->equals( $nt ) ) {
|
2008-05-27 16:10:43 +00:00
|
|
|
$errors[] = array('selfmove');
|
2005-04-25 09:25:06 +00:00
|
|
|
}
|
|
|
|
|
if( !$this->isMovable() || !$nt->isMovable() ) {
|
2008-05-27 16:10:43 +00:00
|
|
|
$errors[] = array('immobile_namespace');
|
2005-04-25 09:25:06 +00:00
|
|
|
}
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2004-04-29 02:14:54 +00:00
|
|
|
$oldid = $this->getArticleID();
|
|
|
|
|
$newid = $nt->getArticleID();
|
|
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
if ( strlen( $nt->getDBkey() ) < 1 ) {
|
2008-05-27 16:10:43 +00:00
|
|
|
$errors[] = array('articleexists');
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2005-04-25 09:25:06 +00:00
|
|
|
if ( ( '' == $this->getDBkey() ) ||
|
2004-03-23 10:22:49 +00:00
|
|
|
( !$oldid ) ||
|
2005-04-25 09:25:06 +00:00
|
|
|
( '' == $nt->getDBkey() ) ) {
|
2008-05-27 16:10:43 +00:00
|
|
|
$errors[] = array('badarticleerror');
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
|
|
|
|
|
2008-05-03 13:09:34 +00:00
|
|
|
// Image-specific checks
|
|
|
|
|
if( $this->getNamespace() == NS_IMAGE ) {
|
|
|
|
|
$file = wfLocalFile( $this );
|
|
|
|
|
if( $file->exists() ) {
|
|
|
|
|
if( $nt->getNamespace() != NS_IMAGE ) {
|
2008-05-27 16:10:43 +00:00
|
|
|
$errors[] = array('imagenocrossnamespace');
|
2008-05-03 13:09:34 +00:00
|
|
|
}
|
2008-07-10 08:16:58 +00:00
|
|
|
if( $nt->getText() != wfStripIllegalFilenameChars( $nt->getText() ) ) {
|
|
|
|
|
$errors[] = array('imageinvalidfilename');
|
|
|
|
|
}
|
2008-05-03 13:39:10 +00:00
|
|
|
if( !File::checkExtensionCompatibility( $file, $nt->getDbKey() ) ) {
|
2008-05-27 16:10:43 +00:00
|
|
|
$errors[] = array('imagetypemismatch');
|
2008-05-03 13:09:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-18 15:52:40 +00:00
|
|
|
if ( $auth ) {
|
|
|
|
|
global $wgUser;
|
2008-05-27 16:03:21 +00:00
|
|
|
$errors = array_merge($errors,
|
|
|
|
|
$this->getUserPermissionsErrors('move', $wgUser),
|
2008-01-18 16:19:38 +00:00
|
|
|
$this->getUserPermissionsErrors('edit', $wgUser),
|
|
|
|
|
$nt->getUserPermissionsErrors('move', $wgUser),
|
|
|
|
|
$nt->getUserPermissionsErrors('edit', $wgUser));
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2007-12-08 18:30:00 +00:00
|
|
|
global $wgUser;
|
|
|
|
|
$err = null;
|
2008-06-24 13:03:16 +00:00
|
|
|
if( !wfRunHooks( 'AbortMove', array( $this, $nt, $wgUser, &$err, $reason ) ) ) {
|
2008-05-27 16:10:43 +00:00
|
|
|
$errors[] = array('hookaborted', $err);
|
2007-12-08 18:30:00 +00:00
|
|
|
}
|
|
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
# The move is allowed only if (1) the target doesn't exist, or
|
|
|
|
|
# (2) the target is a redirect to the source, and has no history
|
|
|
|
|
# (so we can undo bad moves right after they're done).
|
|
|
|
|
|
|
|
|
|
if ( 0 != $newid ) { # Target exists; check for validity
|
|
|
|
|
if ( ! $this->isValidMoveTarget( $nt ) ) {
|
2008-05-27 16:10:43 +00:00
|
|
|
$errors[] = array('articleexists');
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2007-12-15 23:51:54 +00:00
|
|
|
} else {
|
|
|
|
|
$tp = $nt->getTitleProtection();
|
2008-05-12 14:12:51 +00:00
|
|
|
$right = ( $tp['pt_create_perm'] == 'sysop' ) ? 'protect' : $tp['pt_create_perm'];
|
|
|
|
|
if ( $tp and !$wgUser->isAllowed( $right ) ) {
|
2008-05-27 16:10:43 +00:00
|
|
|
$errors[] = array('cantmove-titleprotected');
|
2007-12-15 23:51:54 +00:00
|
|
|
}
|
2005-04-25 09:25:06 +00:00
|
|
|
}
|
2008-05-27 16:03:21 +00:00
|
|
|
if(empty($errors))
|
|
|
|
|
return true;
|
|
|
|
|
return $errors;
|
2005-04-25 09:25:06 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-04-25 09:25:06 +00:00
|
|
|
/**
|
|
|
|
|
* Move a title to a new location
|
|
|
|
|
* @param Title &$nt the new title
|
|
|
|
|
* @param bool $auth indicates whether $wgUser's permissions
|
|
|
|
|
* should be checked
|
2007-11-06 16:14:24 +00:00
|
|
|
* @param string $reason The reason for the move
|
2007-11-23 11:27:09 +00:00
|
|
|
* @param bool $createRedirect Whether to create a redirect from the old title to the new title.
|
|
|
|
|
* Ignored if the user doesn't have the suppressredirect right.
|
2008-05-27 14:42:51 +00:00
|
|
|
* @return mixed true on success, getUserPermissionsErrors()-like array on failure
|
2005-04-25 09:25:06 +00:00
|
|
|
*/
|
2007-11-06 16:14:24 +00:00
|
|
|
public function moveTo( &$nt, $auth = true, $reason = '', $createRedirect = true ) {
|
2008-06-24 13:03:16 +00:00
|
|
|
$err = $this->isValidMoveOperation( $nt, $auth, $reason );
|
2008-05-30 19:59:47 +00:00
|
|
|
if( is_array( $err ) ) {
|
2005-04-25 09:25:06 +00:00
|
|
|
return $err;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-06-01 02:31:45 +00:00
|
|
|
$pageid = $this->getArticleID();
|
2005-04-25 09:25:06 +00:00
|
|
|
if( $nt->exists() ) {
|
2008-05-03 13:09:34 +00:00
|
|
|
$err = $this->moveOverExistingRedirect( $nt, $reason, $createRedirect );
|
2007-11-06 16:14:24 +00:00
|
|
|
$pageCountChange = ($createRedirect ? 0 : -1);
|
2004-03-23 10:22:49 +00:00
|
|
|
} else { # Target didn't exist, do normal move.
|
2008-05-03 13:09:34 +00:00
|
|
|
$err = $this->moveToNewTitle( $nt, $reason, $createRedirect );
|
2007-11-06 16:14:24 +00:00
|
|
|
$pageCountChange = ($createRedirect ? 1 : 0);
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2008-05-30 19:59:47 +00:00
|
|
|
|
|
|
|
|
if( is_array( $err ) ) {
|
2008-05-03 13:09:34 +00:00
|
|
|
return $err;
|
|
|
|
|
}
|
2005-06-01 02:31:45 +00:00
|
|
|
$redirid = $this->getArticleID();
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2008-01-11 20:52:54 +00:00
|
|
|
// Category memberships include a sort key which may be customized.
|
|
|
|
|
// If it's left as the default (the page title), we need to update
|
|
|
|
|
// the sort key to match the new title.
|
|
|
|
|
//
|
|
|
|
|
// Be careful to avoid resetting cl_timestamp, which may disturb
|
|
|
|
|
// time-based lists on some sites.
|
|
|
|
|
//
|
|
|
|
|
// Warning -- if the sort key is *explicitly* set to the old title,
|
|
|
|
|
// we can't actually distinguish it from a default here, and it'll
|
|
|
|
|
// be set to the new title even though it really shouldn't.
|
|
|
|
|
// It'll get corrected on the next edit, but resetting cl_timestamp.
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2008-01-11 20:52:54 +00:00
|
|
|
$dbw->update( 'categorylinks',
|
|
|
|
|
array(
|
|
|
|
|
'cl_sortkey' => $nt->getPrefixedText(),
|
|
|
|
|
'cl_timestamp=cl_timestamp' ),
|
|
|
|
|
array(
|
|
|
|
|
'cl_from' => $pageid,
|
|
|
|
|
'cl_sortkey' => $this->getPrefixedText() ),
|
|
|
|
|
__METHOD__ );
|
2004-08-06 16:25:27 +00:00
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
# Update watchlists
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
$oldnamespace = $this->getNamespace() & ~1;
|
|
|
|
|
$newnamespace = $nt->getNamespace() & ~1;
|
|
|
|
|
$oldtitle = $this->getDBkey();
|
|
|
|
|
$newtitle = $nt->getDBkey();
|
|
|
|
|
|
2004-08-14 18:23:50 +00:00
|
|
|
if( $oldnamespace != $newnamespace || $oldtitle != $newtitle ) {
|
2004-03-23 10:22:49 +00:00
|
|
|
WatchedItem::duplicateEntries( $this, $nt );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Update search engine
|
2005-06-01 02:31:45 +00:00
|
|
|
$u = new SearchUpdate( $pageid, $nt->getPrefixedDBkey() );
|
2004-03-23 10:22:49 +00:00
|
|
|
$u->doUpdate();
|
2005-06-01 02:31:45 +00:00
|
|
|
$u = new SearchUpdate( $redirid, $this->getPrefixedDBkey(), '' );
|
2004-03-23 10:22:49 +00:00
|
|
|
$u->doUpdate();
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-06-19 00:21:49 +00:00
|
|
|
# Update site_stats
|
2007-01-08 15:32:58 +00:00
|
|
|
if( $this->isContentPage() && !$nt->isContentPage() ) {
|
|
|
|
|
# No longer a content page
|
|
|
|
|
# Not viewed, edited, removing
|
|
|
|
|
$u = new SiteStatsUpdate( 0, 1, -1, $pageCountChange );
|
|
|
|
|
} elseif( !$this->isContentPage() && $nt->isContentPage() ) {
|
|
|
|
|
# Now a content page
|
|
|
|
|
# Not viewed, edited, adding
|
2005-07-01 10:44:48 +00:00
|
|
|
$u = new SiteStatsUpdate( 0, 1, +1, $pageCountChange );
|
2007-01-08 15:32:58 +00:00
|
|
|
} elseif( $pageCountChange ) {
|
|
|
|
|
# Redirect added
|
2005-06-19 00:21:49 +00:00
|
|
|
$u = new SiteStatsUpdate( 0, 0, 0, 1 );
|
2007-01-08 15:32:58 +00:00
|
|
|
} else {
|
|
|
|
|
# Nothing special
|
2005-06-19 00:21:49 +00:00
|
|
|
$u = false;
|
|
|
|
|
}
|
2007-01-08 15:32:58 +00:00
|
|
|
if( $u )
|
2005-06-19 00:21:49 +00:00
|
|
|
$u->doUpdate();
|
2007-12-20 06:03:46 +00:00
|
|
|
# Update message cache for interface messages
|
2007-12-20 03:09:19 +00:00
|
|
|
if( $nt->getNamespace() == NS_MEDIAWIKI ) {
|
|
|
|
|
global $wgMessageCache;
|
2008-02-09 11:45:53 +00:00
|
|
|
$oldarticle = new Article( $this );
|
|
|
|
|
$wgMessageCache->replace( $this->getDBkey(), $oldarticle->getContent() );
|
2007-12-20 03:09:19 +00:00
|
|
|
$newarticle = new Article( $nt );
|
|
|
|
|
$wgMessageCache->replace( $nt->getDBkey(), $newarticle->getContent() );
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2005-10-29 06:02:08 +00:00
|
|
|
global $wgUser;
|
2005-06-01 02:31:45 +00:00
|
|
|
wfRunHooks( 'TitleMoveComplete', array( &$this, &$nt, &$wgUser, $pageid, $redirid ) );
|
2004-03-23 10:22:49 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Move page to a title which is at present a redirect to the
|
|
|
|
|
* source page
|
|
|
|
|
*
|
|
|
|
|
* @param Title &$nt the page to move to, which should currently
|
|
|
|
|
* be a redirect
|
2007-11-06 16:14:24 +00:00
|
|
|
* @param string $reason The reason for the move
|
2007-11-23 11:27:09 +00:00
|
|
|
* @param bool $createRedirect Whether to leave a redirect at the old title.
|
|
|
|
|
* Ignored if the user doesn't have the suppressredirect right
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-11-06 16:14:24 +00:00
|
|
|
private function moveOverExistingRedirect( &$nt, $reason = '', $createRedirect = true ) {
|
2007-11-23 11:27:09 +00:00
|
|
|
global $wgUseSquid, $wgUser;
|
2004-08-16 20:14:35 +00:00
|
|
|
$fname = 'Title::moveOverExistingRedirect';
|
2007-01-22 16:53:28 +00:00
|
|
|
$comment = wfMsgForContent( '1movedto2_redir', $this->getPrefixedText(), $nt->getPrefixedText() );
|
2005-04-03 14:45:42 +00:00
|
|
|
|
|
|
|
|
if ( $reason ) {
|
|
|
|
|
$comment .= ": $reason";
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
$now = wfTimestampNow();
|
2004-03-23 10:22:49 +00:00
|
|
|
$newid = $nt->getArticleID();
|
|
|
|
|
$oldid = $this->getArticleID();
|
2004-07-10 03:09:26 +00:00
|
|
|
|
2008-05-25 05:06:50 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
$dbw->begin();
|
2008-05-03 13:09:34 +00:00
|
|
|
|
2004-12-10 05:56:44 +00:00
|
|
|
# Delete the old redirect. We don't save it to history since
|
|
|
|
|
# by definition if we've got here it's rather uninteresting.
|
|
|
|
|
# We have to remove it so that the next step doesn't trigger
|
|
|
|
|
# a conflict on the unique namespace+title index...
|
2004-12-19 08:00:50 +00:00
|
|
|
$dbw->delete( 'page', array( 'page_id' => $newid ), $fname );
|
2008-02-09 12:40:02 +00:00
|
|
|
if ( !$dbw->cascadingDeletes() ) {
|
|
|
|
|
$dbw->delete( 'revision', array( 'rev_page' => $newid ), __METHOD__ );
|
|
|
|
|
global $wgUseTrackbacks;
|
|
|
|
|
if ($wgUseTrackbacks)
|
|
|
|
|
$dbw->delete( 'trackbacks', array( 'tb_page' => $newid ), __METHOD__ );
|
|
|
|
|
$dbw->delete( 'pagelinks', array( 'pl_from' => $newid ), __METHOD__ );
|
|
|
|
|
$dbw->delete( 'imagelinks', array( 'il_from' => $newid ), __METHOD__ );
|
|
|
|
|
$dbw->delete( 'categorylinks', array( 'cl_from' => $newid ), __METHOD__ );
|
|
|
|
|
$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( 'redirect', array( 'rd_from' => $newid ), __METHOD__ );
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-03-28 10:47:12 +00:00
|
|
|
# Save a null revision in the page's history notifying of the move
|
2006-01-15 07:04:28 +00:00
|
|
|
$nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true );
|
2008-05-17 15:53:58 +00:00
|
|
|
$nullRevId = $nullRevision->insertOn( $dbw );
|
2008-05-22 01:03:45 +00:00
|
|
|
|
2008-05-30 21:42:05 +00:00
|
|
|
$article = new Article( $this );
|
2008-05-25 18:20:33 +00:00
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array($article, $nullRevision, false) );
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
# Change the name of the target page:
|
2004-12-19 08:00:50 +00:00
|
|
|
$dbw->update( 'page',
|
2005-07-01 10:44:48 +00:00
|
|
|
/* SET */ array(
|
|
|
|
|
'page_touched' => $dbw->timestamp($now),
|
2004-12-19 08:00:50 +00:00
|
|
|
'page_namespace' => $nt->getNamespace(),
|
2005-03-28 10:47:12 +00:00
|
|
|
'page_title' => $nt->getDBkey(),
|
|
|
|
|
'page_latest' => $nullRevId,
|
2005-07-01 10:44:48 +00:00
|
|
|
),
|
2004-12-19 08:00:50 +00:00
|
|
|
/* WHERE */ array( 'page_id' => $oldid ),
|
2004-03-23 10:22:49 +00:00
|
|
|
$fname
|
|
|
|
|
);
|
2008-02-09 11:45:53 +00:00
|
|
|
$nt->resetArticleID( $oldid );
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2004-12-10 05:56:44 +00:00
|
|
|
# Recreate the redirect, this time in the other direction.
|
2008-05-25 05:06:50 +00:00
|
|
|
if( $createRedirect || !$wgUser->isAllowed('suppressredirect') ) {
|
2007-11-06 16:14:24 +00:00
|
|
|
$mwRedir = MagicWord::get( 'redirect' );
|
|
|
|
|
$redirectText = $mwRedir->getSynonym( 0 ) . ' [[' . $nt->getPrefixedText() . "]]\n";
|
|
|
|
|
$redirectArticle = new Article( $this );
|
|
|
|
|
$newid = $redirectArticle->insertOn( $dbw );
|
|
|
|
|
$redirectRevision = new Revision( array(
|
|
|
|
|
'page' => $newid,
|
|
|
|
|
'comment' => $comment,
|
|
|
|
|
'text' => $redirectText ) );
|
2008-05-17 15:53:58 +00:00
|
|
|
$redirectRevision->insertOn( $dbw );
|
2007-11-06 16:14:24 +00:00
|
|
|
$redirectArticle->updateRevisionOn( $dbw, $redirectRevision, 0 );
|
2008-05-22 01:03:45 +00:00
|
|
|
|
|
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array($redirectArticle, $redirectRevision, false) );
|
2007-11-06 16:14:24 +00:00
|
|
|
|
|
|
|
|
# Now, we record the link from the redirect to the new title.
|
|
|
|
|
# It should have no other outgoing links...
|
|
|
|
|
$dbw->delete( 'pagelinks', array( 'pl_from' => $newid ), $fname );
|
|
|
|
|
$dbw->insert( 'pagelinks',
|
|
|
|
|
array(
|
|
|
|
|
'pl_from' => $newid,
|
|
|
|
|
'pl_namespace' => $nt->getNamespace(),
|
2008-01-14 09:26:36 +00:00
|
|
|
'pl_title' => $nt->getDBkey() ),
|
2007-11-06 16:14:24 +00:00
|
|
|
$fname );
|
2008-02-09 11:45:53 +00:00
|
|
|
} else {
|
|
|
|
|
$this->resetArticleID( 0 );
|
2007-11-06 16:14:24 +00:00
|
|
|
}
|
2008-05-25 05:06:50 +00:00
|
|
|
|
|
|
|
|
# Move an image if this is a file
|
|
|
|
|
if( $this->getNamespace() == NS_IMAGE ) {
|
|
|
|
|
$file = wfLocalFile( $this );
|
|
|
|
|
if( $file->exists() ) {
|
|
|
|
|
$status = $file->move( $nt );
|
|
|
|
|
if( !$status->isOk() ) {
|
|
|
|
|
$dbw->rollback();
|
2008-05-30 19:59:47 +00:00
|
|
|
return $status->getErrorsArray();
|
2008-05-25 05:06:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$dbw->commit();
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2005-01-31 04:07:56 +00:00
|
|
|
# Log the move
|
|
|
|
|
$log = new LogPage( 'move' );
|
2005-04-03 14:45:42 +00:00
|
|
|
$log->addEntry( 'move_redir', $this, $reason, array( 1 => $nt->getPrefixedText() ) );
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
# Purge squid
|
|
|
|
|
if ( $wgUseSquid ) {
|
|
|
|
|
$urls = array_merge( $nt->getSquidURLs(), $this->getSquidURLs() );
|
|
|
|
|
$u = new SquidUpdate( $urls );
|
|
|
|
|
$u->doUpdate();
|
|
|
|
|
}
|
2008-05-30 19:59:47 +00:00
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Move page to non-existing title.
|
|
|
|
|
* @param Title &$nt the new Title
|
2007-11-06 16:14:24 +00:00
|
|
|
* @param string $reason The reason for the move
|
|
|
|
|
* @param bool $createRedirect Whether to create a redirect from the old title to the new title
|
2007-11-23 11:27:09 +00:00
|
|
|
* Ignored if the user doesn't have the suppressredirect right
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-11-06 16:14:24 +00:00
|
|
|
private function moveToNewTitle( &$nt, $reason = '', $createRedirect = true ) {
|
2007-11-23 11:27:09 +00:00
|
|
|
global $wgUseSquid, $wgUser;
|
2004-08-16 20:14:35 +00:00
|
|
|
$fname = 'MovePageForm::moveToNewTitle';
|
2005-01-14 03:24:37 +00:00
|
|
|
$comment = wfMsgForContent( '1movedto2', $this->getPrefixedText(), $nt->getPrefixedText() );
|
2005-04-03 14:45:42 +00:00
|
|
|
if ( $reason ) {
|
2008-07-15 21:13:34 +00:00
|
|
|
$comment .= ": $reason";
|
2005-04-03 14:45:42 +00:00
|
|
|
}
|
2004-03-23 10:22:49 +00:00
|
|
|
|
|
|
|
|
$newid = $nt->getArticleID();
|
|
|
|
|
$oldid = $this->getArticleID();
|
2008-05-25 05:06:50 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2008-05-25 05:06:50 +00:00
|
|
|
$dbw->begin();
|
2004-09-06 09:57:30 +00:00
|
|
|
$now = $dbw->timestamp();
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2005-03-28 10:47:12 +00:00
|
|
|
# Save a null revision in the page's history notifying of the move
|
2006-01-15 07:04:28 +00:00
|
|
|
$nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true );
|
2008-05-17 15:53:58 +00:00
|
|
|
$nullRevId = $nullRevision->insertOn( $dbw );
|
2008-05-22 01:03:45 +00:00
|
|
|
|
2008-05-30 21:42:05 +00:00
|
|
|
$article = new Article( $this );
|
2008-05-25 18:20:33 +00:00
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array($article, $nullRevision, false) );
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2008-02-09 11:45:53 +00:00
|
|
|
# Rename page entry
|
2004-12-19 08:00:50 +00:00
|
|
|
$dbw->update( 'page',
|
2004-03-23 10:22:49 +00:00
|
|
|
/* SET */ array(
|
2005-03-28 10:47:12 +00:00
|
|
|
'page_touched' => $now,
|
2004-12-19 08:00:50 +00:00
|
|
|
'page_namespace' => $nt->getNamespace(),
|
2005-03-28 10:47:12 +00:00
|
|
|
'page_title' => $nt->getDBkey(),
|
|
|
|
|
'page_latest' => $nullRevId,
|
2004-03-23 10:22:49 +00:00
|
|
|
),
|
2004-12-19 08:00:50 +00:00
|
|
|
/* WHERE */ array( 'page_id' => $oldid ),
|
2004-03-23 10:22:49 +00:00
|
|
|
$fname
|
|
|
|
|
);
|
2008-02-09 11:45:53 +00:00
|
|
|
$nt->resetArticleID( $oldid );
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2008-05-25 05:06:50 +00:00
|
|
|
if( $createRedirect || !$wgUser->isAllowed('suppressredirect') ) {
|
2007-11-06 16:14:24 +00:00
|
|
|
# Insert redirect
|
|
|
|
|
$mwRedir = MagicWord::get( 'redirect' );
|
|
|
|
|
$redirectText = $mwRedir->getSynonym( 0 ) . ' [[' . $nt->getPrefixedText() . "]]\n";
|
|
|
|
|
$redirectArticle = new Article( $this );
|
|
|
|
|
$newid = $redirectArticle->insertOn( $dbw );
|
|
|
|
|
$redirectRevision = new Revision( array(
|
|
|
|
|
'page' => $newid,
|
|
|
|
|
'comment' => $comment,
|
|
|
|
|
'text' => $redirectText ) );
|
2008-05-17 15:53:58 +00:00
|
|
|
$redirectRevision->insertOn( $dbw );
|
2007-11-06 16:14:24 +00:00
|
|
|
$redirectArticle->updateRevisionOn( $dbw, $redirectRevision, 0 );
|
2008-05-22 01:03:45 +00:00
|
|
|
|
|
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array($redirectArticle, $redirectRevision, false) );
|
2008-02-09 11:45:53 +00:00
|
|
|
|
2007-11-06 16:14:24 +00:00
|
|
|
# Record the just-created redirect's linking to the page
|
|
|
|
|
$dbw->insert( 'pagelinks',
|
|
|
|
|
array(
|
|
|
|
|
'pl_from' => $newid,
|
|
|
|
|
'pl_namespace' => $nt->getNamespace(),
|
|
|
|
|
'pl_title' => $nt->getDBkey() ),
|
|
|
|
|
$fname );
|
2008-02-09 11:45:53 +00:00
|
|
|
} else {
|
|
|
|
|
$this->resetArticleID( 0 );
|
2007-11-06 16:14:24 +00:00
|
|
|
}
|
2008-05-25 05:06:50 +00:00
|
|
|
|
|
|
|
|
# Move an image if this is a file
|
|
|
|
|
if( $this->getNamespace() == NS_IMAGE ) {
|
|
|
|
|
$file = wfLocalFile( $this );
|
|
|
|
|
if( $file->exists() ) {
|
|
|
|
|
$status = $file->move( $nt );
|
|
|
|
|
if( !$status->isOk() ) {
|
|
|
|
|
$dbw->rollback();
|
2008-05-30 19:59:47 +00:00
|
|
|
return $status->getErrorsArray();
|
2008-05-25 05:06:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$dbw->commit();
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2005-01-31 04:07:56 +00:00
|
|
|
# Log the move
|
|
|
|
|
$log = new LogPage( 'move' );
|
2005-04-03 14:45:42 +00:00
|
|
|
$log->addEntry( 'move', $this, $reason, array( 1 => $nt->getPrefixedText()) );
|
2004-06-05 04:52:33 +00:00
|
|
|
|
2005-05-31 07:21:31 +00:00
|
|
|
# Purge caches as per article creation
|
2004-03-23 10:22:49 +00:00
|
|
|
Article::onArticleCreate( $nt );
|
|
|
|
|
|
|
|
|
|
# Purge old title from squid
|
|
|
|
|
# The new title, and links to the new title, are purged in Article::onArticleCreate()
|
2006-06-18 12:42:16 +00:00
|
|
|
$this->purgeSquid();
|
2008-05-30 19:59:47 +00:00
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Checks if $this can be moved to a given Title
|
|
|
|
|
* - Selects for update, so don't call it unless you mean business
|
|
|
|
|
*
|
|
|
|
|
* @param Title &$nt the new title to check
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isValidMoveTarget( $nt ) {
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-08-16 20:14:35 +00:00
|
|
|
$fname = 'Title::isValidMoveTarget';
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2008-05-03 13:09:34 +00:00
|
|
|
# Is it an existsing file?
|
|
|
|
|
if( $nt->getNamespace() == NS_IMAGE ) {
|
|
|
|
|
$file = wfLocalFile( $nt );
|
|
|
|
|
if( $file->exists() ) {
|
|
|
|
|
wfDebug( __METHOD__ . ": file exists\n" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
# Is it a redirect?
|
|
|
|
|
$id = $nt->getArticleID();
|
2005-03-28 10:47:12 +00:00
|
|
|
$obj = $dbw->selectRow( array( 'page', 'revision', 'text'),
|
2005-09-02 04:44:15 +00:00
|
|
|
array( 'page_is_redirect','old_text','old_flags' ),
|
2005-03-28 10:47:12 +00:00
|
|
|
array( 'page_id' => $id, 'page_latest=rev_id', 'rev_text_id=old_id' ),
|
2004-12-19 08:00:50 +00:00
|
|
|
$fname, 'FOR UPDATE' );
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2005-07-01 10:44:48 +00:00
|
|
|
if ( !$obj || 0 == $obj->page_is_redirect ) {
|
2004-03-23 10:22:49 +00:00
|
|
|
# Not a redirect
|
2006-06-28 20:31:04 +00:00
|
|
|
wfDebug( __METHOD__ . ": not a redirect\n" );
|
2005-07-01 10:44:48 +00:00
|
|
|
return false;
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2005-09-02 04:44:15 +00:00
|
|
|
$text = Revision::getRevisionText( $obj );
|
2004-03-23 10:22:49 +00:00
|
|
|
|
|
|
|
|
# Does the redirect point to the source?
|
2006-06-28 20:31:04 +00:00
|
|
|
# Or is it a broken self-redirect, usually caused by namespace collisions?
|
2006-11-29 11:43:58 +00:00
|
|
|
$m = array();
|
2005-09-02 04:44:15 +00:00
|
|
|
if ( preg_match( "/\\[\\[\\s*([^\\]\\|]*)]]/", $text, $m ) ) {
|
2004-03-23 10:22:49 +00:00
|
|
|
$redirTitle = Title::newFromText( $m[1] );
|
2004-08-08 01:30:39 +00:00
|
|
|
if( !is_object( $redirTitle ) ||
|
2006-06-28 20:31:04 +00:00
|
|
|
( $redirTitle->getPrefixedDBkey() != $this->getPrefixedDBkey() &&
|
|
|
|
|
$redirTitle->getPrefixedDBkey() != $nt->getPrefixedDBkey() ) ) {
|
|
|
|
|
wfDebug( __METHOD__ . ": redirect points to other page\n" );
|
2004-03-23 10:22:49 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2005-09-02 04:44:15 +00:00
|
|
|
} else {
|
|
|
|
|
# Fail safe
|
2006-06-28 20:31:04 +00:00
|
|
|
wfDebug( __METHOD__ . ": failsafe\n" );
|
2005-09-02 04:44:15 +00:00
|
|
|
return false;
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Does the article have a history?
|
2004-12-19 08:00:50 +00:00
|
|
|
$row = $dbw->selectRow( array( 'page', 'revision'),
|
2005-07-01 10:44:48 +00:00
|
|
|
array( 'rev_id' ),
|
2004-12-19 08:00:50 +00:00
|
|
|
array( 'page_namespace' => $nt->getNamespace(),
|
|
|
|
|
'page_title' => $nt->getDBkey(),
|
|
|
|
|
'page_id=rev_page AND page_latest != rev_id'
|
2005-07-01 10:44:48 +00:00
|
|
|
), $fname, 'FOR UPDATE'
|
2004-03-23 10:22:49 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
# Return true if there was no history
|
|
|
|
|
return $row === false;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-07-05 18:20:46 +00:00
|
|
|
/**
|
|
|
|
|
* Can this title be added to a user's watchlist?
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function isWatchable() {
|
|
|
|
|
return !$this->isExternal()
|
2008-03-21 23:13:34 +00:00
|
|
|
&& MWNamespace::isWatchable( $this->getNamespace() );
|
2007-07-05 18:20:46 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get categories to which this Title belongs and return an array of
|
|
|
|
|
* categories' names.
|
|
|
|
|
*
|
|
|
|
|
* @return array an array of parents in the form:
|
|
|
|
|
* $parent => $currentarticle
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getParentCategories() {
|
2006-03-07 01:10:39 +00:00
|
|
|
global $wgContLang;
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2004-06-06 02:06:46 +00:00
|
|
|
$titlekey = $this->getArticleId();
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2004-07-10 03:09:26 +00:00
|
|
|
$categorylinks = $dbr->tableName( 'categorylinks' );
|
|
|
|
|
|
2004-08-23 00:49:02 +00:00
|
|
|
# NEW SQL
|
2004-11-20 03:35:00 +00:00
|
|
|
$sql = "SELECT * FROM $categorylinks"
|
2004-08-23 00:49:02 +00:00
|
|
|
." WHERE cl_from='$titlekey'"
|
|
|
|
|
." AND cl_from <> '0'"
|
|
|
|
|
." ORDER BY cl_sortkey";
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2008-06-26 20:26:56 +00:00
|
|
|
$res = $dbr->query( $sql );
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2008-06-26 20:26:56 +00:00
|
|
|
if( $dbr->numRows( $res ) > 0 ) {
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row )
|
|
|
|
|
//$data[] = Title::newFromText($wgContLang->getNSText ( NS_CATEGORY ).':'.$row->cl_to);
|
|
|
|
|
$data[$wgContLang->getNSText( NS_CATEGORY ).':'.$row->cl_to] = $this->getFullText();
|
2008-06-26 20:26:56 +00:00
|
|
|
$dbr->freeResult( $res );
|
2004-06-06 02:06:46 +00:00
|
|
|
} else {
|
2007-10-23 14:19:48 +00:00
|
|
|
$data = array();
|
2004-06-06 02:06:46 +00:00
|
|
|
}
|
|
|
|
|
return $data;
|
|
|
|
|
}
|
2004-06-07 07:55:27 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2004-11-20 03:35:00 +00:00
|
|
|
* Get a tree of parent categories
|
|
|
|
|
* @param array $children an array with the children in the keys, to check for circular refs
|
2004-09-30 05:21:20 +00:00
|
|
|
* @return array
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getParentCategoryTree( $children = array() ) {
|
2008-02-28 08:14:49 +00:00
|
|
|
$stack = array();
|
2004-08-23 00:49:02 +00:00
|
|
|
$parents = $this->getParentCategories();
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2008-05-18 16:09:56 +00:00
|
|
|
if( $parents ) {
|
2008-06-26 20:26:56 +00:00
|
|
|
foreach( $parents as $parent => $current ) {
|
2004-11-20 03:35:00 +00:00
|
|
|
if ( array_key_exists( $parent, $children ) ) {
|
|
|
|
|
# Circular reference
|
|
|
|
|
$stack[$parent] = array();
|
|
|
|
|
} else {
|
|
|
|
|
$nt = Title::newFromText($parent);
|
2006-08-24 17:35:42 +00:00
|
|
|
if ( $nt ) {
|
|
|
|
|
$stack[$parent] = $nt->getParentCategoryTree( $children + array($parent => 1) );
|
|
|
|
|
}
|
2004-11-20 03:35:00 +00:00
|
|
|
}
|
2004-06-06 02:06:46 +00:00
|
|
|
}
|
2004-08-23 00:49:02 +00:00
|
|
|
return $stack;
|
2004-06-07 07:55:27 +00:00
|
|
|
} else {
|
2004-08-23 00:49:02 +00:00
|
|
|
return array();
|
2004-06-06 02:06:46 +00:00
|
|
|
}
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get an associative array for selecting this title from
|
2006-01-09 03:52:24 +00:00
|
|
|
* the "page" table
|
2004-09-30 05:21:20 +00:00
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function pageCond() {
|
2006-01-09 03:52:24 +00:00
|
|
|
return array( 'page_namespace' => $this->mNamespace, 'page_title' => $this->mDbkeyform );
|
2004-07-18 08:48:43 +00:00
|
|
|
}
|
2004-10-02 19:49:54 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the revision ID of the previous revision
|
|
|
|
|
*
|
2006-06-23 11:09:40 +00:00
|
|
|
* @param integer $revision Revision ID. Get the revision that was before this one.
|
2008-05-15 14:53:02 +00:00
|
|
|
* @param integer $flags, GAID_FOR_UPDATE
|
2006-12-06 08:28:44 +00:00
|
|
|
* @return integer $oldrevision|false
|
2004-10-02 19:49:54 +00:00
|
|
|
*/
|
2008-05-15 14:53:02 +00:00
|
|
|
public function getPreviousRevisionID( $revision, $flags=0 ) {
|
|
|
|
|
$db = ($flags & GAID_FOR_UPDATE) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
|
|
|
|
|
return $db->selectField( 'revision', 'rev_id',
|
2008-05-23 09:00:08 +00:00
|
|
|
array(
|
|
|
|
|
'rev_page' => $this->getArticleId($flags),
|
|
|
|
|
'rev_id < ' . intval( $revision )
|
|
|
|
|
),
|
|
|
|
|
__METHOD__,
|
|
|
|
|
array( 'ORDER BY' => 'rev_id DESC' )
|
|
|
|
|
);
|
2004-10-02 19:49:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the revision ID of the next revision
|
|
|
|
|
*
|
|
|
|
|
* @param integer $revision Revision ID. Get the revision that was after this one.
|
2008-05-15 14:53:02 +00:00
|
|
|
* @param integer $flags, GAID_FOR_UPDATE
|
2006-12-06 08:28:44 +00:00
|
|
|
* @return integer $oldrevision|false
|
2004-10-02 19:49:54 +00:00
|
|
|
*/
|
2008-05-15 14:53:02 +00:00
|
|
|
public function getNextRevisionID( $revision, $flags=0 ) {
|
|
|
|
|
$db = ($flags & GAID_FOR_UPDATE) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
|
|
|
|
|
return $db->selectField( 'revision', 'rev_id',
|
2008-05-23 09:00:08 +00:00
|
|
|
array(
|
|
|
|
|
'rev_page' => $this->getArticleId($flags),
|
|
|
|
|
'rev_id > ' . intval( $revision )
|
|
|
|
|
),
|
|
|
|
|
__METHOD__,
|
|
|
|
|
array( 'ORDER BY' => 'rev_id' )
|
|
|
|
|
);
|
2004-10-02 19:49:54 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2006-12-06 08:28:44 +00:00
|
|
|
/**
|
|
|
|
|
* Get the number of revisions between the given revision IDs.
|
2008-04-10 17:55:12 +00:00
|
|
|
* Used for diffs and other things that really need it.
|
2006-12-06 08:28:44 +00:00
|
|
|
*
|
|
|
|
|
* @param integer $old Revision ID.
|
|
|
|
|
* @param integer $new Revision ID.
|
|
|
|
|
* @return integer Number of revisions between these IDs.
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function countRevisionsBetween( $old, $new ) {
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2006-12-06 08:28:44 +00:00
|
|
|
return $dbr->selectField( 'revision', 'count(*)',
|
|
|
|
|
'rev_page = ' . intval( $this->getArticleId() ) .
|
|
|
|
|
' AND rev_id > ' . intval( $old ) .
|
2008-04-10 17:49:59 +00:00
|
|
|
' AND rev_id < ' . intval( $new ),
|
2008-04-10 17:55:12 +00:00
|
|
|
__METHOD__,
|
|
|
|
|
array( 'USE INDEX' => 'PRIMARY' ) );
|
2006-12-06 08:28:44 +00:00
|
|
|
}
|
|
|
|
|
|
2005-02-21 11:28:07 +00:00
|
|
|
/**
|
|
|
|
|
* Compare with another title.
|
|
|
|
|
*
|
|
|
|
|
* @param Title $title
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2008-07-28 22:52:14 +00:00
|
|
|
public function equals( Title $title ) {
|
2006-02-18 19:41:01 +00:00
|
|
|
// Note: === is necessary for proper matching of number-like titles.
|
|
|
|
|
return $this->getInterwiki() === $title->getInterwiki()
|
2005-02-21 11:28:07 +00:00
|
|
|
&& $this->getNamespace() == $title->getNamespace()
|
2008-01-14 09:13:04 +00:00
|
|
|
&& $this->getDBkey() === $title->getDBkey();
|
2005-02-21 11:28:07 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-05-08 23:16:36 +00:00
|
|
|
/**
|
|
|
|
|
* Callback for usort() to do title sorts by (namespace, title)
|
|
|
|
|
*/
|
|
|
|
|
static function compare( $a, $b ) {
|
|
|
|
|
if( $a->getNamespace() == $b->getNamespace() ) {
|
|
|
|
|
return strcmp( $a->getText(), $b->getText() );
|
|
|
|
|
} else {
|
|
|
|
|
return $a->getNamespace() - $b->getNamespace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-07-05 18:20:46 +00:00
|
|
|
/**
|
|
|
|
|
* Return a string representation of this title
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public function __toString() {
|
|
|
|
|
return $this->getPrefixedText();
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-04-25 09:25:06 +00:00
|
|
|
/**
|
|
|
|
|
* Check if page exists
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function exists() {
|
2005-04-25 09:25:06 +00:00
|
|
|
return $this->getArticleId() != 0;
|
|
|
|
|
}
|
2004-10-02 19:49:54 +00:00
|
|
|
|
2005-04-27 07:48:14 +00:00
|
|
|
/**
|
2007-07-18 07:18:08 +00:00
|
|
|
* Do we know that this title definitely exists, or should we otherwise
|
|
|
|
|
* consider that it exists?
|
2005-07-01 10:44:48 +00:00
|
|
|
*
|
2007-07-18 07:18:08 +00:00
|
|
|
* @return bool
|
2005-04-27 07:48:14 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isAlwaysKnown() {
|
2007-11-28 15:09:36 +00:00
|
|
|
// If the page is form Mediawiki:message/lang, calling wfMsgWeirdKey causes
|
|
|
|
|
// the full l10n of that language to be loaded. That takes much memory and
|
|
|
|
|
// isn't needed. So we strip the language part away.
|
|
|
|
|
// Also, extension messages which are not loaded, are shown as red, because
|
|
|
|
|
// we don't call MessageCache::loadAllMessages.
|
|
|
|
|
list( $basename, /* rest */ ) = explode( '/', $this->mDbkeyform, 2 );
|
2007-07-18 07:18:08 +00:00
|
|
|
return $this->isExternal()
|
|
|
|
|
|| ( $this->mNamespace == NS_MAIN && $this->mDbkeyform == '' )
|
2007-11-28 15:09:36 +00:00
|
|
|
|| ( $this->mNamespace == NS_MEDIAWIKI && wfMsgWeirdKey( $basename ) );
|
2005-04-27 07:48:14 +00:00
|
|
|
}
|
2005-05-26 10:23:36 +00:00
|
|
|
|
|
|
|
|
/**
|
2006-06-18 12:42:16 +00:00
|
|
|
* Update page_touched timestamps and send squid purge messages for
|
2008-04-14 07:45:50 +00:00
|
|
|
* pages linking to this title. May be sent to the job queue depending
|
2006-06-18 12:42:16 +00:00
|
|
|
* on the number of links. Typically called on create and delete.
|
2005-05-26 10:23:36 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function touchLinks() {
|
2006-06-18 12:42:16 +00:00
|
|
|
$u = new HTMLCacheUpdate( $this, 'pagelinks' );
|
|
|
|
|
$u->doUpdate();
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2006-06-18 12:42:16 +00:00
|
|
|
if ( $this->getNamespace() == NS_CATEGORY ) {
|
|
|
|
|
$u = new HTMLCacheUpdate( $this, 'categorylinks' );
|
|
|
|
|
$u->doUpdate();
|
2005-12-20 21:17:03 +00:00
|
|
|
}
|
2005-05-26 10:23:36 +00:00
|
|
|
}
|
2005-07-23 05:47:25 +00:00
|
|
|
|
2006-09-05 14:44:50 +00:00
|
|
|
/**
|
|
|
|
|
* Get the last touched timestamp
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getTouched() {
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2006-09-05 14:44:50 +00:00
|
|
|
$touched = $dbr->selectField( 'page', 'page_touched',
|
2008-04-14 07:45:50 +00:00
|
|
|
array(
|
2006-09-05 14:44:50 +00:00
|
|
|
'page_namespace' => $this->getNamespace(),
|
|
|
|
|
'page_title' => $this->getDBkey()
|
|
|
|
|
), __METHOD__
|
|
|
|
|
);
|
|
|
|
|
return $touched;
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-16 15:24:04 +00:00
|
|
|
public function trackbackURL() {
|
2005-07-23 05:47:25 +00:00
|
|
|
global $wgTitle, $wgScriptPath, $wgServer;
|
|
|
|
|
|
|
|
|
|
return "$wgServer$wgScriptPath/trackback.php?article="
|
|
|
|
|
. htmlspecialchars(urlencode($wgTitle->getPrefixedDBkey()));
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-16 15:24:04 +00:00
|
|
|
public function trackbackRDF() {
|
2005-07-23 05:47:25 +00:00
|
|
|
$url = htmlspecialchars($this->getFullURL());
|
|
|
|
|
$title = htmlspecialchars($this->getText());
|
|
|
|
|
$tburl = $this->trackbackURL();
|
|
|
|
|
|
2008-03-22 00:20:39 +00:00
|
|
|
// Autodiscovery RDF is placed in comments so HTML validator
|
|
|
|
|
// won't barf. This is a rather icky workaround, but seems
|
|
|
|
|
// frequently used by this kind of RDF thingy.
|
|
|
|
|
//
|
|
|
|
|
// Spec: http://www.sixapart.com/pronet/docs/trackback_spec
|
|
|
|
|
return "<!--
|
2005-07-23 05:47:25 +00:00
|
|
|
<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/\">
|
|
|
|
|
<rdf:Description
|
|
|
|
|
rdf:about=\"$url\"
|
|
|
|
|
dc:identifier=\"$url\"
|
|
|
|
|
dc:title=\"$title\"
|
|
|
|
|
trackback:ping=\"$tburl\" />
|
2008-03-22 00:20:39 +00:00
|
|
|
</rdf:RDF>
|
|
|
|
|
-->";
|
2005-07-23 05:47:25 +00:00
|
|
|
}
|
2006-03-16 02:51:11 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generate strings used for xml 'id' names in monobook tabs
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getNamespaceKey() {
|
2006-10-13 23:32:36 +00:00
|
|
|
global $wgContLang;
|
2006-03-16 02:51:11 +00:00
|
|
|
switch ($this->getNamespace()) {
|
|
|
|
|
case NS_MAIN:
|
|
|
|
|
case NS_TALK:
|
|
|
|
|
return 'nstab-main';
|
|
|
|
|
case NS_USER:
|
|
|
|
|
case NS_USER_TALK:
|
|
|
|
|
return 'nstab-user';
|
|
|
|
|
case NS_MEDIA:
|
|
|
|
|
return 'nstab-media';
|
|
|
|
|
case NS_SPECIAL:
|
|
|
|
|
return 'nstab-special';
|
|
|
|
|
case NS_PROJECT:
|
|
|
|
|
case NS_PROJECT_TALK:
|
2006-05-15 17:58:41 +00:00
|
|
|
return 'nstab-project';
|
2006-03-16 02:51:11 +00:00
|
|
|
case NS_IMAGE:
|
|
|
|
|
case NS_IMAGE_TALK:
|
|
|
|
|
return 'nstab-image';
|
|
|
|
|
case NS_MEDIAWIKI:
|
|
|
|
|
case NS_MEDIAWIKI_TALK:
|
|
|
|
|
return 'nstab-mediawiki';
|
|
|
|
|
case NS_TEMPLATE:
|
|
|
|
|
case NS_TEMPLATE_TALK:
|
|
|
|
|
return 'nstab-template';
|
|
|
|
|
case NS_HELP:
|
|
|
|
|
case NS_HELP_TALK:
|
|
|
|
|
return 'nstab-help';
|
|
|
|
|
case NS_CATEGORY:
|
|
|
|
|
case NS_CATEGORY_TALK:
|
|
|
|
|
return 'nstab-category';
|
|
|
|
|
default:
|
2006-10-13 23:32:36 +00:00
|
|
|
return 'nstab-' . $wgContLang->lc( $this->getSubjectNsText() );
|
2006-03-16 02:51:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
2006-10-30 06:25:31 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true if this title resolves to the named special page
|
|
|
|
|
* @param string $name The special page name
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isSpecial( $name ) {
|
2006-10-30 06:25:31 +00:00
|
|
|
if ( $this->getNamespace() == NS_SPECIAL ) {
|
2006-11-29 11:43:58 +00:00
|
|
|
list( $thisName, /* $subpage */ ) = SpecialPage::resolveAliasWithSubpage( $this->getDBkey() );
|
2006-10-30 06:25:31 +00:00
|
|
|
if ( $name == $thisName ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-04-14 07:45:50 +00:00
|
|
|
* If the Title refers to a special page alias which is not the local default,
|
2006-10-30 06:25:31 +00:00
|
|
|
* returns a new Title which points to the local default. Otherwise, returns $this.
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function fixSpecialName() {
|
2006-10-30 06:25:31 +00:00
|
|
|
if ( $this->getNamespace() == NS_SPECIAL ) {
|
|
|
|
|
$canonicalName = SpecialPage::resolveAlias( $this->mDbkeyform );
|
|
|
|
|
if ( $canonicalName ) {
|
|
|
|
|
$localName = SpecialPage::getLocalNameFor( $canonicalName );
|
|
|
|
|
if ( $localName != $this->mDbkeyform ) {
|
|
|
|
|
return Title::makeTitle( NS_SPECIAL, $localName );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
2007-04-16 15:24:04 +00:00
|
|
|
|
2007-01-08 15:32:58 +00:00
|
|
|
/**
|
|
|
|
|
* Is this Title in a namespace which contains content?
|
|
|
|
|
* In other words, is this a content page, for the purposes of calculating
|
|
|
|
|
* statistics, etc?
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function isContentPage() {
|
2008-03-21 23:13:34 +00:00
|
|
|
return MWNamespace::isContent( $this->getNamespace() );
|
2007-01-08 15:32:58 +00:00
|
|
|
}
|
2008-04-12 18:06:57 +00:00
|
|
|
|
2008-05-15 19:17:21 +00:00
|
|
|
public function getRedirectsHere( $ns = null ) {
|
2008-04-12 18:06:57 +00:00
|
|
|
$redirs = array();
|
2008-05-15 19:17:21 +00:00
|
|
|
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$where = array(
|
|
|
|
|
'rd_namespace' => $this->getNamespace(),
|
|
|
|
|
'rd_title' => $this->getDBkey(),
|
|
|
|
|
'rd_from = page_id'
|
|
|
|
|
);
|
|
|
|
|
if ( !is_null($ns) ) $where['page_namespace'] = $ns;
|
|
|
|
|
|
2008-07-27 18:59:46 +00:00
|
|
|
$res = $dbr->select(
|
2008-05-15 19:17:21 +00:00
|
|
|
array( 'redirect', 'page' ),
|
|
|
|
|
array( 'page_namespace', 'page_title' ),
|
|
|
|
|
$where,
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
2008-07-27 18:59:46 +00:00
|
|
|
foreach( $res as $row ) {
|
2008-04-12 18:06:57 +00:00
|
|
|
$redirs[] = self::newFromRow( $row );
|
|
|
|
|
}
|
|
|
|
|
return $redirs;
|
|
|
|
|
}
|
2007-12-16 19:57:40 +00:00
|
|
|
}
|