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
|
|
|
|
2010-03-15 23:22:50 +00:00
|
|
|
/**
|
|
|
|
|
* @todo: determine if it is really necessary to load this. Appears to be left over from pre-autoloader versions, and
|
|
|
|
|
* is only really needed to provide access to constant UTF8_REPLACEMENT, which actually resides in UtfNormalDefines.php
|
|
|
|
|
* and is loaded by UtfNormalUtil.php, which is loaded by UtfNormal.php.
|
|
|
|
|
*/
|
2007-04-05 02:30:29 +00:00
|
|
|
if ( !class_exists( 'UtfNormal' ) ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
require_once( dirname( __FILE__ ) . '/normal/UtfNormal.php' );
|
2007-04-05 02:30:29 +00:00
|
|
|
}
|
2006-06-01 08:12:49 +00:00
|
|
|
|
2004-08-20 14:59:49 +00:00
|
|
|
define ( 'GAID_FOR_UPDATE', 1 );
|
|
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2008-08-11 04:39:00 +00:00
|
|
|
* Represents a title within MediaWiki.
|
|
|
|
|
* Optionally may contain an interwiki designation or namespace.
|
|
|
|
|
* @note This class can fetch various kinds of data from the database;
|
|
|
|
|
* however, it does so inefficiently.
|
2010-03-15 23:22:50 +00:00
|
|
|
*
|
|
|
|
|
* @internal documentation reviewed 15 Mar 2010
|
2004-09-03 23:00:01 +00:00
|
|
|
*/
|
2003-04-14 23:10:40 +00:00
|
|
|
class Title {
|
2008-08-11 04:39:00 +00:00
|
|
|
/** @name Static cache variables */
|
2010-04-24 06:22:11 +00:00
|
|
|
// @{
|
|
|
|
|
static private $titleCache = array();
|
|
|
|
|
static private $interwikiCache = array();
|
|
|
|
|
// @}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-08-16 10:13:35 +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.
|
|
|
|
|
*/
|
|
|
|
|
const CACHE_MAX = 1000;
|
|
|
|
|
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2008-08-11 04:39:00 +00:00
|
|
|
* @name Private member variables
|
|
|
|
|
* Please use the accessor functions instead.
|
2006-06-10 18:28:50 +00:00
|
|
|
* @private
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2010-04-24 06:22:11 +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
|
2008-07-25 20:16:24 +00:00
|
|
|
var $mOldRestrictions = false;
|
2009-12-14 20:37:51 +00:00
|
|
|
var $mCascadeRestriction; ///< Cascade restrictions on this page to included templates and images?
|
2010-04-23 18:37:33 +00:00
|
|
|
var $mCascadingRestrictions; // Caching the results of getCascadeProtectionSources
|
2009-12-14 20:37:51 +00:00
|
|
|
var $mRestrictionsExpiry = array(); ///< When do the restrictions on this page expire?
|
|
|
|
|
var $mHasCascadingRestrictions; ///< Are cascading restrictions in effect on this page?
|
|
|
|
|
var $mCascadeSources; ///< Where are the cascading restrictions coming from on this page?
|
2008-08-11 04:39:00 +00:00
|
|
|
var $mRestrictionsLoaded = false; ///< Boolean for initialisation on demand
|
2009-12-14 20:37:51 +00:00
|
|
|
var $mPrefixedText; ///< Text form including namespace/interwiki, initialised on demand
|
2010-04-24 00:23:57 +00:00
|
|
|
var $mTitleProtection; ///< Cached value of getTitleProtection
|
2008-07-25 20:16:24 +00:00
|
|
|
# Don't change the following default, NS_MAIN is hardcoded in several
|
|
|
|
|
# places. See bug 696.
|
2010-04-24 06:22:11 +00:00
|
|
|
var $mDefaultNamespace = NS_MAIN; // /< Namespace index when there is no namespace
|
2009-12-14 20:37:51 +00:00
|
|
|
# Zero except in {{transclusion}} tags
|
2010-04-24 06:22:11 +00:00
|
|
|
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?
|
|
|
|
|
var $mNotificationTimestamp = array(); // /< Associative array of user ID -> timestamp/false
|
|
|
|
|
var $mBacklinkCache = null; // /< Cache of links to this title
|
|
|
|
|
// @}
|
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
|
|
|
*/
|
2010-04-24 06:22:11 +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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $key \type{\string} The database key, which has underscores
|
2004-09-30 05:21:20 +00:00
|
|
|
* instead of spaces, possibly including namespace and
|
|
|
|
|
* interwiki prefixes
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{Title} the new object, or NULL on an error
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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;
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $t->secureAndSplit() )
|
2003-10-01 10:26:26 +00:00
|
|
|
return $t;
|
|
|
|
|
else
|
2009-12-11 21:07:27 +00:00
|
|
|
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
|
|
|
/**
|
2008-10-10 15:37:44 +00:00
|
|
|
* Create a new Title from text, such as what one would find in a link. De-
|
|
|
|
|
* codes any HTML entities in the text.
|
2004-09-30 05:21:20 +00:00
|
|
|
*
|
2010-03-15 23:22:50 +00:00
|
|
|
* @param $text string The link text; spaces, prefixes, and an
|
2008-10-10 15:37:44 +00:00
|
|
|
* initial ':' indicating the main namespace are accepted.
|
2010-03-15 23:22:50 +00:00
|
|
|
* @param $defaultNamespace int The namespace to use if none is speci-
|
2008-10-10 15:37:51 +00:00
|
|
|
* fied by a prefix. If you want to force a specific namespace even if
|
|
|
|
|
* $text might begin with a namespace prefix, use makeTitle() or
|
|
|
|
|
* makeTitleSafe().
|
2008-10-10 15:37:44 +00:00
|
|
|
* @return Title The new object, or null on an error.
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2006-07-10 15:08:51 +00:00
|
|
|
public static function newFromText( $text, $defaultNamespace = NS_MAIN ) {
|
2010-04-24 06:22:11 +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...
|
|
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $defaultNamespace == NS_MAIN && isset( Title::$titleCache[$text] ) ) {
|
2006-06-08 13:08:22 +00:00
|
|
|
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
|
|
|
/**
|
2010-03-28 03:10:10 +00:00
|
|
|
* Convert things like é ā or 〗 into normalized(bug 14952) text
|
2004-11-23 07:38:42 +00:00
|
|
|
*/
|
2010-03-28 03:10:10 +00:00
|
|
|
$filteredText = Sanitizer::decodeCharReferencesAndNormalize( $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 ;
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $t->secureAndSplit() ) {
|
|
|
|
|
if ( $defaultNamespace == NS_MAIN ) {
|
|
|
|
|
if ( $cachedcount >= self::CACHE_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();
|
2010-04-24 06:22:11 +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 {
|
2009-12-11 21:07:27 +00:00
|
|
|
$ret = null;
|
2005-08-02 13:35:19 +00:00
|
|
|
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
|
|
|
/**
|
2009-06-02 04:05:47 +00:00
|
|
|
* THIS IS NOT THE FUNCTION YOU WANT. Use Title::newFromText().
|
|
|
|
|
*
|
|
|
|
|
* Example of wrong and broken code:
|
|
|
|
|
* $title = Title::newFromURL( $wgRequest->getVal( 'title' ) );
|
|
|
|
|
*
|
|
|
|
|
* Example of right code:
|
|
|
|
|
* $title = Title::newFromText( $wgRequest->getVal( 'title' ) );
|
|
|
|
|
*
|
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.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $url \type{\string} the title, as might be taken from a URL
|
|
|
|
|
* @return \type{Title} the new object, or NULL on an error
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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 );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $t->secureAndSplit() ) {
|
2003-10-01 10:26:26 +00:00
|
|
|
return $t;
|
|
|
|
|
} else {
|
2009-12-11 21:07:27 +00:00
|
|
|
return null;
|
2003-10-01 10:26:26 +00:00
|
|
|
}
|
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
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $id \type{\int} the page_id corresponding to the Title to create
|
|
|
|
|
* @param $flags \type{\int} use GAID_FOR_UPDATE to use master
|
|
|
|
|
* @return \type{Title} the new object, or NULL on an error
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2008-05-10 23:31:52 +00:00
|
|
|
public static function newFromID( $id, $flags = 0 ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
$db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
|
2009-03-27 10:22:30 +00:00
|
|
|
$row = $db->selectRow( 'page', '*', array( 'page_id' => $id ), __METHOD__ );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $row !== false ) {
|
2009-03-27 10:22:30 +00:00
|
|
|
$title = Title::newFromRow( $row );
|
2004-01-17 05:49:39 +00:00
|
|
|
} else {
|
2009-12-11 21:07:27 +00:00
|
|
|
$title = null;
|
2004-01-17 05:49:39 +00:00
|
|
|
}
|
|
|
|
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-21 08:39:31 +00:00
|
|
|
* @param $ids \type{\arrayof{\int}} Array of IDs
|
|
|
|
|
* @return \type{\arrayof{Title}} Array of Titles
|
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();
|
2010-04-24 06:22:11 +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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $row \type{Row} (needs at least page_title,page_namespace)
|
|
|
|
|
* @return \type{Title} corresponding Title
|
2008-04-08 20:34:09 +00:00
|
|
|
*/
|
|
|
|
|
public static function newFromRow( $row ) {
|
|
|
|
|
$t = self::makeTitle( $row->page_namespace, $row->page_title );
|
2008-04-09 05:21:00 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
$t->mArticleID = isset( $row->page_id ) ? intval( $row->page_id ) : -1;
|
|
|
|
|
$t->mLength = isset( $row->page_len ) ? intval( $row->page_len ) : -1;
|
|
|
|
|
$t->mRedirect = isset( $row->page_is_redirect ) ? (bool)$row->page_is_redirect : null;
|
2010-06-28 12:02:09 +00:00
|
|
|
$t->mLatestID = isset( $row->page_latest ) ? intval( $row->page_latest ) : false;
|
2008-04-09 05:21:00 +00:00
|
|
|
|
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.
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $ns \type{\int} the namespace of the article
|
|
|
|
|
* @param $title \type{\string} the unprefixed database key form
|
|
|
|
|
* @param $fragment \type{\string} The link fragment (after the "#")
|
|
|
|
|
* @return \type{Title} the new object
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $ns \type{\int} the namespace of the article
|
|
|
|
|
* @param $title \type{\string} the database key form
|
|
|
|
|
* @param $fragment \type{\string} The link fragment (after the "#")
|
|
|
|
|
* @return \type{Title} the new object, or NULL on an error
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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 );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $t->secureAndSplit() ) {
|
2004-08-22 23:55:36 +00:00
|
|
|
return $t;
|
|
|
|
|
} else {
|
2009-12-11 21:07:27 +00:00
|
|
|
return null;
|
2004-08-22 23:55:36 +00:00
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Create a new Title for the Main Page
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{Title} the new object
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
2009-01-29 00:29:52 +00:00
|
|
|
* This will only return the very next target, useful for
|
|
|
|
|
* the redirect table and other checks that don't need full recursion
|
2007-08-01 01:45:58 +00:00
|
|
|
*
|
2009-01-21 20:42:32 +00:00
|
|
|
* @param $text \type{\string} Text with possible redirect
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{Title} The corresponding Title
|
2009-01-21 20:42:32 +00:00
|
|
|
*/
|
2009-01-29 00:29:52 +00:00
|
|
|
public static function newFromRedirect( $text ) {
|
|
|
|
|
return self::newFromRedirectInternal( $text );
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-01-29 00:29:52 +00:00
|
|
|
/**
|
|
|
|
|
* Extract a redirect destination from a string and return the
|
|
|
|
|
* Title, or null if the text doesn't contain a valid redirect
|
|
|
|
|
* This will recurse down $wgMaxRedirects times or until a non-redirect target is hit
|
|
|
|
|
* in order to provide (hopefully) the Title of the final destination instead of another redirect
|
|
|
|
|
*
|
|
|
|
|
* @param $text \type{\string} Text with possible redirect
|
|
|
|
|
* @return \type{Title} The corresponding Title
|
|
|
|
|
*/
|
|
|
|
|
public static function newFromRedirectRecurse( $text ) {
|
|
|
|
|
$titles = self::newFromRedirectArray( $text );
|
2009-02-03 00:06:46 +00:00
|
|
|
return $titles ? array_pop( $titles ) : null;
|
2009-01-29 00:29:52 +00:00
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-01-29 00:29:52 +00:00
|
|
|
/**
|
|
|
|
|
* Extract a redirect destination from a string and return an
|
|
|
|
|
* array of Titles, or null if the text doesn't contain a valid redirect
|
|
|
|
|
* The last element in the array is the final destination after all redirects
|
|
|
|
|
* have been resolved (up to $wgMaxRedirects times)
|
|
|
|
|
*
|
|
|
|
|
* @param $text \type{\string} Text with possible redirect
|
|
|
|
|
* @return \type{\array} Array of Titles, with the destination last
|
|
|
|
|
*/
|
|
|
|
|
public static function newFromRedirectArray( $text ) {
|
2009-01-21 20:42:32 +00:00
|
|
|
global $wgMaxRedirects;
|
|
|
|
|
// are redirects disabled?
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $wgMaxRedirects < 1 )
|
2009-01-29 00:29:52 +00:00
|
|
|
return null;
|
|
|
|
|
$title = self::newFromRedirectInternal( $text );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( is_null( $title ) )
|
2009-01-21 20:42:32 +00:00
|
|
|
return null;
|
2009-01-29 00:29:52 +00:00
|
|
|
// recursive check to follow double redirects
|
|
|
|
|
$recurse = $wgMaxRedirects;
|
|
|
|
|
$titles = array( $title );
|
2010-04-24 06:22:11 +00:00
|
|
|
while ( --$recurse > 0 ) {
|
|
|
|
|
if ( $title->isRedirect() ) {
|
2009-01-29 00:29:52 +00:00
|
|
|
$article = new Article( $title, 0 );
|
|
|
|
|
$newtitle = $article->getRedirectTarget();
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// Redirects to some special pages are not permitted
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $newtitle instanceOf Title && $newtitle->isValidRedirectTarget() ) {
|
2009-01-29 00:29:52 +00:00
|
|
|
// the new title passes the checks, so make that our current title so that further recursion can be checked
|
|
|
|
|
$title = $newtitle;
|
|
|
|
|
$titles[] = $newtitle;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $titles;
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-01-29 00:29:52 +00:00
|
|
|
/**
|
|
|
|
|
* Really extract the redirect destination
|
|
|
|
|
* Do not call this function directly, use one of the newFromRedirect* functions above
|
|
|
|
|
*
|
|
|
|
|
* @param $text \type{\string} Text with possible redirect
|
|
|
|
|
* @return \type{Title} The corresponding Title
|
|
|
|
|
*/
|
|
|
|
|
protected static function newFromRedirectInternal( $text ) {
|
2007-08-01 01:45:58 +00:00
|
|
|
$redir = MagicWord::get( 'redirect' );
|
2010-04-24 06:22:11 +00:00
|
|
|
$text = trim( $text );
|
|
|
|
|
if ( $redir->matchStartAndRemove( $text ) ) {
|
2007-08-01 01:45:58 +00:00
|
|
|
// Extract the first link and see if it's usable
|
2008-08-06 20:33:45 +00:00
|
|
|
// Ensure that it really does come directly after #REDIRECT
|
2008-08-09 00:33:02 +00:00
|
|
|
// Some older redirects included a colon, so don't freak about that!
|
2007-08-21 03:57:54 +00:00
|
|
|
$m = array();
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( preg_match( '!^\s*:?\s*\[{2}(.*?)(?:\|.*?)?\]{2}!', $text, $m ) ) {
|
2007-08-01 01:45:58 +00:00
|
|
|
// Strip preceding colon used to "escape" categories, etc.
|
|
|
|
|
// and URL-decode links
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( strpos( $m[1], '%' ) !== false ) {
|
2007-08-26 14:52:56 +00:00
|
|
|
// 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] );
|
2009-01-29 00:29:52 +00:00
|
|
|
// If the title is a redirect to bad special pages or is invalid, return null
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$title instanceof Title || !$title->isValidRedirectTarget() ) {
|
2009-01-21 20:42:32 +00:00
|
|
|
return null;
|
|
|
|
|
}
|
2009-01-29 00:29:52 +00:00
|
|
|
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
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
# ----------------------------------------------------------------------------
|
2004-03-06 01:49:16 +00:00
|
|
|
# Static functions
|
2010-04-24 06:22:11 +00:00
|
|
|
# ----------------------------------------------------------------------------
|
2004-03-06 01:49:16 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the prefixed DB key associated with an ID
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $id \type{\int} the page_id of the article
|
|
|
|
|
* @return \type{Title} an object representing the article, or NULL
|
2009-12-14 20:37:51 +00:00
|
|
|
* if no such article was found
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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-11-13 22:20:51 +00:00
|
|
|
$s = $dbr->selectRow( 'page',
|
2010-04-24 06:22:11 +00:00
|
|
|
array( 'page_namespace', 'page_title' ),
|
2009-12-14 20:37:51 +00:00
|
|
|
array( 'page_id' => $id ),
|
2008-11-13 22:20:51 +00:00
|
|
|
__METHOD__ );
|
2009-12-11 21:07:27 +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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} the list of characters, not delimited
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $ns \type{\int} a namespace index
|
|
|
|
|
* @param $title \type{\string} text-form main part
|
|
|
|
|
* @return \type{\string} a stripped-down title string ready for the
|
2009-12-14 20:37:51 +00:00
|
|
|
* search index
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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() . '&#;';
|
2010-02-02 15:09:01 +00:00
|
|
|
$t = $wgContLang->normalizeForSearch( $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
|
|
|
|
2008-12-01 17:14:30 +00:00
|
|
|
if ( $ns == NS_FILE ) {
|
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
|
|
|
|
2009-06-02 19:37:45 +00:00
|
|
|
/**
|
2004-09-30 05:21:20 +00:00
|
|
|
* Make a prefixed DB key from a DB key and a namespace index
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $ns \type{\int} numerical representation of the namespace
|
|
|
|
|
* @param $title \type{\string} the DB key form the title
|
|
|
|
|
* @param $fragment \type{\string} The link fragment (after the "#")
|
|
|
|
|
* @return \type{\string} the prefixed form of the title
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
|
|
/**
|
|
|
|
|
* Determine whether the object refers to a page within
|
2005-07-01 10:44:48 +00:00
|
|
|
* this project.
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool} TRUE if this is an in-project interwiki link
|
2004-09-30 05:21:20 +00:00
|
|
|
* 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 != '' ) {
|
2008-09-29 10:08:46 +00:00
|
|
|
return Interwiki::fetch( $this->mInterwiki )->isLocal();
|
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.
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool} TRUE if this is transcludable
|
2005-07-03 07:15:53 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isTrans() {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->mInterwiki == '' )
|
2005-07-03 07:15:53 +00:00
|
|
|
return false;
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2008-09-29 10:08:46 +00:00
|
|
|
return Interwiki::fetch( $this->mInterwiki )->isTranscludable();
|
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
|
2010-04-24 06:22:11 +00:00
|
|
|
*
|
2010-03-15 23:22:50 +00:00
|
|
|
* @param $fragment string containing a URL or link fragment (after the "#")
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return String: escaped string
|
2006-12-08 06:09:15 +00:00
|
|
|
*/
|
|
|
|
|
static function escapeFragmentForURL( $fragment ) {
|
2009-01-05 15:59:17 +00:00
|
|
|
# Note that we don't urlencode the fragment. urlencoded Unicode
|
|
|
|
|
# fragments appear not to work in IE (at least up to 7) or in at least
|
|
|
|
|
# one version of Opera 9.x. The W3C validator, for one, doesn't seem
|
|
|
|
|
# to care if they aren't encoded.
|
2010-01-29 21:44:01 +00:00
|
|
|
return Sanitizer::escapeId( $fragment, 'noninitial' );
|
2006-12-08 06:09:15 +00:00
|
|
|
}
|
|
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
# ----------------------------------------------------------------------------
|
2004-03-06 01:49:16 +00:00
|
|
|
# Other stuff
|
2010-04-24 06:22:11 +00:00
|
|
|
# ----------------------------------------------------------------------------
|
2004-03-06 01:49:16 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/** Simple accessors */
|
|
|
|
|
/**
|
|
|
|
|
* Get the text form (spaces not underscores) of the main part
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Main part of the title
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getText() { return $this->mTextform; }
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the URL-encoded form of the main part
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Main part of the title, URL-encoded
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getPartialURL() { return $this->mUrlform; }
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the main part with underscores
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Main part of the title, with underscores
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getDBkey() { return $this->mDbkeyform; }
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2008-08-11 04:39:00 +00:00
|
|
|
* Get the namespace index, i.e.\ one of the NS_xxxx constants.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\int} Namespace index
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getNamespace() { return $this->mNamespace; }
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2005-08-27 03:47:47 +00:00
|
|
|
/**
|
|
|
|
|
* Get the namespace text
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Namespace text
|
2005-08-27 03:47:47 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getNsText() {
|
2009-10-16 04:06:30 +00:00
|
|
|
global $wgContLang;
|
2006-12-31 03:04:49 +00:00
|
|
|
|
2010-01-06 19:59:42 +00:00
|
|
|
if ( $this->mInterwiki != '' ) {
|
2006-12-31 03:04:49 +00:00
|
|
|
// 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.
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( MWNamespace::exists( $this->mNamespace ) ) {
|
2009-10-16 04:06:30 +00:00
|
|
|
return MWNamespace::getCanonicalName( $this->mNamespace );
|
2006-12-31 03:04:49 +00:00
|
|
|
}
|
|
|
|
|
}
|
2005-08-27 03:56:58 +00:00
|
|
|
return $wgContLang->getNsText( $this->mNamespace );
|
|
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2007-06-03 10:44:27 +00:00
|
|
|
/**
|
|
|
|
|
* Get the DB key with the initial letter case as specified by the user
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} DB key
|
2007-06-03 10:44:27 +00:00
|
|
|
*/
|
|
|
|
|
function getUserCaseDBKey() {
|
|
|
|
|
return $this->mUserCaseDBKey;
|
|
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2005-08-27 03:56:58 +00:00
|
|
|
/**
|
|
|
|
|
* Get the namespace text of the subject (rather than talk) page
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Namespace text
|
2005-08-27 03:56:58 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getSubjectNsText() {
|
2009-02-17 23:00:57 +00:00
|
|
|
global $wgContLang;
|
|
|
|
|
return $wgContLang->getNsText( MWNamespace::getSubject( $this->mNamespace ) );
|
2005-08-27 03:47:47 +00:00
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2006-04-12 15:38:17 +00:00
|
|
|
/**
|
|
|
|
|
* Get the namespace text of the talk page
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Namespace text
|
2006-04-12 15:38:17 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getTalkNsText() {
|
2009-02-17 23:00:57 +00:00
|
|
|
global $wgContLang;
|
|
|
|
|
return( $wgContLang->getNsText( MWNamespace::getTalk( $this->mNamespace ) ) );
|
2006-04-12 15:38:17 +00:00
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2006-04-12 15:38:17 +00:00
|
|
|
/**
|
|
|
|
|
* Could this title have a corresponding talk page?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool} TRUE or FALSE
|
2006-04-12 15:38:17 +00:00
|
|
|
*/
|
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
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the interwiki prefix (or null string)
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Interwiki prefix
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getInterwiki() { return $this->mInterwiki; }
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2008-08-11 04:39:00 +00:00
|
|
|
* Get the Title fragment (i.e.\ the bit after the #) in text form
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Title fragment
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getFragment() { return $this->mFragment; }
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2006-12-08 06:09:15 +00:00
|
|
|
/**
|
|
|
|
|
* Get the fragment in URL form, including the "#" character if there is one
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Fragment in URL form
|
2006-12-08 06:09:15 +00:00
|
|
|
*/
|
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 );
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Get the default namespace index, for when there is no namespace
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\int} Default namespace index
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} a stripped-down title string ready for the
|
2009-12-14 20:37:51 +00:00
|
|
|
* search index
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} the prefixed title, with underscores and
|
2009-12-14 20:37:51 +00:00
|
|
|
* any interwiki and namespace prefixes
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} the prefixed title, with spaces
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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 '#')
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} the prefixed title, with spaces and
|
2009-12-14 20:37:51 +00:00
|
|
|
* the fragment, including '#'
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getFullText() {
|
2004-07-29 04:48:42 +00:00
|
|
|
$text = $this->getPrefixedText();
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->mFragment != '' ) {
|
2004-07-29 04:48:42 +00:00
|
|
|
$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 /
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Base name
|
2006-05-14 03:51:36 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getBaseText() {
|
2010-04-24 06:22:11 +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
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( count( $parts ) > 1 )
|
2008-05-23 22:00:14 +00:00
|
|
|
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 /
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Subpage name
|
2006-03-04 23:29:46 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getSubpageText() {
|
2010-04-24 06:22:11 +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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} URL-encoded subpage name
|
2006-04-02 16:19:29 +00:00
|
|
|
*/
|
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 ) );
|
|
|
|
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} the URL-encoded form
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getPrefixedURL() {
|
2003-04-14 23:10:40 +00:00
|
|
|
$s = $this->prefix( $this->mDbkeyform );
|
2008-11-08 23:20:44 +00:00
|
|
|
$s = wfUrlencode( str_replace( ' ', '_', $s ) );
|
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
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $query \twotypes{\string,\array} an optional query string, not used for interwiki
|
2008-08-01 00:47:26 +00:00
|
|
|
* links. Can be specified as an associative array as well, e.g.,
|
|
|
|
|
* array( 'action' => 'edit' ) (keys and values will be URL-escaped).
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $variant \type{\string} language variant of url (for sr, zh..)
|
|
|
|
|
* @return \type{\string} the URL
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( is_array( $query ) ) {
|
2008-08-01 00:47:26 +00:00
|
|
|
$query = wfArrayToCGI( $query );
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-13 18:43:55 +00:00
|
|
|
$interwiki = Interwiki::fetch( $this->mInterwiki );
|
|
|
|
|
if ( !$interwiki ) {
|
2009-11-29 06:47:51 +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.
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $wgRequest->getVal( 'action' ) != 'render' ) {
|
2006-01-12 10:06:54 +00:00
|
|
|
$url = $wgServer . $url;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
} else {
|
2008-10-13 18:43:55 +00:00
|
|
|
$baseUrl = $interwiki->getURL( );
|
2008-05-09 23:52:04 +00:00
|
|
|
|
2006-12-31 03:04:49 +00:00
|
|
|
$namespace = wfUrlencode( $this->getNsText() );
|
2010-01-06 19:59:42 +00:00
|
|
|
if ( $namespace != '' ) {
|
2005-10-22 16:25:05 +00:00
|
|
|
# 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.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @param $query Mixed: an optional query string; if not specified,
|
2009-12-14 20:37:51 +00:00
|
|
|
* $wgArticlePath will be used. Can be specified as an associative array
|
2008-08-01 00:47:26 +00:00
|
|
|
* as well, e.g., array( 'action' => 'edit' ) (keys and values will be
|
|
|
|
|
* URL-escaped).
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $variant \type{\string} language variant of url (for sr, zh..)
|
|
|
|
|
* @return \type{\string} the URL
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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;
|
2008-09-29 23:02:52 +00:00
|
|
|
global $wgVariantArticlePath, $wgContLang, $wgUser;
|
2008-05-14 18:28:52 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( is_array( $query ) ) {
|
2008-08-01 00:47:26 +00:00
|
|
|
$query = wfArrayToCGI( $query );
|
|
|
|
|
}
|
|
|
|
|
|
2006-10-12 10:34:49 +00:00
|
|
|
// internal links should point to same variant as current page (only anonymous users)
|
2010-06-09 11:44:05 +00:00
|
|
|
if ( !$variant && $wgContLang->hasVariants() && !$wgUser->isLoggedIn() ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
$pref = $wgContLang->getPreferredVariant( false );
|
|
|
|
|
if ( $pref != $wgContLang->getCode() )
|
2006-10-12 10:34:49 +00:00
|
|
|
$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() );
|
2008-09-29 23:02:52 +00:00
|
|
|
if ( $query == '' ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $variant != false && $wgContLang->hasVariants() ) {
|
2010-06-09 11:44:05 +00:00
|
|
|
if ( !$wgVariantArticlePath ) {
|
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();
|
2010-04-24 06:22:11 +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] );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( isset( $wgActionPaths[$action] ) ) {
|
2005-10-22 16:25:05 +00:00
|
|
|
$query = $matches[1];
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( isset( $matches[4] ) ) $query .= $matches[4];
|
2005-10-22 16:25:05 +00:00
|
|
|
$url = str_replace( '$1', $dbkey, $wgActionPaths[$action] );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $query != '' ) {
|
2009-01-02 17:10:26 +00:00
|
|
|
$url = wfAppendQuery( $url, $query );
|
2009-01-02 16:34:43 +00:00
|
|
|
}
|
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.
|
2010-04-24 06:22:11 +00:00
|
|
|
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
|
|
|
|
2008-08-01 15:02:46 +00:00
|
|
|
/**
|
|
|
|
|
* Get a URL that's the simplest URL that will be valid to link, locally,
|
|
|
|
|
* to the current Title. It includes the fragment, but does not include
|
|
|
|
|
* the server unless action=render is used (or the link is external). If
|
|
|
|
|
* there's a fragment but the prefixed text is empty, we just return a link
|
|
|
|
|
* to the fragment.
|
|
|
|
|
*
|
2009-04-19 17:07:41 +00:00
|
|
|
* The result obviously should not be URL-escaped, but does need to be
|
|
|
|
|
* HTML-escaped if it's being output in HTML.
|
|
|
|
|
*
|
2008-08-21 08:39:31 +00:00
|
|
|
* @param $query \type{\arrayof{\string}} An associative array of key => value pairs for the
|
2008-08-01 15:02:46 +00:00
|
|
|
* query string. Keys and values will be escaped.
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $variant \type{\string} Language variant of URL (for sr, zh..). Ignored
|
2008-08-01 15:02:46 +00:00
|
|
|
* for external links. Default is "false" (same variant as current page,
|
|
|
|
|
* for anonymous users).
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} the URL
|
2008-08-01 15:02:46 +00:00
|
|
|
*/
|
|
|
|
|
public function getLinkUrl( $query = array(), $variant = false ) {
|
2009-02-20 11:09:04 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->isExternal() ) {
|
2009-02-20 14:13:43 +00:00
|
|
|
$ret = $this->getFullURL( $query );
|
2010-04-24 06:22:11 +00:00
|
|
|
} elseif ( $this->getPrefixedText() === '' && $this->getFragment() !== '' ) {
|
2009-02-20 14:13:43 +00:00
|
|
|
$ret = $this->getFragmentForURL();
|
2008-08-01 15:02:46 +00:00
|
|
|
} else {
|
2009-02-24 00:03:33 +00:00
|
|
|
$ret = $this->getLocalURL( $query, $variant ) . $this->getFragmentForURL();
|
2008-08-01 15:02:46 +00:00
|
|
|
}
|
2009-02-20 11:09:04 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2009-02-20 14:13:43 +00:00
|
|
|
return $ret;
|
2008-08-01 15:02:46 +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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $query \type{\string} an optional query string
|
|
|
|
|
* @return \type{\string} the URL
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $query \type{\string} an optional query string
|
|
|
|
|
* @return \type{\string} the URL
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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.
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $query \type{\string} an optional query string
|
|
|
|
|
* @param $variant \type{\string} language variant of url (for sr, zh..)
|
|
|
|
|
* @return \type{\string} the URL
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} the URL, or a null string if this is an
|
2009-12-14 20:37:51 +00:00
|
|
|
* interwiki link
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getEditURL() {
|
2010-01-06 19:59:42 +00:00
|
|
|
if ( $this->mInterwiki != '' ) { return ''; }
|
2004-08-16 20:14:35 +00:00
|
|
|
$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.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} the text, including any prefixes
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool}
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2010-01-06 19:59:42 +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?
|
|
|
|
|
*
|
2010-02-23 18:36:46 +00:00
|
|
|
* @param $action \type{\string} Action to check (default: edit)
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool}
|
2006-02-06 09:49:28 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isSemiProtected( $action = 'edit' ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->exists() ) {
|
2006-12-30 19:49:30 +00:00
|
|
|
$restrictions = $this->getRestrictions( $action );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( count( $restrictions ) > 0 ) {
|
|
|
|
|
foreach ( $restrictions as $restriction ) {
|
|
|
|
|
if ( strtolower( $restriction ) != 'autoconfirmed' )
|
2006-12-30 19:49:30 +00:00
|
|
|
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?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2010-02-23 18:36:46 +00:00
|
|
|
* @param $action \type{\string} the action the page is protected from,
|
2009-11-06 10:27:44 +00:00
|
|
|
* by default checks all actions.
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool}
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isProtected( $action = '' ) {
|
2009-11-06 10:27:44 +00:00
|
|
|
global $wgRestrictionLevels;
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-11-09 12:05:30 +00:00
|
|
|
$restrictionTypes = $this->getRestrictionTypes();
|
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
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $restrictionTypes as $type ) {
|
|
|
|
|
if ( $action == $type || $action == '' ) {
|
2008-03-04 21:27:23 +00:00
|
|
|
$r = $this->getRestrictions( $type );
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $wgRestrictionLevels as $level ) {
|
|
|
|
|
if ( in_array( $level, $r ) && $level != '' ) {
|
2008-03-04 21:27:23 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-07 04:13:14 +00:00
|
|
|
/**
|
|
|
|
|
* Is this a conversion table for the LanguageConverter?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2010-01-07 04:13:14 +00:00
|
|
|
* @return \type{\bool}
|
|
|
|
|
*/
|
|
|
|
|
public function isConversionTable() {
|
|
|
|
|
if($this->getNamespace() == NS_MEDIAWIKI
|
|
|
|
|
&& strpos( $this->getText(), 'Conversiontable' ) !== false ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2008-03-02 13:57:56 +00:00
|
|
|
* Is $wgUser watching this page?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool}
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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 ) ) {
|
2010-04-24 06:22:11 +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?
|
2009-09-14 21:42:28 +00:00
|
|
|
* This skips potentially expensive cascading permission checks
|
|
|
|
|
* as well as avoids expensive error formatting
|
2007-01-13 03:22:20 +00:00
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $action \type{\string} action that permission needs to be checked for
|
|
|
|
|
* @return \type{\bool}
|
2009-12-14 20:37:51 +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 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
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool}
|
2007-07-07 04:18:44 +00:00
|
|
|
*/
|
2007-07-07 04:53:35 +00:00
|
|
|
public function isNamespaceProtected() {
|
2007-07-07 04:18:44 +00:00
|
|
|
global $wgNamespaceProtection, $wgUser;
|
2010-04-24 06:22:11 +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?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-21 08:39:31 +00:00
|
|
|
* @param $action \type{\string} action that permission needs to be checked for
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $doExpensiveQueries \type{\bool} Set this to false to avoid doing unnecessary queries.
|
|
|
|
|
* @return \type{\bool}
|
2009-12-14 20:37:51 +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;
|
2010-04-24 06:22:11 +00:00
|
|
|
return ( $this->getUserPermissionsErrorsInternal( $action, $wgUser, $doExpensiveQueries, true ) === 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
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $action \type{\string}action that permission needs to be checked for
|
|
|
|
|
* @param $user \type{User} user to check
|
|
|
|
|
* @param $doExpensiveQueries \type{\bool} Set this to false to avoid doing unnecessary queries.
|
2008-08-21 08:39:31 +00:00
|
|
|
* @param $ignoreErrors \type{\arrayof{\string}} Set this to a list of message keys whose corresponding errors may be ignored.
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\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() ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !StubObject::isRealObject( $user ) ) {
|
|
|
|
|
// Since StubObject is always used on globals, we can
|
|
|
|
|
// unstub $wgUser here and set $user = $wgUser
|
2008-06-05 14:05:35 +00:00
|
|
|
global $wgUser;
|
|
|
|
|
$wgUser->_unstub( '', 5 );
|
|
|
|
|
$user = $wgUser;
|
|
|
|
|
}
|
2008-12-31 18:56:16 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
$errors = $this->getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries );
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2008-06-27 06:24:42 +00:00
|
|
|
// Remove the errors being ignored.
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $errors as $index => $error ) {
|
|
|
|
|
$error_key = is_array( $error ) ? $error[0] : $error;
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( in_array( $error_key, $ignoreErrors ) ) {
|
|
|
|
|
unset( $errors[$index] );
|
2008-06-27 06:24:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
2007-08-01 10:19:26 +00:00
|
|
|
|
|
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2010-04-24 06:22:11 +00:00
|
|
|
* Permissions checks that fail most often, and which are easiest to test.
|
2008-01-13 22:23:36 +00:00
|
|
|
*
|
2010-04-24 06:22:11 +00:00
|
|
|
* @param $action String the action to check
|
|
|
|
|
* @param $user User user to check
|
|
|
|
|
* @param $errors Array list of current errors
|
|
|
|
|
* @param $doExpensiveQueries Boolean whether or not to perform expensive queries
|
|
|
|
|
* @param $short Boolean short circuit on first error
|
|
|
|
|
*
|
|
|
|
|
* @return Array list of errors
|
2007-08-01 10:19:26 +00:00
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
private function checkQuickPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) {
|
|
|
|
|
if ( $action == 'create' ) {
|
|
|
|
|
if ( ( $this->isTalkPage() && !$user->isAllowed( 'createtalk' ) ) ||
|
|
|
|
|
( !$this->isTalkPage() && !$user->isAllowed( 'createpage' ) ) ) {
|
|
|
|
|
$errors[] = $user->isAnon() ? array ( 'nocreatetext' ) : array ( 'nocreate-loggedin' );
|
|
|
|
|
}
|
|
|
|
|
} elseif ( $action == 'move' ) {
|
|
|
|
|
if ( !$user->isAllowed( 'move-rootuserpages' )
|
|
|
|
|
&& $this->mNamespace == NS_USER && !$this->isSubpage() ) {
|
2009-02-06 17:58:18 +00:00
|
|
|
// Show user page-specific message only if the user can move other pages
|
|
|
|
|
$errors[] = array( 'cant-move-user-page' );
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-02-06 17:58:18 +00:00
|
|
|
// Check if user is allowed to move files if it's a file
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->mNamespace == NS_FILE && !$user->isAllowed( 'movefile' ) ) {
|
2009-02-06 17:58:18 +00:00
|
|
|
$errors[] = array( 'movenotallowedfile' );
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$user->isAllowed( 'move' ) ) {
|
2009-02-06 17:58:18 +00:00
|
|
|
// User can't move anything
|
2009-05-26 19:16:49 +00:00
|
|
|
global $wgGroupPermissions;
|
2009-07-17 22:08:54 +00:00
|
|
|
$userCanMove = false;
|
2009-07-17 22:26:39 +00:00
|
|
|
if ( isset( $wgGroupPermissions['user']['move'] ) ) {
|
2009-07-17 22:08:54 +00:00
|
|
|
$userCanMove = $wgGroupPermissions['user']['move'];
|
|
|
|
|
}
|
|
|
|
|
$autoconfirmedCanMove = false;
|
2009-07-17 22:26:39 +00:00
|
|
|
if ( isset( $wgGroupPermissions['autoconfirmed']['move'] ) ) {
|
2009-07-17 22:08:54 +00:00
|
|
|
$autoconfirmedCanMove = $wgGroupPermissions['autoconfirmed']['move'];
|
|
|
|
|
}
|
|
|
|
|
if ( $user->isAnon() && ( $userCanMove || $autoconfirmedCanMove ) ) {
|
2009-05-26 19:16:49 +00:00
|
|
|
// custom message if logged-in users without any special rights can move
|
|
|
|
|
$errors[] = array ( 'movenologintext' );
|
|
|
|
|
} else {
|
2010-04-24 06:22:11 +00:00
|
|
|
$errors[] = array ( 'movenotallowed' );
|
2009-05-26 19:16:49 +00:00
|
|
|
}
|
2009-02-06 17:58:18 +00:00
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
} elseif ( $action == 'move-target' ) {
|
|
|
|
|
if ( !$user->isAllowed( 'move' ) ) {
|
2009-02-06 17:58:18 +00:00
|
|
|
// User can't move anything
|
2010-04-24 06:22:11 +00:00
|
|
|
$errors[] = array ( 'movenotallowed' );
|
|
|
|
|
} elseif ( !$user->isAllowed( 'move-rootuserpages' )
|
|
|
|
|
&& $this->mNamespace == NS_USER && !$this->isSubpage() ) {
|
2009-02-06 17:58:18 +00:00
|
|
|
// Show user page-specific message only if the user can move other pages
|
|
|
|
|
$errors[] = array( 'cant-move-to-user-page' );
|
|
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
} elseif ( !$user->isAllowed( $action ) ) {
|
2009-02-06 17:58:18 +00:00
|
|
|
$return = null;
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-09-14 21:42:28 +00:00
|
|
|
// We avoid expensive display logic for quickUserCan's and such
|
2009-12-14 20:37:51 +00:00
|
|
|
$groups = false;
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$short ) {
|
2009-09-14 21:42:28 +00:00
|
|
|
$groups = array_map( array( 'User', 'makeGroupLinkWiki' ),
|
|
|
|
|
User::getGroupsWithPermission( $action ) );
|
2009-12-14 20:37:51 +00:00
|
|
|
}
|
|
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $groups ) {
|
2010-03-13 16:50:36 +00:00
|
|
|
global $wgLang;
|
2010-04-24 06:22:11 +00:00
|
|
|
$return = array(
|
2010-03-13 16:09:23 +00:00
|
|
|
'badaccess-groups',
|
2010-04-24 06:22:11 +00:00
|
|
|
$wgLang->commaList( $groups ),
|
2010-03-13 16:09:23 +00:00
|
|
|
count( $groups )
|
|
|
|
|
);
|
2009-02-06 17:58:18 +00:00
|
|
|
} else {
|
|
|
|
|
$return = array( "badaccess-group0" );
|
|
|
|
|
}
|
|
|
|
|
$errors[] = $return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add the resulting error code to the errors array
|
|
|
|
|
*
|
|
|
|
|
* @param $errors Array list of current errors
|
|
|
|
|
* @param $result Mixed result of errors
|
|
|
|
|
*
|
|
|
|
|
* @return Array list of errors
|
|
|
|
|
*/
|
|
|
|
|
private function resultToError( $errors, $result ) {
|
|
|
|
|
if ( is_array( $result ) && count( $result ) && !is_array( $result[0] ) ) {
|
|
|
|
|
// A single array representing an error
|
|
|
|
|
$errors[] = $result;
|
|
|
|
|
} else if ( is_array( $result ) && is_array( $result[0] ) ) {
|
|
|
|
|
// A nested array representing multiple errors
|
|
|
|
|
$errors = array_merge( $errors, $result );
|
|
|
|
|
} else if ( $result !== '' && is_string( $result ) ) {
|
|
|
|
|
// A string representing a message-id
|
|
|
|
|
$errors[] = array( $result );
|
|
|
|
|
} else if ( $result === false ) {
|
|
|
|
|
// a generic "We don't want them to do that"
|
|
|
|
|
$errors[] = array( 'badaccess-group0' );
|
2009-02-06 17:58:18 +00:00
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
return $errors;
|
|
|
|
|
}
|
2009-02-06 17:58:18 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
/**
|
|
|
|
|
* Check various permission hooks
|
|
|
|
|
* @see checkQuickPermissions for parameter information
|
|
|
|
|
*/
|
|
|
|
|
private function checkPermissionHooks( $action, $user, $errors, $doExpensiveQueries, $short ) {
|
2007-10-10 09:56:47 +00:00
|
|
|
// Use getUserPermissionsErrors instead
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !wfRunHooks( 'userCan', array( &$this, &$user, $action, &$result ) ) ) {
|
2007-08-01 10:19:26 +00:00
|
|
|
return $result ? array() : array( array( 'badaccess-group0' ) );
|
2006-02-05 18:47:40 +00:00
|
|
|
}
|
2009-01-29 21:09:14 +00:00
|
|
|
// Check getUserPermissionsErrors hook
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !wfRunHooks( 'getUserPermissionsErrors', array( &$this, &$user, $action, &$result ) ) ) {
|
2010-05-24 09:55:46 +00:00
|
|
|
$errors = $this->resultToError( $errors, $result );
|
2009-01-29 21:09:14 +00:00
|
|
|
}
|
|
|
|
|
// Check getUserPermissionsErrorsExpensive hook
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $doExpensiveQueries && !( $short && count( $errors ) > 0 ) &&
|
|
|
|
|
!wfRunHooks( 'getUserPermissionsErrorsExpensive', array( &$this, &$user, $action, &$result ) ) ) {
|
2010-05-24 09:55:46 +00:00
|
|
|
$errors = $this->resultToError( $errors, $result );
|
2009-01-29 21:09:14 +00:00
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check permissions on special pages & namespaces
|
|
|
|
|
* @see checkQuickPermissions for parameter information
|
|
|
|
|
*/
|
|
|
|
|
private function checkSpecialsAndNSPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) {
|
2009-02-06 14:35:17 +00:00
|
|
|
# Only 'createaccount' and 'execute' can be performed on
|
|
|
|
|
# special pages, which don't actually exist in the DB.
|
2008-05-23 10:34:11 +00:00
|
|
|
$specialOKActions = array( 'createaccount', 'execute' );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( NS_SPECIAL == $this->mNamespace && !in_array( $action, $specialOKActions ) ) {
|
|
|
|
|
$errors[] = array( 'ns-specialprotected' );
|
2004-10-27 07:37:35 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2009-02-06 14:35:17 +00:00
|
|
|
# Check $wgNamespaceProtection for restricted namespaces
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->isNamespaceProtected() ) {
|
|
|
|
|
$ns = $this->mNamespace == NS_MAIN ?
|
2008-12-08 00:10:22 +00:00
|
|
|
wfMsg( 'nstab-main' ) : $this->getNsText();
|
2010-04-24 06:22:11 +00:00
|
|
|
$errors[] = $this->mNamespace == NS_MEDIAWIKI ?
|
|
|
|
|
array( 'protectedinterface' ) : array( 'namespaceprotected', $ns );
|
2004-10-27 07:37:35 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check CSS/JS sub-page permissions
|
|
|
|
|
* @see checkQuickPermissions for parameter information
|
|
|
|
|
*/
|
|
|
|
|
private function checkCSSandJSPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) {
|
2009-02-06 14:35:17 +00:00
|
|
|
# Protect css/js subpages of user pages
|
2004-04-28 19:30:21 +00:00
|
|
|
# XXX: this might be better using restrictions
|
2009-12-14 20:37:51 +00:00
|
|
|
# XXX: Find a way to work around the php bug that prevents using $this->userCanEditCssSubpage()
|
2009-08-01 16:44:44 +00:00
|
|
|
# and $this->userCanEditJsSubpage() from working
|
2009-08-02 08:31:29 +00:00
|
|
|
# XXX: right 'editusercssjs' is deprecated, for backward compatibility only
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $action != 'patrol' && !$user->isAllowed( 'editusercssjs' )
|
|
|
|
|
&& !preg_match( '/^' . preg_quote( $user->getName(), '/' ) . '\//', $this->mTextform ) ) {
|
|
|
|
|
if ( $this->isCssSubpage() && !$user->isAllowed( 'editusercss' ) ) {
|
|
|
|
|
$errors[] = array( 'customcssjsprotected' );
|
|
|
|
|
} else if ( $this->isJsSubpage() && !$user->isAllowed( 'edituserjs' ) ) {
|
|
|
|
|
$errors[] = array( 'customcssjsprotected' );
|
|
|
|
|
}
|
2004-10-27 07:37:35 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check against page_restrictions table requirements on this
|
|
|
|
|
* page. The user must possess all required rights for this
|
|
|
|
|
* action.
|
|
|
|
|
* @see checkQuickPermissions for parameter information
|
|
|
|
|
*/
|
|
|
|
|
private function checkPageRestrictions( $action, $user, $errors, $doExpensiveQueries, $short ) {
|
|
|
|
|
foreach ( $this->getRestrictions( $action ) as $right ) {
|
2009-02-06 14:35:17 +00:00
|
|
|
// Backwards compatibility, rewrite sysop -> protect
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $right == 'sysop' ) {
|
2009-02-06 14:35:17 +00:00
|
|
|
$right = 'protect';
|
|
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $right != '' && !$user->isAllowed( $right ) ) {
|
2009-02-06 14:35:17 +00:00
|
|
|
// Users with 'editprotected' permission can edit protected pages
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $action == 'edit' && $user->isAllowed( 'editprotected' ) ) {
|
2009-02-06 14:35:17 +00:00
|
|
|
// Users with 'editprotected' permission cannot edit protected pages
|
|
|
|
|
// with cascading option turned on.
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->mCascadeRestriction ) {
|
2009-02-06 14:35:17 +00:00
|
|
|
$errors[] = array( 'protectedpagetext', $right );
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$errors[] = array( 'protectedpagetext', $right );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check restrictions on cascading pages.
|
|
|
|
|
* @see checkQuickPermissions for parameter information
|
|
|
|
|
*/
|
|
|
|
|
private function checkCascadingSourcesRestrictions( $action, $user, $errors, $doExpensiveQueries, $short ) {
|
|
|
|
|
if ( $doExpensiveQueries && !$this->isCssJsSubpage() ) {
|
|
|
|
|
# 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
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( isset( $restrictions[$action] ) ) {
|
|
|
|
|
foreach ( $restrictions[$action] as $right ) {
|
2007-03-14 22:57:32 +00:00
|
|
|
$right = ( $right == 'sysop' ) ? 'protect' : $right;
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $right != '' && !$user->isAllowed( $right ) ) {
|
2007-08-01 10:19:26 +00:00
|
|
|
$pages = '';
|
2010-04-24 06:22:11 +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
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
return $errors;
|
|
|
|
|
}
|
2007-12-01 09:08:43 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
/**
|
|
|
|
|
* Check action permissions not already checked in checkQuickPermissions
|
|
|
|
|
* @see checkQuickPermissions for parameter information
|
|
|
|
|
*/
|
|
|
|
|
private function checkActionPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) {
|
|
|
|
|
if ( $action == 'protect' ) {
|
|
|
|
|
if ( $this->getUserPermissionsErrors( 'edit', $user ) != array() ) {
|
|
|
|
|
// If they can't edit, they shouldn't protect.
|
|
|
|
|
$errors[] = array( 'protect-cantedit' );
|
|
|
|
|
}
|
|
|
|
|
} elseif ( $action == 'create' ) {
|
2007-12-11 09:51:56 +00:00
|
|
|
$title_protection = $this->getTitleProtection();
|
2010-04-23 19:36:37 +00:00
|
|
|
if( $title_protection ) {
|
|
|
|
|
if( $title_protection['pt_create_perm'] == 'sysop' ) {
|
|
|
|
|
$title_protection['pt_create_perm'] = 'protect'; // B/C
|
2008-12-08 00:10:22 +00:00
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
if( $title_protection['pt_create_perm'] == '' || !$user->isAllowed( $title_protection['pt_create_perm'] ) ) {
|
|
|
|
|
$errors[] = array( 'titleprotected', User::whoIs( $title_protection['pt_user'] ), $title_protection['pt_reason'] );
|
2007-12-11 09:51:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
} elseif ( $action == 'move' ) {
|
2008-10-11 08:26:01 +00:00
|
|
|
// Check for immobile pages
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !MWNamespace::isMovable( $this->mNamespace ) ) {
|
2008-10-11 08:26:01 +00:00
|
|
|
// Specific message for this case
|
|
|
|
|
$errors[] = array( 'immobile-source-namespace', $this->getNsText() );
|
2010-04-24 06:22:11 +00:00
|
|
|
} elseif ( !$this->isMovable() ) {
|
2008-10-11 08:26:01 +00:00
|
|
|
// Less specific message for rarer cases
|
|
|
|
|
$errors[] = array( 'immobile-page' );
|
|
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
} elseif ( $action == 'move-target' ) {
|
|
|
|
|
if ( !MWNamespace::isMovable( $this->mNamespace ) ) {
|
2008-10-11 08:26:01 +00:00
|
|
|
$errors[] = array( 'immobile-target-namespace', $this->getNsText() );
|
2010-04-24 06:22:11 +00:00
|
|
|
} elseif ( !$this->isMovable() ) {
|
2008-10-11 08:26:01 +00:00
|
|
|
$errors[] = array( 'immobile-target-page' );
|
|
|
|
|
}
|
2007-07-11 08:43:21 +00:00
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check that the user isn't blocked from editting.
|
|
|
|
|
* @see checkQuickPermissions for parameter information
|
|
|
|
|
*/
|
|
|
|
|
private function checkUserBlock( $action, $user, $errors, $doExpensiveQueries, $short ) {
|
|
|
|
|
if( $short ) {
|
|
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
global $wgContLang;
|
|
|
|
|
global $wgLang;
|
|
|
|
|
global $wgEmailConfirmToEdit;
|
|
|
|
|
|
|
|
|
|
if ( $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount' ) {
|
|
|
|
|
$errors[] = array( 'confirmedittext' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Edit blocks should not affect reading. Account creation blocks handled at userlogin.
|
|
|
|
|
if ( $action != 'read' && $action != 'createaccount' && $user->isBlockedFrom( $this ) ) {
|
|
|
|
|
$block = $user->mBlock;
|
|
|
|
|
|
|
|
|
|
// This is from OutputPage::blockedPage
|
|
|
|
|
// Copied at r23888 by werdna
|
|
|
|
|
|
|
|
|
|
$id = $user->blockedBy();
|
|
|
|
|
$reason = $user->blockedFor();
|
|
|
|
|
if ( $reason == '' ) {
|
|
|
|
|
$reason = wfMsg( 'blockednoreason' );
|
|
|
|
|
}
|
|
|
|
|
$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;
|
|
|
|
|
$blockTimestamp = $wgLang->timeanddate( wfTimestamp( TS_MW, $user->mBlock->mTimestamp ), true );
|
|
|
|
|
if ( $blockExpiry == 'infinity' ) {
|
|
|
|
|
// Entry in database (table ipblocks) is 'infinity' but 'ipboptions' uses 'infinite' or 'indefinite'
|
|
|
|
|
$scBlockExpiryOptions = wfMsg( 'ipboptions' );
|
|
|
|
|
|
|
|
|
|
foreach ( explode( ',', $scBlockExpiryOptions ) as $option ) {
|
2010-06-09 11:44:05 +00:00
|
|
|
if ( !strpos( $option, ':' ) )
|
2010-04-24 06:22:11 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
$errors[] = array( ( $block->mAuto ? 'autoblockedtext' : 'blockedtext' ), $link, $reason, $ip, $name,
|
|
|
|
|
$blockid, $blockExpiry, $intended, $blockTimestamp );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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)
|
|
|
|
|
*
|
|
|
|
|
* @param $action \type{\string} action that permission needs to be checked for
|
|
|
|
|
* @param $user \type{User} user to check
|
|
|
|
|
* @param $doExpensiveQueries \type{\bool} Set this to false to avoid doing unnecessary queries.
|
|
|
|
|
* @param $short \type{\bool} Set this to true to stop after the first permission error.
|
|
|
|
|
* @return \type{\array} Array of arrays of the arguments to wfMsg to explain permissions problems.
|
|
|
|
|
*/
|
|
|
|
|
protected function getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries = true, $short = false ) {
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$errors = array();
|
|
|
|
|
$checks = array( 'checkQuickPermissions',
|
|
|
|
|
'checkPermissionHooks',
|
|
|
|
|
'checkSpecialsAndNSPermissions',
|
|
|
|
|
'checkCSSandJSPermissions',
|
|
|
|
|
'checkPageRestrictions',
|
|
|
|
|
'checkCascadingSourcesRestrictions',
|
|
|
|
|
'checkActionPermissions',
|
|
|
|
|
'checkUserBlock' );
|
|
|
|
|
|
|
|
|
|
while( count( $checks ) > 0 &&
|
|
|
|
|
!( $short && count( $errors ) > 0 ) ) {
|
|
|
|
|
$method = array_shift( $checks );
|
|
|
|
|
$errors = $this->$method( $action, $user, $errors, $doExpensiveQueries, $short );
|
|
|
|
|
}
|
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?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\mixed} An associative array representing any existent title
|
2007-12-16 19:57:40 +00:00
|
|
|
* 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;
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-08-06 16:26:04 +00:00
|
|
|
// Can't protect pages that exist.
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->exists() ) {
|
2009-08-06 16:26:04 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2008-01-10 22:15:33 +00:00
|
|
|
|
2010-04-24 00:23:57 +00:00
|
|
|
if ( !isset( $this->mTitleProtection ) ) {
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$res = $dbr->select( 'protected_titles', '*',
|
|
|
|
|
array( 'pt_namespace' => $this->getNamespace(), 'pt_title' => $this->getDBkey() ),
|
|
|
|
|
__METHOD__ );
|
2007-12-11 09:51:56 +00:00
|
|
|
|
2010-04-24 00:23:57 +00:00
|
|
|
// fetchRow returns false if there are no rows.
|
|
|
|
|
$this->mTitleProtection = $dbr->fetchRow( $res );
|
2007-12-11 09:51:56 +00:00
|
|
|
}
|
2010-04-24 00:23:57 +00:00
|
|
|
return $this->mTitleProtection;
|
2007-12-11 09:51:56 +00:00
|
|
|
}
|
|
|
|
|
|
2008-08-11 04:39:00 +00:00
|
|
|
/**
|
|
|
|
|
* Update the title protection status
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $create_perm \type{\string} Permission required for creation
|
|
|
|
|
* @param $reason \type{\string} Reason for protection
|
|
|
|
|
* @param $expiry \type{\string} Expiry timestamp
|
2010-03-15 23:22:50 +00:00
|
|
|
* @return boolean true
|
2008-08-11 04:39:00 +00:00
|
|
|
*/
|
2007-12-11 09:51:56 +00:00
|
|
|
public function updateTitleProtection( $create_perm, $reason, $expiry ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
global $wgUser, $wgContLang;
|
2007-12-11 09:51:56 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $create_perm == implode( ',', $this->getRestrictions( 'create' ) )
|
|
|
|
|
&& $expiry == $this->mRestrictionsExpiry['create'] ) {
|
2007-12-11 09:51:56 +00:00
|
|
|
// No change
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
list ( $namespace, $title ) = array( $this->getNamespace(), $this->getDBkey() );
|
2007-12-11 09:51:56 +00:00
|
|
|
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
$encodedExpiry = Block::encodeExpiry( $expiry, $dbw );
|
2007-12-11 09:51:56 +00:00
|
|
|
|
|
|
|
|
$expiry_description = '';
|
|
|
|
|
if ( $encodedExpiry != 'infinity' ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
$expiry_description = ' (' . wfMsgForContent( 'protect-expiring', $wgContLang->timeanddate( $expiry ),
|
|
|
|
|
$wgContLang->date( $expiry ) , $wgContLang->time( $expiry ) ) . ')';
|
2007-12-11 09:51:56 +00:00
|
|
|
}
|
2008-09-13 05:33:24 +00:00
|
|
|
else {
|
2010-04-24 06:22:11 +00:00
|
|
|
$expiry_description .= ' (' . wfMsgForContent( 'protect-expiry-indefinite' ) . ')';
|
2008-09-13 05:33:24 +00:00
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2007-12-11 09:51:56 +00:00
|
|
|
# Update protection table
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $create_perm != '' ) {
|
|
|
|
|
$dbw->replace( 'protected_titles', array( array( 'pt_namespace', 'pt_title' ) ),
|
2009-07-31 22:57:29 +00:00
|
|
|
array(
|
|
|
|
|
'pt_namespace' => $namespace,
|
|
|
|
|
'pt_title' => $title,
|
|
|
|
|
'pt_create_perm' => $create_perm,
|
2010-04-24 06:22:11 +00:00
|
|
|
'pt_timestamp' => Block::encodeExpiry( wfTimestampNow(), $dbw ),
|
2009-07-31 22:57:29 +00:00
|
|
|
'pt_expiry' => $encodedExpiry,
|
|
|
|
|
'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
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $dbw->affectedRows() ) {
|
2009-07-31 22:57:29 +00:00
|
|
|
$log = new LogPage( 'protect' );
|
2007-12-11 09:51:56 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $create_perm ) {
|
|
|
|
|
$params = array( "[create=$create_perm] $expiry_description", '' );
|
2009-07-31 22:57:29 +00:00
|
|
|
$log->addEntry( ( isset( $this->mRestrictions['create'] ) && $this->mRestrictions['create'] ) ? 'modify' : 'protect', $this, trim( $reason ), $params );
|
|
|
|
|
} else {
|
|
|
|
|
$log->addEntry( 'unprotect', $this, $reason );
|
|
|
|
|
}
|
2007-12-11 09:51:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-08-11 04:39:00 +00:00
|
|
|
* Remove any title protection due to page existing
|
2007-12-11 09:51:56 +00:00
|
|
|
*/
|
|
|
|
|
public function deleteTitleProtection() {
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
|
2008-04-14 07:45:50 +00:00
|
|
|
$dbw->delete( 'protected_titles',
|
2009-12-14 20:37:51 +00:00
|
|
|
array( 'pt_namespace' => $this->getNamespace(), 'pt_title' => $this->getDBkey() ),
|
2008-11-13 22:20:51 +00:00
|
|
|
__METHOD__ );
|
2007-12-11 09:51:56 +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
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool} TRUE or FALSE
|
2005-04-25 04:34:46 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isMovable() {
|
2008-11-13 22:20:51 +00:00
|
|
|
return MWNamespace::isMovable( $this->getNamespace() ) && $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?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return \type{\bool}
|
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;
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-06-23 02:03:47 +00:00
|
|
|
static $useShortcut = null;
|
|
|
|
|
|
|
|
|
|
# Initialize the $useShortcut boolean, to determine if we can skip quite a bit of code below
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( is_null( $useShortcut ) ) {
|
2009-06-23 02:03:47 +00:00
|
|
|
global $wgRevokePermissions;
|
|
|
|
|
$useShortcut = true;
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( empty( $wgGroupPermissions['*']['read'] ) ) {
|
2009-06-23 02:03:47 +00:00
|
|
|
# Not a public wiki, so no shortcut
|
|
|
|
|
$useShortcut = false;
|
2010-04-24 06:22:11 +00:00
|
|
|
} elseif ( !empty( $wgRevokePermissions ) ) {
|
2009-06-24 00:37:44 +00:00
|
|
|
/*
|
|
|
|
|
* Iterate through each group with permissions being revoked (key not included since we don't care
|
|
|
|
|
* what the group name is), then check if the read permission is being revoked. If it is, then
|
|
|
|
|
* we don't use the shortcut below since the user might not be able to read, even though anon
|
|
|
|
|
* reading is allowed.
|
|
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $wgRevokePermissions as $perms ) {
|
|
|
|
|
if ( !empty( $perms['read'] ) ) {
|
2009-06-23 02:03:47 +00:00
|
|
|
# We might be removing the read right from the user, so no shortcut
|
|
|
|
|
$useShortcut = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-14 20:37:51 +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;
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-23 02:03:47 +00:00
|
|
|
# Shortcut for public wikis, allows skipping quite a bit of code
|
|
|
|
|
if ( $useShortcut )
|
|
|
|
|
return true;
|
|
|
|
|
|
2010-04-24 06:22:11 +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.
|
|
|
|
|
*/
|
2010-04-24 06:22:11 +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
|
|
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !is_array( $wgWhitelistRead ) ) {
|
2007-09-11 14:46:04 +00:00
|
|
|
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
|
2010-04-24 06:22:11 +00:00
|
|
|
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
|
|
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->getNamespace() == NS_MAIN ) {
|
|
|
|
|
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
|
|
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->getNamespace() == NS_SPECIAL ) {
|
2008-01-14 09:13:04 +00:00
|
|
|
$name = $this->getDBkey();
|
2010-04-24 06:22:11 +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();
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( in_array( $pure, $wgWhitelistRead, true ) )
|
2007-06-28 22:34:36 +00:00
|
|
|
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?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return \type{\bool}
|
2005-02-21 11:28:07 +00:00
|
|
|
*/
|
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?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return \type{\bool}
|
2006-12-12 19:14:29 +00:00
|
|
|
*/
|
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.)
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return \type{\bool}
|
2008-05-23 01:11:17 +00:00
|
|
|
*/
|
|
|
|
|
public function hasSubpages() {
|
2010-04-24 06:22:11 +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.
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( isset( $this->mHasSubpages ) ) {
|
2008-05-23 01:11:17 +00:00
|
|
|
return $this->mHasSubpages;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-09 14:16:51 +00:00
|
|
|
$subpages = $this->getSubpages( 1 );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $subpages instanceof TitleArray )
|
2009-02-09 14:16:51 +00:00
|
|
|
return $this->mHasSubpages = (bool)$subpages->count();
|
|
|
|
|
return $this->mHasSubpages = false;
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-02-09 14:16:51 +00:00
|
|
|
/**
|
|
|
|
|
* Get all subpages of this page.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2009-02-09 14:16:51 +00:00
|
|
|
* @param $limit Maximum number of subpages to fetch; -1 for no limit
|
|
|
|
|
* @return mixed TitleArray, or empty array if this page's namespace
|
|
|
|
|
* doesn't allow subpages
|
|
|
|
|
*/
|
2009-02-19 11:20:29 +00:00
|
|
|
public function getSubpages( $limit = -1 ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !MWNamespace::hasSubpages( $this->getNamespace() ) )
|
2009-02-09 14:16:51 +00:00
|
|
|
return array();
|
|
|
|
|
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$conds['page_namespace'] = $this->getNamespace();
|
2009-10-21 19:53:03 +00:00
|
|
|
$conds[] = 'page_title ' . $dbr->buildLike( $this->getDBkey() . '/', $dbr->anyString() );
|
2009-02-09 14:16:51 +00:00
|
|
|
$options = array();
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $limit > -1 )
|
2009-02-09 14:16:51 +00:00
|
|
|
$options['LIMIT'] = $limit;
|
|
|
|
|
return $this->mSubpages = TitleArray::newFromResult(
|
|
|
|
|
$dbr->select( 'page',
|
2009-03-03 22:56:17 +00:00
|
|
|
array( 'page_id', 'page_namespace', 'page_title', 'page_is_redirect' ),
|
2009-02-09 14:16:51 +00:00
|
|
|
$conds,
|
|
|
|
|
__METHOD__,
|
|
|
|
|
$options
|
|
|
|
|
)
|
2008-05-23 01:11:17 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-29 04:31:19 +00:00
|
|
|
/**
|
|
|
|
|
* Could this page contain custom CSS or JavaScript, based
|
|
|
|
|
* on the title?
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2007-06-29 04:31:19 +00:00
|
|
|
*/
|
|
|
|
|
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?
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isCssJsSubpage() {
|
2010-04-24 06:22:11 +00:00
|
|
|
return ( NS_USER == $this->mNamespace and preg_match( "/\\/.*\\.(?:css|js)$/", $this->mTextform ) );
|
2004-05-10 13:15:28 +00:00
|
|
|
}
|
2010-03-23 21:40:02 +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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return \type{\bool}
|
2006-02-23 14:37:51 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isValidCssJsSubpage() {
|
2006-07-02 15:57:59 +00:00
|
|
|
if ( $this->isCssJsSubpage() ) {
|
2010-03-05 22:42:53 +00:00
|
|
|
$name = $this->getSkinFromCssJsSubpage();
|
|
|
|
|
if ( $name == 'common' ) return true;
|
2006-07-02 15:57:59 +00:00
|
|
|
$skinNames = Skin::getSkinNames();
|
2010-03-05 22:42:53 +00:00
|
|
|
return array_key_exists( $name, $skinNames );
|
2006-07-02 15:57:59 +00:00
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2006-02-23 14:37:51 +00:00
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2006-02-23 14:37:51 +00:00
|
|
|
/**
|
|
|
|
|
* Trim down a .css or .js subpage title to get the corresponding skin name
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2010-03-15 23:22:50 +00:00
|
|
|
* @return string containing skin name from .css or .js subpage title
|
2006-02-23 14:37:51 +00:00
|
|
|
*/
|
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 ) );
|
|
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Is this a .css subpage of a user page?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return \type{\bool}
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isCssSubpage() {
|
2010-04-24 06:22:11 +00:00
|
|
|
return ( NS_USER == $this->mNamespace && preg_match( "/\\/.*\\.css$/", $this->mTextform ) );
|
2004-05-10 13:15:28 +00:00
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Is this a .js subpage of a user page?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return \type{\bool}
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isJsSubpage() {
|
2010-04-24 06:22:11 +00:00
|
|
|
return ( NS_USER == $this->mNamespace && preg_match( "/\\/.*\\.js$/", $this->mTextform ) );
|
2004-05-10 13:15:28 +00:00
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
2009-08-01 16:44:44 +00:00
|
|
|
* Protect css subpages of user pages: can $wgUser edit
|
|
|
|
|
* this page?
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2009-08-01 16:44:44 +00:00
|
|
|
* @todo XXX: this might be better using restrictions
|
|
|
|
|
*/
|
|
|
|
|
public function userCanEditCssSubpage() {
|
|
|
|
|
global $wgUser;
|
2010-04-24 06:22:11 +00:00
|
|
|
return ( ( $wgUser->isAllowed( 'editusercssjs' ) && $wgUser->isAllowed( 'editusercss' ) )
|
|
|
|
|
|| preg_match( '/^' . preg_quote( $wgUser->getName(), '/' ) . '\//', $this->mTextform ) );
|
2009-08-01 16:44:44 +00:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Protect js subpages of user pages: can $wgUser edit
|
2004-09-30 05:21:20 +00:00
|
|
|
* this page?
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2004-09-30 05:21:20 +00:00
|
|
|
* @todo XXX: this might be better using restrictions
|
|
|
|
|
*/
|
2009-08-01 16:44:44 +00:00
|
|
|
public function userCanEditJsSubpage() {
|
2004-05-10 13:15:28 +00:00
|
|
|
global $wgUser;
|
2010-04-24 06:22:11 +00:00
|
|
|
return ( ( $wgUser->isAllowed( 'editusercssjs' ) && $wgUser->isAllowed( 'edituserjs' ) )
|
|
|
|
|
|| 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.
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool} If the page is subject to cascading restrictions.
|
2007-01-12 07:31:34 +00:00
|
|
|
*/
|
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.
|
|
|
|
|
*
|
2010-04-24 06:22:11 +00:00
|
|
|
* @param $getPages \type{\bool} Whether or not to retrieve the actual pages
|
2010-03-23 21:40:02 +00:00
|
|
|
* that the restrictions have come from.
|
|
|
|
|
* @return \type{\arrayof{mixed title array, restriction array}} Array of the Title
|
|
|
|
|
* objects of the pages from which cascading restrictions have come,
|
2010-04-24 06:22:11 +00:00
|
|
|
* false for none, or true if such restrictions exist, but $getPages was not set.
|
2010-03-23 21:40:02 +00:00
|
|
|
* The restriction array is an array of each type, each of which contains a
|
|
|
|
|
* array of unique groups.
|
2007-01-12 04:43:33 +00:00
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
public function getCascadeProtectionSources( $getPages = true ) {
|
2007-03-14 22:57:32 +00:00
|
|
|
$pagerestrictions = array();
|
|
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( isset( $this->mCascadeSources ) && $getPages ) {
|
2007-03-14 22:57:32 +00:00
|
|
|
return array( $this->mCascadeSources, $this->mCascadingRestrictions );
|
2010-04-24 06:22:11 +00:00
|
|
|
} else if ( isset( $this->mHasCascadingRestrictions ) && !$getPages ) {
|
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-11-06 22:30:55 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2007-01-12 04:43:33 +00:00
|
|
|
|
2008-12-01 17:14:30 +00:00
|
|
|
if ( $this->getNamespace() == NS_FILE ) {
|
2010-04-24 06:22:11 +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 {
|
2010-04-24 06:22:11 +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
|
|
|
}
|
|
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $getPages ) {
|
|
|
|
|
$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
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
$sources = $getPages ? array() : false;
|
2007-01-22 19:52:32 +00:00
|
|
|
$now = wfTimestampNow();
|
|
|
|
|
$purgeExpired = false;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $res as $row ) {
|
2007-01-22 19:52:32 +00:00
|
|
|
$expiry = Block::decodeExpiry( $row->pr_expiry );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $expiry > $now ) {
|
|
|
|
|
if ( $getPages ) {
|
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;
|
2010-04-24 06:22:11 +00:00
|
|
|
$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
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-11-06 10:27:44 +00:00
|
|
|
if ( !isset( $pagerestrictions[$row->pr_type] ) ) {
|
|
|
|
|
$pagerestrictions[$row->pr_type] = array();
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( isset( $pagerestrictions[$row->pr_type] ) &&
|
|
|
|
|
!in_array( $row->pr_level, $pagerestrictions[$row->pr_type] ) ) {
|
|
|
|
|
$pagerestrictions[$row->pr_type][] = $row->pr_level;
|
2007-03-14 22:57:32 +00:00
|
|
|
}
|
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
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $purgeExpired ) {
|
2007-01-22 19:52:32 +00:00
|
|
|
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
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $getPages ) {
|
2007-01-12 08:37:07 +00:00
|
|
|
$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;
|
|
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
|
2007-03-14 22:57:32 +00:00
|
|
|
return array( $sources, $pagerestrictions );
|
2007-01-10 23:32:38 +00:00
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2010-03-15 23:22:50 +00:00
|
|
|
/**
|
|
|
|
|
* Returns cascading restrictions for the current article
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return Boolean
|
2010-03-15 23:22:50 +00:00
|
|
|
*/
|
2007-01-11 00:31:04 +00:00
|
|
|
function areRestrictionsCascading() {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$this->mRestrictionsLoaded ) {
|
2007-01-10 23:32:38 +00:00
|
|
|
$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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $res \type{Resource} restrictions as an SQL result.
|
2010-03-23 21:40:02 +00:00
|
|
|
* @param $oldFashionedRestrictions string comma-separated list of page
|
|
|
|
|
* restrictions from page table (pre 1.10)
|
2004-11-24 12:55:48 +00:00
|
|
|
*/
|
2009-12-11 21:07:27 +00:00
|
|
|
private function loadRestrictionsFromResultWrapper( $res, $oldFashionedRestrictions = null ) {
|
2009-08-06 16:26:04 +00:00
|
|
|
$rows = array();
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
while ( $row = $dbr->fetchObject( $res ) ) {
|
2009-08-06 16:26:04 +00:00
|
|
|
$rows[] = $row;
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-08-06 16:26:04 +00:00
|
|
|
$this->loadRestrictionsFromRows( $rows, $oldFashionedRestrictions );
|
|
|
|
|
}
|
2010-03-23 21:40:02 +00:00
|
|
|
|
2010-03-15 23:22:50 +00:00
|
|
|
/**
|
2010-03-23 21:40:02 +00:00
|
|
|
* Compiles list of active page restrictions from both page table (pre 1.10)
|
|
|
|
|
* and page_restrictions table
|
|
|
|
|
*
|
2010-03-15 23:22:50 +00:00
|
|
|
* @param $rows array of db result objects
|
2010-03-23 21:40:02 +00:00
|
|
|
* @param $oldFashionedRestrictions string comma-separated list of page
|
|
|
|
|
* restrictions from page table (pre 1.10)
|
2010-03-15 23:22:50 +00:00
|
|
|
*/
|
2009-12-11 21:07:27 +00:00
|
|
|
public function loadRestrictionsFromRows( $rows, $oldFashionedRestrictions = null ) {
|
2008-03-04 21:27:23 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-11-09 12:05:30 +00:00
|
|
|
$restrictionTypes = $this->getRestrictionTypes();
|
2008-03-04 21:27:23 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $restrictionTypes as $type ) {
|
2008-03-04 21:27:23 +00:00
|
|
|
$this->mRestrictions[$type] = array();
|
2010-04-24 06:22:11 +00:00
|
|
|
$this->mRestrictionsExpiry[$type] = Block::decodeExpiry( '' );
|
2008-03-04 21:27:23 +00:00
|
|
|
}
|
2007-01-10 23:32:38 +00:00
|
|
|
|
2008-02-26 20:41:21 +00:00
|
|
|
$this->mCascadeRestriction = false;
|
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).
|
|
|
|
|
|
2009-12-11 21:07:27 +00:00
|
|
|
if ( $oldFashionedRestrictions === null ) {
|
2009-12-14 20:37:51 +00:00
|
|
|
$oldFashionedRestrictions = $dbr->selectField( 'page', 'page_restrictions',
|
2008-05-28 17:50:17 +00:00
|
|
|
array( 'page_id' => $this->getArticleId() ), __METHOD__ );
|
2007-01-12 01:44:33 +00:00
|
|
|
}
|
|
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $oldFashionedRestrictions != '' ) {
|
2007-01-12 01:44:33 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( explode( ':', trim( $oldFashionedRestrictions ) ) as $restrict ) {
|
2007-01-12 01:44:33 +00:00
|
|
|
$temp = explode( '=', trim( $restrict ) );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( count( $temp ) == 1 ) {
|
2007-01-12 01:44:33 +00:00
|
|
|
// 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
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( count( $rows ) ) {
|
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
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $rows as $row ) {
|
2007-01-12 01:44:33 +00:00
|
|
|
# Cycle through all the restrictions.
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2009-11-06 10:27:44 +00:00
|
|
|
// Don't take care of restrictions types that aren't allowed
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !in_array( $row->pr_type, $restrictionTypes ) )
|
2008-03-04 21:27:23 +00:00
|
|
|
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 ) {
|
2008-09-13 05:33:24 +00:00
|
|
|
$this->mRestrictionsExpiry[$row->pr_type] = $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
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $purgeExpired ) {
|
2007-01-22 19:52:32 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2008-08-11 04:39:00 +00:00
|
|
|
/**
|
|
|
|
|
* Load restrictions from the page_restrictions table
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @param $oldFashionedRestrictions string comma-separated list of page
|
|
|
|
|
* restrictions from page table (pre 1.10)
|
2008-08-11 04:39:00 +00:00
|
|
|
*/
|
2009-12-11 21:07:27 +00:00
|
|
|
public function loadRestrictions( $oldFashionedRestrictions = null ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$this->mRestrictionsLoaded ) {
|
|
|
|
|
if ( $this->exists() ) {
|
2007-12-11 09:51:56 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
|
|
|
|
|
$res = $dbr->select( 'page_restrictions', '*',
|
|
|
|
|
array ( 'pr_page' => $this->getArticleId() ), __METHOD__ );
|
|
|
|
|
|
2009-08-06 16:26:04 +00:00
|
|
|
$this->loadRestrictionsFromResultWrapper( $res, $oldFashionedRestrictions );
|
2007-12-11 09:51:56 +00:00
|
|
|
} else {
|
|
|
|
|
$title_protection = $this->getTitleProtection();
|
2007-04-16 15:24:04 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $title_protection ) {
|
2007-12-11 09:51:56 +00:00
|
|
|
$now = wfTimestampNow();
|
2010-04-24 06:22:11 +00:00
|
|
|
$expiry = Block::decodeExpiry( $title_protection['pt_expiry'] );
|
2007-12-11 09:51:56 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$expiry || $expiry > $now ) {
|
2007-12-11 09:51:56 +00:00
|
|
|
// Apply the restrictions
|
2008-09-13 05:33:24 +00:00
|
|
|
$this->mRestrictionsExpiry['create'] = $expiry;
|
2010-04-24 06:22:11 +00:00
|
|
|
$this->mRestrictions['create'] = explode( ',', trim( $title_protection['pt_create_perm'] ) );
|
2007-12-11 09:51:56 +00:00
|
|
|
} else { // Get rid of the old restrictions
|
|
|
|
|
Title::purgeExpiredRestrictions();
|
|
|
|
|
}
|
2008-07-03 12:25:52 +00:00
|
|
|
} else {
|
2010-04-24 06:22:11 +00:00
|
|
|
$this->mRestrictionsExpiry['create'] = 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
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $action \type{\string} action that permission needs to be checked for
|
2008-08-21 08:39:31 +00:00
|
|
|
* @return \type{\arrayof{\string}} the array of groups allowed to edit this article
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-10-18 14:55:48 +00:00
|
|
|
public function getRestrictions( $action ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$this->mRestrictionsLoaded ) {
|
2007-12-11 09:51:56 +00:00
|
|
|
$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
|
|
|
|
2008-09-16 04:09:06 +00:00
|
|
|
/**
|
|
|
|
|
* Get the expiry time for the restriction against a given action
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2009-12-14 20:37:51 +00:00
|
|
|
* @return 14-char timestamp, or 'infinity' if the page is protected forever
|
2010-03-15 23:22:50 +00:00
|
|
|
* or not protected at all, or false if the action is not recognised.
|
2008-09-16 04:09:06 +00:00
|
|
|
*/
|
|
|
|
|
public function getRestrictionExpiry( $action ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$this->mRestrictionsLoaded ) {
|
2008-09-16 04:09:06 +00:00
|
|
|
$this->loadRestrictions();
|
|
|
|
|
}
|
|
|
|
|
return isset( $this->mRestrictionsExpiry[$action] ) ? $this->mRestrictionsExpiry[$action] : false;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Is there a version of this page in the deletion archive?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\int} the number of archived revisions
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isDeleted() {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->getNamespace() < 0 ) {
|
2008-08-10 20:34:46 +00:00
|
|
|
$n = 0;
|
|
|
|
|
} else {
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2009-12-14 20:37:51 +00:00
|
|
|
$n = $dbr->selectField( 'archive', 'COUNT(*)',
|
2009-02-24 16:17:23 +00:00
|
|
|
array( 'ar_namespace' => $this->getNamespace(), 'ar_title' => $this->getDBkey() ),
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->getNamespace() == NS_FILE ) {
|
2008-08-10 20:34:46 +00:00
|
|
|
$n += $dbr->selectField( 'filearchive', 'COUNT(*)',
|
2009-02-24 16:17:23 +00:00
|
|
|
array( 'fa_name' => $this->getDBkey() ),
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
2008-08-10 20:34:46 +00:00
|
|
|
}
|
2008-08-10 10:30:52 +00:00
|
|
|
}
|
2008-08-10 20:34:46 +00:00
|
|
|
return (int)$n;
|
2003-08-31 22:21:50 +00:00
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-02-24 16:17:23 +00:00
|
|
|
/**
|
|
|
|
|
* Is there a version of this page in the deletion archive?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return Boolean
|
2009-02-24 16:17:23 +00:00
|
|
|
*/
|
|
|
|
|
public function isDeletedQuick() {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->getNamespace() < 0 ) {
|
2009-02-24 16:17:23 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$deleted = (bool)$dbr->selectField( 'archive', '1',
|
|
|
|
|
array( 'ar_namespace' => $this->getNamespace(), 'ar_title' => $this->getDBkey() ),
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$deleted && $this->getNamespace() == NS_FILE ) {
|
2009-02-24 16:17:23 +00:00
|
|
|
$deleted = (bool)$dbr->selectField( 'filearchive', '1',
|
|
|
|
|
array( 'fa_name' => $this->getDBkey() ),
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return $deleted;
|
|
|
|
|
}
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select
|
2009-12-14 20:37:51 +00:00
|
|
|
* for update
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\int} the ID
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-01-09 02:45:09 +00:00
|
|
|
public function getArticleID( $flags = 0 ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->getNamespace() < 0 ) {
|
2008-11-13 22:20:51 +00:00
|
|
|
return $this->mArticleID = 0;
|
|
|
|
|
}
|
2008-04-09 18:23:34 +00:00
|
|
|
$linkCache = LinkCache::singleton();
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $flags & GAID_FOR_UPDATE ) {
|
2006-01-05 02:05:53 +00:00
|
|
|
$oldUpdate = $linkCache->forUpdate( true );
|
2008-09-07 08:24:06 +00:00
|
|
|
$linkCache->clearLink( $this );
|
2006-01-05 02:05:53 +00:00
|
|
|
$this->mArticleID = $linkCache->addLinkObj( $this );
|
|
|
|
|
$linkCache->forUpdate( $oldUpdate );
|
2004-08-20 14:59:49 +00:00
|
|
|
} else {
|
2010-04-24 06:22:11 +00:00
|
|
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select for update
|
|
|
|
|
* @return \type{\bool}
|
2008-04-09 05:21:00 +00:00
|
|
|
*/
|
|
|
|
|
public function isRedirect( $flags = 0 ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !is_null( $this->mRedirect ) )
|
2008-04-09 16:32:14 +00:00
|
|
|
return $this->mRedirect;
|
2008-11-13 22:20:51 +00:00
|
|
|
# Calling getArticleID() loads the field from cache as needed
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$this->getArticleID( $flags ) ) {
|
2008-11-13 22:20:51 +00:00
|
|
|
return $this->mRedirect = false;
|
2008-04-09 05:21:00 +00:00
|
|
|
}
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select for update
|
|
|
|
|
* @return \type{\bool}
|
2008-04-09 05:21:00 +00:00
|
|
|
*/
|
|
|
|
|
public function getLength( $flags = 0 ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->mLength != -1 )
|
2008-04-09 16:32:14 +00:00
|
|
|
return $this->mLength;
|
2008-11-13 22:20:51 +00:00
|
|
|
# Calling getArticleID() loads the field from cache as needed
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$this->getArticleID( $flags ) ) {
|
2008-11-13 22:20:51 +00:00
|
|
|
return $this->mLength = 0;
|
2008-04-09 05:21:00 +00:00
|
|
|
}
|
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?
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select for update
|
2010-06-15 12:14:54 +00:00
|
|
|
* @return \type{\int} or 0 if the page doesn't exist
|
2008-05-06 14:54:17 +00:00
|
|
|
*/
|
|
|
|
|
public function getLatestRevID( $flags = 0 ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->mLatestID !== false )
|
2010-06-28 12:02:09 +00:00
|
|
|
return intval( $this->mLatestID );
|
2010-06-15 12:14:54 +00:00
|
|
|
# Calling getArticleID() loads the field from cache as needed
|
|
|
|
|
if ( !$this->getArticleID( $flags ) ) {
|
|
|
|
|
return $this->mLatestID = 0;
|
|
|
|
|
}
|
|
|
|
|
$linkCache = LinkCache::singleton();
|
|
|
|
|
$this->mLatestID = intval( $linkCache->getGoodLinkFieldObj( $this, 'revision' ) );
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2008-09-02 21:29:22 +00:00
|
|
|
return $this->mLatestID;
|
2005-07-01 10:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $newid \type{\int} the new Article ID
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
|
|
|
2010-03-11 05:32:04 +00:00
|
|
|
if ( $newid === false ) {
|
|
|
|
|
$this->mArticleID = -1;
|
|
|
|
|
} else {
|
|
|
|
|
$this->mArticleID = intval( $newid );
|
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
$this->mRestrictionsLoaded = false;
|
|
|
|
|
$this->mRestrictions = array();
|
2010-03-11 05:32:04 +00:00
|
|
|
$this->mRedirect = null;
|
|
|
|
|
$this->mLength = -1;
|
|
|
|
|
$this->mLatestID = false;
|
2003-04-14 23:10:40 +00:00
|
|
|
}
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool} true if the update succeded
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function invalidateCache() {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( wfReadOnly() ) {
|
2005-04-12 04:03:21 +00:00
|
|
|
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',
|
2009-12-14 20:37:51 +00:00
|
|
|
array( 'page_touched' => $dbw->timestamp() ),
|
|
|
|
|
$this->pageCond(),
|
2008-11-13 22:20:51 +00:00
|
|
|
__METHOD__
|
2004-07-10 03:09:26 +00:00
|
|
|
);
|
2008-12-28 14:19:39 +00:00
|
|
|
HTMLFileCache::clearFileCache( $this );
|
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
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $name \type{\string} the text
|
|
|
|
|
* @return \type{\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 = '';
|
2010-01-06 19:59:42 +00:00
|
|
|
if ( $this->mInterwiki != '' ) {
|
2004-08-16 20:14:35 +00:00
|
|
|
$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;
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-03-15 23:22:50 +00:00
|
|
|
/**
|
|
|
|
|
* Returns a simple regex that will match on characters and sequences invalid in titles.
|
|
|
|
|
* Note that this doesn't pick up many things that could be wrong with titles, but that
|
|
|
|
|
* replacing this regex with something valid will make many titles valid.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2010-03-15 23:22:50 +00:00
|
|
|
* @return string regex string
|
|
|
|
|
*/
|
2009-09-30 10:36:22 +00:00
|
|
|
static function getTitleInvalidRegex() {
|
2004-11-27 08:31:21 +00:00
|
|
|
static $rxTc = false;
|
2010-04-24 06:22:11 +00:00
|
|
|
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
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-09-30 10:36:22 +00:00
|
|
|
return $rxTc;
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-10-09 12:52:16 +00:00
|
|
|
/**
|
2010-03-15 23:22:50 +00:00
|
|
|
* Capitalize a text string for a title if it belongs to a namespace that capitalizes
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2010-03-15 23:22:50 +00:00
|
|
|
* @param $text string containing title to capitalize
|
2010-03-23 21:40:02 +00:00
|
|
|
* @param $ns int namespace index, defaults to NS_MAIN
|
|
|
|
|
* @return String containing capitalized title
|
2009-10-09 12:52:16 +00:00
|
|
|
*/
|
|
|
|
|
public static function capitalize( $text, $ns = NS_MAIN ) {
|
|
|
|
|
global $wgContLang;
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-10-09 12:52:16 +00:00
|
|
|
if ( MWNamespace::isCapitalized( $ns ) )
|
|
|
|
|
return $wgContLang->ucfirst( $text );
|
|
|
|
|
else
|
|
|
|
|
return $text;
|
|
|
|
|
}
|
2009-09-30 10:36:22 +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.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2009-09-30 10:36:22 +00:00
|
|
|
* @return \type{\bool} true on success
|
|
|
|
|
*/
|
|
|
|
|
private function secureAndSplit() {
|
2009-10-09 12:52:16 +00:00
|
|
|
global $wgContLang, $wgLocalInterwiki;
|
2009-09-30 10:36:22 +00:00
|
|
|
|
|
|
|
|
# Initialisation
|
|
|
|
|
$rxTc = self::getTitleInvalidRegex();
|
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.
|
2008-11-27 20:11:38 +00:00
|
|
|
$dbkey = preg_replace( '/\xE2\x80[\x8E\x8F\xAA-\xAE]/S', '', $dbkey );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2003-12-11 12:43:13 +00:00
|
|
|
# Clean up whitespace
|
2009-08-23 00:45:36 +00:00
|
|
|
# Note: use of the /u option on preg_replace here will cause
|
|
|
|
|
# input with invalid UTF-8 sequences to be nullified out in PHP 5.2.x,
|
|
|
|
|
# conveniently disabling them.
|
2003-12-11 12:43:13 +00:00
|
|
|
#
|
2009-09-25 15:15:33 +00:00
|
|
|
$dbkey = preg_replace( '/[ _\xA0\x{1680}\x{180E}\x{2000}-\x{200A}\x{2028}\x{2029}\x{202F}\x{205F}\x{3000}]+/u', '_', $dbkey );
|
2006-12-08 06:09:15 +00:00
|
|
|
$dbkey = trim( $dbkey, '_' );
|
2004-04-09 00:45:15 +00:00
|
|
|
|
2010-01-06 19:59:42 +00:00
|
|
|
if ( $dbkey == '' ) {
|
2003-10-01 10:26:26 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2010-04-24 06:22:11 +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}
|
2010-04-24 06:22:11 +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;
|
2009-01-15 18:36:59 +00:00
|
|
|
$prefixRegexp = "/^(.+?)_*:_*(.*)$/S";
|
2005-08-20 15:30:22 +00:00
|
|
|
do {
|
2006-11-29 11:43:58 +00:00
|
|
|
$m = array();
|
2009-01-15 18:36:59 +00:00
|
|
|
if ( preg_match( $prefixRegexp, $dbkey, $m ) ) {
|
2005-08-20 15:30:22 +00:00
|
|
|
$p = $m[1];
|
2010-03-26 20:55:55 +00:00
|
|
|
if ( ( $ns = $wgContLang->getNsIndex( $p ) ) !== false ) {
|
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;
|
2009-01-15 18:36:59 +00:00
|
|
|
# For Talk:X pages, check if X has a "namespace" prefix
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $ns == NS_TALK && preg_match( $prefixRegexp, $dbkey, $x ) ) {
|
|
|
|
|
if ( $wgContLang->getNsIndex( $x[1] ) )
|
2009-01-15 18:36:59 +00:00
|
|
|
return false; # Disallow Talk:File:x type titles...
|
2010-04-24 06:22:11 +00:00
|
|
|
else if ( Interwiki::isValidInterwiki( $x[1] ) )
|
2009-01-20 22:55:20 +00:00
|
|
|
return false; # Disallow Talk:Interwiki:x type titles...
|
2009-01-15 18:36:59 +00:00
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
} elseif ( Interwiki::isValidInterwiki( $p ) ) {
|
|
|
|
|
if ( !$firstPass ) {
|
2005-08-20 15:30:22 +00:00
|
|
|
# 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 ) ) {
|
2010-04-24 06:22:11 +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;
|
2010-04-24 06:22:11 +00:00
|
|
|
} 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!
|
|
|
|
|
#
|
2010-01-06 19:59:42 +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 ) {
|
2010-06-21 14:08:46 +00:00
|
|
|
$this->setFragment( preg_replace( '/^#_*/', '#', $fragment ) );
|
2006-12-08 06:09:15 +00:00
|
|
|
$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.
|
|
|
|
|
#
|
2010-04-24 06:22:11 +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
|
|
|
/**
|
2008-07-30 21:52:15 +00:00
|
|
|
* Pages with "/./" or "/../" appearing in the URLs will often be un-
|
|
|
|
|
* reachable due to the way web browsers deal with 'relative' URLs.
|
|
|
|
|
* Also, they conflict with subpage syntax. Forbid them explicitly.
|
2004-11-23 07:38:42 +00:00
|
|
|
*/
|
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!
|
|
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( strpos( $dbkey, '~~~' ) !== false ) {
|
2007-03-08 22:14:53 +00:00
|
|
|
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;
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->mInterwiki == '' ) {
|
2009-10-09 12:52:16 +00:00
|
|
|
$dbkey = self::capitalize( $dbkey, $this->mNamespace );
|
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.
|
|
|
|
|
*/
|
2010-04-24 06:22:11 +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.
|
2010-04-24 06:22:11 +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.
|
2010-04-24 06:22:11 +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
|
|
|
/**
|
2008-09-04 03:22:26 +00:00
|
|
|
* Set the fragment for this title. Removes the first character from the
|
2009-12-14 20:37:51 +00:00
|
|
|
* specified fragment before setting, so it assumes you're passing it with
|
2008-09-04 03:22:26 +00:00
|
|
|
* an initial "#".
|
|
|
|
|
*
|
2008-09-04 07:45:52 +00:00
|
|
|
* Deprecated for public use, use Title::makeTitle() with fragment parameter.
|
|
|
|
|
* Still in active use privately.
|
2006-12-08 06:09:15 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $fragment \type{\string} text
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{Title} the object for the talk page
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{Title} the object for the subject page
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getSubjectPage() {
|
2008-10-30 16:17:37 +00:00
|
|
|
// Is this the same title?
|
|
|
|
|
$subjectNS = MWNamespace::getSubject( $this->getNamespace() );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->getNamespace() == $subjectNS ) {
|
2008-10-30 16:17:37 +00:00
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
return Title::makeTitle( $subjectNS, $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.
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @param $options Array: may be FOR UPDATE
|
|
|
|
|
* @param $table String: table name
|
|
|
|
|
* @param $prefix String: fields prefix
|
2008-08-21 08:39:31 +00:00
|
|
|
* @return \type{\arrayof{Title}} the Title objects linking here
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2009-02-17 19:03:40 +00:00
|
|
|
public function getLinksTo( $options = array(), $table = 'pagelinks', $prefix = 'pl' ) {
|
2008-04-09 18:23:34 +00:00
|
|
|
$linkCache = LinkCache::singleton();
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2009-02-17 19:03:40 +00:00
|
|
|
if ( count( $options ) > 0 ) {
|
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 ),
|
2010-06-15 12:14:54 +00:00
|
|
|
array( 'page_namespace', 'page_title', 'page_id', 'page_len', 'page_is_redirect', 'page_latest' ),
|
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 ) ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $res as $row ) {
|
2004-12-19 08:00:50 +00:00
|
|
|
if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
|
2010-06-15 12:14:54 +00:00
|
|
|
$linkCache->addGoodLinkObj( $row->page_id, $titleObj, $row->page_len, $row->page_is_redirect, $row->page_latest );
|
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.
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @param $options Array: may be FOR UPDATE
|
2008-08-21 08:39:31 +00:00
|
|
|
* @return \type{\arrayof{Title}} the Title objects linking here
|
2005-12-30 09:33:11 +00:00
|
|
|
*/
|
2009-02-17 19:03:40 +00:00
|
|
|
public function getTemplateLinksTo( $options = array() ) {
|
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)
|
2008-08-21 08:39:31 +00:00
|
|
|
* @return \type{\arrayof{Title}} the Title objects
|
2005-04-24 04:13:47 +00:00
|
|
|
*/
|
2009-02-18 08:35:15 +00:00
|
|
|
public function getBrokenLinksFrom() {
|
2007-09-14 04:21:36 +00:00
|
|
|
if ( $this->getArticleId() == 0 ) {
|
|
|
|
|
# All links from article ID 0 are false positives
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-18 08:35:15 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$res = $dbr->select(
|
|
|
|
|
array( 'page', 'pagelinks' ),
|
|
|
|
|
array( 'pl_namespace', 'pl_title' ),
|
|
|
|
|
array(
|
|
|
|
|
'pl_from' => $this->getArticleId(),
|
|
|
|
|
'page_namespace IS NULL'
|
|
|
|
|
),
|
|
|
|
|
__METHOD__, array(),
|
|
|
|
|
array(
|
2009-12-14 20:37:51 +00:00
|
|
|
'page' => array(
|
|
|
|
|
'LEFT JOIN',
|
2009-02-18 08:35:15 +00:00
|
|
|
array( 'pl_namespace=page_namespace', 'pl_title=page_title' )
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-04-24 04:13:47 +00:00
|
|
|
$retVal = array();
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $res as $row ) {
|
2009-02-18 08:35:15 +00:00
|
|
|
$retVal[] = Title::makeTitle( $row->pl_namespace, $row->pl_title );
|
2005-04-24 04:13:47 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
*
|
2008-08-21 08:39:31 +00:00
|
|
|
* @return \type{\arrayof{\string}} the URLs
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $wgContLang->hasVariants() ) {
|
2006-10-12 10:34:49 +00:00
|
|
|
$variants = $wgContLang->getVariants();
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $variants as $vCode ) {
|
|
|
|
|
$urls[] = $this->getInternalURL( '', $vCode );
|
2006-10-12 10:34:49 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $urls;
|
2004-03-20 15:03:26 +00:00
|
|
|
}
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2008-08-11 04:39:00 +00:00
|
|
|
/**
|
|
|
|
|
* Purge all applicable Squid URLs
|
|
|
|
|
*/
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @param $nt \type{Title} the new page Title
|
2010-03-15 23:22:50 +00:00
|
|
|
* @return \type{\mixed} true on success, getUserPermissionsErrors()-like array on failure
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @param $nt \type{Title} the new title
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $auth \type{\bool} indicates whether $wgUser's permissions
|
2009-12-14 20:37:51 +00:00
|
|
|
* should be checked
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $reason \type{\string} is the log summary of the move, used for spam checking
|
|
|
|
|
* @return \type{\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-10-11 08:26:01 +00:00
|
|
|
global $wgUser;
|
|
|
|
|
|
2009-12-14 20:37:51 +00:00
|
|
|
$errors = array();
|
2010-04-24 06:22:11 +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
|
2010-04-24 06:22:11 +00:00
|
|
|
return array( array( 'badtitletext' ) );
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->equals( $nt ) ) {
|
|
|
|
|
$errors[] = array( 'selfmove' );
|
2005-04-25 09:25:06 +00:00
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$this->isMovable() ) {
|
2008-10-11 08:26:01 +00:00
|
|
|
$errors[] = array( 'immobile-source-namespace', $this->getNsText() );
|
|
|
|
|
}
|
2008-12-15 14:48:46 +00:00
|
|
|
if ( $nt->getInterwiki() != '' ) {
|
2008-12-15 15:47:42 +00:00
|
|
|
$errors[] = array( 'immobile-target-namespace-iw' );
|
2008-12-15 14:48:46 +00:00
|
|
|
}
|
2008-10-11 08:26:01 +00:00
|
|
|
if ( !$nt->isMovable() ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
$errors[] = array( 'immobile-target-namespace', $nt->getNsText() );
|
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 ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
$errors[] = array( 'articleexists' );
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2010-01-06 19:59:42 +00:00
|
|
|
if ( ( $this->getDBkey() == '' ) ||
|
2004-03-23 10:22:49 +00:00
|
|
|
( !$oldid ) ||
|
2010-01-06 19:59:42 +00:00
|
|
|
( $nt->getDBkey() == '' ) ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
$errors[] = array( 'badarticleerror' );
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
|
|
|
|
|
2008-05-03 13:09:34 +00:00
|
|
|
// Image-specific checks
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->getNamespace() == NS_FILE ) {
|
2008-05-03 13:09:34 +00:00
|
|
|
$file = wfLocalFile( $this );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $file->exists() ) {
|
|
|
|
|
if ( $nt->getNamespace() != NS_FILE ) {
|
|
|
|
|
$errors[] = array( 'imagenocrossnamespace' );
|
2008-05-03 13:09:34 +00:00
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $nt->getText() != wfStripIllegalFilenameChars( $nt->getText() ) ) {
|
|
|
|
|
$errors[] = array( 'imageinvalidfilename' );
|
2008-07-10 08:16:58 +00:00
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !File::checkExtensionCompatibility( $file, $nt->getDBkey() ) ) {
|
|
|
|
|
$errors[] = array( 'imagetypemismatch' );
|
2008-05-03 13:09:34 +00:00
|
|
|
}
|
2010-01-07 09:32:09 +00:00
|
|
|
}
|
2009-12-26 22:04:37 +00:00
|
|
|
$destfile = wfLocalFile( $nt );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$wgUser->isAllowed( 'reupload-shared' ) && !$destfile->exists() && wfFindFile( $nt ) ) {
|
2009-12-26 21:56:05 +00:00
|
|
|
$errors[] = array( 'file-exists-sharedrepo' );
|
2008-05-03 13:09:34 +00:00
|
|
|
}
|
2010-01-07 09:32:09 +00:00
|
|
|
|
2008-05-03 13:09:34 +00:00
|
|
|
}
|
|
|
|
|
|
2008-01-18 15:52:40 +00:00
|
|
|
if ( $auth ) {
|
2008-11-01 23:20:25 +00:00
|
|
|
$errors = wfMergeErrorArrays( $errors,
|
2010-04-24 06:22:11 +00:00
|
|
|
$this->getUserPermissionsErrors( 'move', $wgUser ),
|
|
|
|
|
$this->getUserPermissionsErrors( 'edit', $wgUser ),
|
|
|
|
|
$nt->getUserPermissionsErrors( 'move-target', $wgUser ),
|
|
|
|
|
$nt->getUserPermissionsErrors( 'edit', $wgUser ) );
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2009-03-19 21:48:16 +00:00
|
|
|
$match = EditPage::matchSummarySpamRegex( $reason );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $match !== false ) {
|
2008-08-19 20:32:30 +00:00
|
|
|
// This is kind of lame, won't display nice
|
2010-04-24 06:22:11 +00:00
|
|
|
$errors[] = array( 'spamprotectiontext' );
|
2008-08-19 20:32:30 +00:00
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2007-12-08 18:30:00 +00:00
|
|
|
$err = null;
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !wfRunHooks( 'AbortMove', array( $this, $nt, $wgUser, &$err, $reason ) ) ) {
|
|
|
|
|
$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 ) ) {
|
2010-04-24 06:22:11 +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 ) ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
$errors[] = array( 'cantmove-titleprotected' );
|
2007-12-15 23:51:54 +00:00
|
|
|
}
|
2005-04-25 09:25:06 +00:00
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( empty( $errors ) )
|
2008-05-27 16:03:21 +00:00
|
|
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @param $nt \type{Title} the new title
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $auth \type{\bool} indicates whether $wgUser's permissions
|
2009-12-14 20:37:51 +00:00
|
|
|
* should be checked
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $reason \type{\string} The reason for the move
|
|
|
|
|
* @param $createRedirect \type{\bool} 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.
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\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 );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( is_array( $err ) ) {
|
2005-04-25 09:25:06 +00:00
|
|
|
return $err;
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2009-12-14 13:41:32 +00:00
|
|
|
// If it is a file, move it first. It is done before all other moving stuff is done because it's hard to revert
|
2009-03-29 13:42:29 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->getNamespace() == NS_FILE ) {
|
2009-03-29 13:42:29 +00:00
|
|
|
$file = wfLocalFile( $this );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $file->exists() ) {
|
2009-03-29 13:42:29 +00:00
|
|
|
$status = $file->move( $nt );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$status->isOk() ) {
|
2009-03-29 13:42:29 +00:00
|
|
|
return $status->getErrorsArray();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-01 02:31:45 +00:00
|
|
|
$pageid = $this->getArticleID();
|
2008-09-24 15:02:02 +00:00
|
|
|
$protected = $this->isProtected();
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $nt->exists() ) {
|
2008-05-03 13:09:34 +00:00
|
|
|
$err = $this->moveOverExistingRedirect( $nt, $reason, $createRedirect );
|
2010-04-24 06:22:11 +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 );
|
2010-04-24 06:22:11 +00:00
|
|
|
$pageCountChange = ( $createRedirect ? 1 : 0 );
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2008-05-30 19:59:47 +00:00
|
|
|
|
2010-04-24 06:22:11 +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.
|
|
|
|
|
$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
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $protected ) {
|
2008-09-24 15:02:02 +00:00
|
|
|
# Protect the redirect title as the title used to be...
|
|
|
|
|
$dbw->insertSelect( 'page_restrictions', 'page_restrictions',
|
2009-12-14 20:37:51 +00:00
|
|
|
array(
|
2008-09-24 15:02:02 +00:00
|
|
|
'pr_page' => $redirid,
|
|
|
|
|
'pr_type' => 'pr_type',
|
|
|
|
|
'pr_level' => 'pr_level',
|
|
|
|
|
'pr_cascade' => 'pr_cascade',
|
|
|
|
|
'pr_user' => 'pr_user',
|
|
|
|
|
'pr_expiry' => 'pr_expiry'
|
|
|
|
|
),
|
|
|
|
|
array( 'pr_page' => $pageid ),
|
|
|
|
|
__METHOD__,
|
|
|
|
|
array( 'IGNORE' )
|
|
|
|
|
);
|
|
|
|
|
# Update the protection log
|
|
|
|
|
$log = new LogPage( 'protect' );
|
2009-01-07 22:49:54 +00:00
|
|
|
$comment = wfMsgForContent( 'prot_1movedto2', $this->getPrefixedText(), $nt->getPrefixedText() );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $reason ) $comment .= wfMsgForContent( 'colon-separator' ) . $reason;
|
|
|
|
|
$log->addEntry( 'move_prot', $nt, $comment, array( $this->getPrefixedText() ) ); // FIXME: $params?
|
2008-09-24 15:02:02 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2008-09-24 15:02:02 +00:00
|
|
|
# Update watchlists
|
2004-03-23 10:22:49 +00:00
|
|
|
$oldnamespace = $this->getNamespace() & ~1;
|
|
|
|
|
$newnamespace = $nt->getNamespace() & ~1;
|
|
|
|
|
$oldtitle = $this->getDBkey();
|
|
|
|
|
$newtitle = $nt->getDBkey();
|
|
|
|
|
|
2010-04-24 06:22:11 +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
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->isContentPage() && !$nt->isContentPage() ) {
|
2007-01-08 15:32:58 +00:00
|
|
|
# No longer a content page
|
|
|
|
|
# Not viewed, edited, removing
|
|
|
|
|
$u = new SiteStatsUpdate( 0, 1, -1, $pageCountChange );
|
2010-04-24 06:22:11 +00:00
|
|
|
} elseif ( !$this->isContentPage() && $nt->isContentPage() ) {
|
2007-01-08 15:32:58 +00:00
|
|
|
# Now a content page
|
|
|
|
|
# Not viewed, edited, adding
|
2010-04-24 06:22:11 +00:00
|
|
|
$u = new SiteStatsUpdate( 0, 1, + 1, $pageCountChange );
|
|
|
|
|
} elseif ( $pageCountChange ) {
|
2007-01-08 15:32:58 +00:00
|
|
|
# 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;
|
|
|
|
|
}
|
2010-04-24 06:22:11 +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
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $nt->getNamespace() == NS_MEDIAWIKI ) {
|
2007-12-20 03:09:19 +00:00
|
|
|
global $wgMessageCache;
|
2009-03-08 17:15:57 +00:00
|
|
|
|
|
|
|
|
# @bug 17860: old article can be deleted, if this the case,
|
|
|
|
|
# delete it from message cache
|
2009-04-24 18:48:56 +00:00
|
|
|
if ( $this->getArticleID() === 0 ) {
|
2009-03-08 17:15:57 +00:00
|
|
|
$wgMessageCache->replace( $this->getDBkey(), false );
|
|
|
|
|
} else {
|
|
|
|
|
$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
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @param $nt \type{Title} the page to move to, which should currently
|
2009-12-14 20:37:51 +00:00
|
|
|
* be a redirect
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $reason \type{\string} The reason for the move
|
|
|
|
|
* @param $createRedirect \type{\bool} Whether to leave a redirect at the old 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 moveOverExistingRedirect( &$nt, $reason = '', $createRedirect = true ) {
|
2010-02-12 21:45:14 +00:00
|
|
|
global $wgUseSquid, $wgUser, $wgContLang;
|
2009-09-26 08:05:58 +00:00
|
|
|
|
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 ) {
|
2009-11-02 19:06:16 +00:00
|
|
|
$comment .= wfMsgForContent( 'colon-separator' ) . $reason;
|
2005-04-03 14:45:42 +00:00
|
|
|
}
|
2010-02-12 21:45:14 +00:00
|
|
|
# Truncate for whole multibyte characters. +5 bytes for ellipsis
|
|
|
|
|
$comment = $wgContLang->truncate( $comment, 250 );
|
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();
|
2008-07-31 07:39:05 +00:00
|
|
|
$latest = $this->getLatestRevID();
|
2009-08-18 10:43:22 +00:00
|
|
|
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
|
2009-07-22 20:09:23 +00:00
|
|
|
$rcts = $dbw->timestamp( $nt->getEarliestRevTime() );
|
|
|
|
|
$newns = $nt->getNamespace();
|
|
|
|
|
$newdbk = $nt->getDBkey();
|
2004-07-10 03:09:26 +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...
|
2009-09-26 08:05:58 +00:00
|
|
|
$dbw->delete( 'page', array( 'page_id' => $newid ), __METHOD__ );
|
2008-02-09 12:40:02 +00:00
|
|
|
if ( !$dbw->cascadingDeletes() ) {
|
|
|
|
|
$dbw->delete( 'revision', array( 'rev_page' => $newid ), __METHOD__ );
|
|
|
|
|
global $wgUseTrackbacks;
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $wgUseTrackbacks )
|
2008-02-09 12:40:02 +00:00
|
|
|
$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__ );
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
// If the redirect was recently created, it may have an entry in recentchanges still
|
|
|
|
|
$dbw->delete( 'recentchanges',
|
|
|
|
|
array( 'rc_timestamp' => $rcts, 'rc_namespace' => $newns, 'rc_title' => $newdbk, 'rc_new' => 1 ),
|
2009-07-22 20:09:23 +00:00
|
|
|
__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
|
2009-01-20 22:32:25 +00:00
|
|
|
$nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true );
|
2008-05-17 15:53:58 +00:00
|
|
|
$nullRevId = $nullRevision->insertOn( $dbw );
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2008-05-30 21:42:05 +00:00
|
|
|
$article = new Article( $this );
|
2010-04-24 06:22:11 +00:00
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array( $article, $nullRevision, $latest, $wgUser ) );
|
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(
|
2010-04-24 06:22:11 +00:00
|
|
|
'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 ),
|
2009-09-26 08:05:58 +00:00
|
|
|
__METHOD__
|
2004-03-23 10:22:49 +00:00
|
|
|
);
|
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.
|
2010-04-24 06:22:11 +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 );
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array( $redirectArticle, $redirectRevision, false, $wgUser ) );
|
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...
|
2009-09-26 08:05:58 +00:00
|
|
|
$dbw->delete( 'pagelinks', array( 'pl_from' => $newid ), __METHOD__ );
|
2007-11-06 16:14:24 +00:00
|
|
|
$dbw->insert( 'pagelinks',
|
|
|
|
|
array(
|
|
|
|
|
'pl_from' => $newid,
|
|
|
|
|
'pl_namespace' => $nt->getNamespace(),
|
2008-01-14 09:26:36 +00:00
|
|
|
'pl_title' => $nt->getDBkey() ),
|
2009-09-26 08:05:58 +00:00
|
|
|
__METHOD__ );
|
2008-12-30 17:52:43 +00:00
|
|
|
$redirectSuppressed = false;
|
2008-02-09 11:45:53 +00:00
|
|
|
} else {
|
|
|
|
|
$this->resetArticleID( 0 );
|
2008-12-30 17:52:43 +00:00
|
|
|
$redirectSuppressed = true;
|
2007-11-06 16:14:24 +00:00
|
|
|
}
|
2008-12-30 17:52:43 +00:00
|
|
|
|
2005-01-31 04:07:56 +00:00
|
|
|
# Log the move
|
|
|
|
|
$log = new LogPage( 'move' );
|
2008-12-30 17:52:43 +00:00
|
|
|
$log->addEntry( 'move_redir', $this, $reason, array( 1 => $nt->getPrefixedText(), 2 => $redirectSuppressed ) );
|
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();
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-30 05:21:20 +00:00
|
|
|
/**
|
|
|
|
|
* Move page to non-existing title.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @param $nt \type{Title} the new Title
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $reason \type{\string} The reason for the move
|
|
|
|
|
* @param $createRedirect \type{\bool} 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 ) {
|
2010-02-12 21:45:14 +00:00
|
|
|
global $wgUseSquid, $wgUser, $wgContLang;
|
2009-09-26 08:05:58 +00:00
|
|
|
|
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-08-18 18:15:47 +00:00
|
|
|
$comment .= wfMsgExt( 'colon-separator',
|
|
|
|
|
array( 'escapenoentities', 'content' ) );
|
|
|
|
|
$comment .= $reason;
|
2005-04-03 14:45:42 +00:00
|
|
|
}
|
2010-02-12 21:45:14 +00:00
|
|
|
# Truncate for whole multibyte characters. +5 bytes for ellipsis
|
|
|
|
|
$comment = $wgContLang->truncate( $comment, 250 );
|
2004-03-23 10:22:49 +00:00
|
|
|
|
|
|
|
|
$newid = $nt->getArticleID();
|
|
|
|
|
$oldid = $this->getArticleID();
|
2008-07-31 07:39:05 +00:00
|
|
|
$latest = $this->getLatestRevId();
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
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
|
2009-01-20 22:32:25 +00:00
|
|
|
$nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true );
|
2009-08-18 20:14:41 +00:00
|
|
|
if ( !is_object( $nullRevision ) ) {
|
|
|
|
|
throw new MWException( 'No valid null revision produced in ' . __METHOD__ );
|
|
|
|
|
}
|
2008-05-17 15:53:58 +00:00
|
|
|
$nullRevId = $nullRevision->insertOn( $dbw );
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2008-05-30 21:42:05 +00:00
|
|
|
$article = new Article( $this );
|
2010-04-24 06:22:11 +00:00
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array( $article, $nullRevision, $latest, $wgUser ) );
|
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 ),
|
2009-09-26 08:05:58 +00:00
|
|
|
__METHOD__
|
2004-03-23 10:22:49 +00:00
|
|
|
);
|
2008-02-09 11:45:53 +00:00
|
|
|
$nt->resetArticleID( $oldid );
|
2004-03-23 10:22:49 +00:00
|
|
|
|
2010-04-24 06:22:11 +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 );
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
wfRunHooks( 'NewRevisionFromEditComplete', array( $redirectArticle, $redirectRevision, false, $wgUser ) );
|
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() ),
|
2009-09-26 08:05:58 +00:00
|
|
|
__METHOD__ );
|
2008-12-30 17:52:43 +00:00
|
|
|
$redirectSuppressed = false;
|
2008-02-09 11:45:53 +00:00
|
|
|
} else {
|
|
|
|
|
$this->resetArticleID( 0 );
|
2008-12-30 17:52:43 +00:00
|
|
|
$redirectSuppressed = true;
|
2007-11-06 16:14:24 +00:00
|
|
|
}
|
2008-12-30 17:52:43 +00:00
|
|
|
|
2005-01-31 04:07:56 +00:00
|
|
|
# Log the move
|
|
|
|
|
$log = new LogPage( 'move' );
|
2008-12-30 17:52:43 +00:00
|
|
|
$log->addEntry( 'move', $this, $reason, array( 1 => $nt->getPrefixedText(), 2 => $redirectSuppressed ) );
|
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();
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-02-09 14:16:51 +00:00
|
|
|
/**
|
|
|
|
|
* Move this page's subpages to be subpages of $nt
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2009-02-09 14:16:51 +00:00
|
|
|
* @param $nt Title Move target
|
|
|
|
|
* @param $auth bool Whether $wgUser's permissions should be checked
|
|
|
|
|
* @param $reason string The reason for the move
|
|
|
|
|
* @param $createRedirect bool Whether to create redirects from the old subpages to the new ones
|
|
|
|
|
* Ignored if the user doesn't have the 'suppressredirect' right
|
|
|
|
|
* @return mixed array with old page titles as keys, and strings (new page titles) or
|
|
|
|
|
* arrays (errors) as values, or an error array with numeric indices if no pages were moved
|
|
|
|
|
*/
|
|
|
|
|
public function moveSubpages( $nt, $auth = true, $reason = '', $createRedirect = true ) {
|
2009-04-28 03:03:48 +00:00
|
|
|
global $wgMaximumMovedPages;
|
2009-02-09 14:16:51 +00:00
|
|
|
// Check permissions
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$this->userCan( 'move-subpages' ) )
|
2009-02-09 14:16:51 +00:00
|
|
|
return array( 'cant-move-subpages' );
|
|
|
|
|
// Do the source and target namespaces support subpages?
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !MWNamespace::hasSubpages( $this->getNamespace() ) )
|
2009-02-09 14:16:51 +00:00
|
|
|
return array( 'namespace-nosubpages',
|
|
|
|
|
MWNamespace::getCanonicalName( $this->getNamespace() ) );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !MWNamespace::hasSubpages( $nt->getNamespace() ) )
|
2009-02-09 14:16:51 +00:00
|
|
|
return array( 'namespace-nosubpages',
|
|
|
|
|
MWNamespace::getCanonicalName( $nt->getNamespace() ) );
|
|
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
$subpages = $this->getSubpages( $wgMaximumMovedPages + 1 );
|
2009-02-09 14:16:51 +00:00
|
|
|
$retval = array();
|
|
|
|
|
$count = 0;
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $subpages as $oldSubpage ) {
|
2009-02-09 14:16:51 +00:00
|
|
|
$count++;
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $count > $wgMaximumMovedPages ) {
|
2009-02-09 14:16:51 +00:00
|
|
|
$retval[$oldSubpage->getPrefixedTitle()] =
|
|
|
|
|
array( 'movepage-max-pages',
|
|
|
|
|
$wgMaximumMovedPages );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-18 20:28:26 +00:00
|
|
|
// We don't know whether this function was called before
|
|
|
|
|
// or after moving the root page, so check both
|
|
|
|
|
// $this and $nt
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $oldSubpage->getArticleId() == $this->getArticleId() ||
|
2009-08-18 20:28:26 +00:00
|
|
|
$oldSubpage->getArticleID() == $nt->getArticleId() )
|
2009-02-09 14:16:51 +00:00
|
|
|
// When moving a page to a subpage of itself,
|
|
|
|
|
// don't move it twice
|
|
|
|
|
continue;
|
|
|
|
|
$newPageName = preg_replace(
|
2010-04-24 06:22:11 +00:00
|
|
|
'#^' . preg_quote( $this->getDBkey(), '#' ) . '#',
|
2009-12-17 14:45:52 +00:00
|
|
|
StringUtils::escapeRegexReplacement( $nt->getDBkey() ), # bug 21234
|
2009-10-22 14:50:45 +00:00
|
|
|
$oldSubpage->getDBkey() );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $oldSubpage->isTalkPage() ) {
|
2009-02-09 14:16:51 +00:00
|
|
|
$newNs = $nt->getTalkPage()->getNamespace();
|
|
|
|
|
} else {
|
|
|
|
|
$newNs = $nt->getSubjectPage()->getNamespace();
|
|
|
|
|
}
|
|
|
|
|
# Bug 14385: we need makeTitleSafe because the new page names may
|
|
|
|
|
# be longer than 255 characters.
|
|
|
|
|
$newSubpage = Title::makeTitleSafe( $newNs, $newPageName );
|
|
|
|
|
|
|
|
|
|
$success = $oldSubpage->moveTo( $newSubpage, $auth, $reason, $createRedirect );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $success === true ) {
|
2009-02-09 14:16:51 +00:00
|
|
|
$retval[$oldSubpage->getPrefixedText()] = $newSubpage->getPrefixedText();
|
|
|
|
|
} else {
|
|
|
|
|
$retval[$oldSubpage->getPrefixedText()] = $success;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $retval;
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2008-11-08 19:31:08 +00:00
|
|
|
/**
|
|
|
|
|
* Checks if this page is just a one-rev redirect.
|
|
|
|
|
* Adds lock, so don't use just for light purposes.
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2008-11-08 19:31:08 +00:00
|
|
|
*/
|
2008-11-13 22:20:51 +00:00
|
|
|
public function isSingleRevRedirect() {
|
2008-11-08 19:31:08 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
# Is it a redirect?
|
|
|
|
|
$row = $dbw->selectRow( 'page',
|
2008-11-13 22:20:51 +00:00
|
|
|
array( 'page_is_redirect', 'page_latest', 'page_id' ),
|
|
|
|
|
$this->pageCond(),
|
2008-11-08 19:31:08 +00:00
|
|
|
__METHOD__,
|
2009-02-17 19:03:40 +00:00
|
|
|
array( 'FOR UPDATE' )
|
2008-11-08 19:31:08 +00:00
|
|
|
);
|
|
|
|
|
# Cache some fields we may want
|
2010-04-24 06:22:11 +00:00
|
|
|
$this->mArticleID = $row ? intval( $row->page_id ) : 0;
|
2008-11-08 19:31:08 +00:00
|
|
|
$this->mRedirect = $row ? (bool)$row->page_is_redirect : false;
|
2010-04-24 06:22:11 +00:00
|
|
|
$this->mLatestID = $row ? intval( $row->page_latest ) : false;
|
|
|
|
|
if ( !$this->mRedirect ) {
|
2008-11-08 19:31:08 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
# Does the article have a history?
|
2010-04-24 06:22:11 +00:00
|
|
|
$row = $dbw->selectField( array( 'page', 'revision' ),
|
2008-11-08 19:31:08 +00:00
|
|
|
'rev_id',
|
|
|
|
|
array( 'page_namespace' => $this->getNamespace(),
|
|
|
|
|
'page_title' => $this->getDBkey(),
|
|
|
|
|
'page_id=rev_page',
|
|
|
|
|
'page_latest != rev_id'
|
2009-12-14 20:37:51 +00:00
|
|
|
),
|
2008-11-08 19:31:08 +00:00
|
|
|
__METHOD__,
|
2009-02-17 19:03:40 +00:00
|
|
|
array( 'FOR UPDATE' )
|
2008-11-08 19:31:08 +00:00
|
|
|
);
|
|
|
|
|
# Return true if there was no history
|
2010-04-24 06:22:11 +00:00
|
|
|
return ( $row === false );
|
2008-11-08 19:31:08 +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
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @param $nt \type{Title} the new title to check
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool} TRUE or FALSE
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isValidMoveTarget( $nt ) {
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2008-05-03 13:09:34 +00:00
|
|
|
# Is it an existsing file?
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $nt->getNamespace() == NS_FILE ) {
|
2008-05-03 13:09:34 +00:00
|
|
|
$file = wfLocalFile( $nt );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $file->exists() ) {
|
2008-05-03 13:09:34 +00:00
|
|
|
wfDebug( __METHOD__ . ": file exists\n" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-08 19:31:08 +00:00
|
|
|
# Is it a redirect with no history?
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$nt->isSingleRevRedirect() ) {
|
2008-11-08 19:31:08 +00:00
|
|
|
wfDebug( __METHOD__ . ": not a one-rev redirect\n" );
|
2005-07-01 10:44:48 +00:00
|
|
|
return false;
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
2008-11-08 19:31:08 +00:00
|
|
|
# Get the article text
|
|
|
|
|
$rev = Revision::newFromTitle( $nt );
|
|
|
|
|
$text = $rev->getText();
|
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] );
|
2010-04-24 06:22:11 +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
|
|
|
}
|
2008-11-08 19:31:08 +00:00
|
|
|
return true;
|
2004-03-23 10:22:49 +00:00
|
|
|
}
|
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?
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool} TRUE or FALSE
|
2007-07-05 18:20:46 +00:00
|
|
|
*/
|
|
|
|
|
public function isWatchable() {
|
2008-11-13 22:20:51 +00:00
|
|
|
return !$this->isExternal() && 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.
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\array} array an array of parents in the form:
|
2004-09-30 05:21:20 +00:00
|
|
|
* $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"
|
2010-04-24 06:22:11 +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
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $dbr->numRows( $res ) > 0 ) {
|
|
|
|
|
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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $children \type{\array} an array with the children in the keys, to check for circular refs
|
|
|
|
|
* @return \type{\array} Tree of parent categories
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function getParentCategoryTree( $children = array() ) {
|
2009-12-14 20:37:51 +00:00
|
|
|
$stack = array();
|
2004-08-23 00:49:02 +00:00
|
|
|
$parents = $this->getParentCategories();
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $parents ) {
|
|
|
|
|
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 {
|
2010-04-24 06:22:11 +00:00
|
|
|
$nt = Title::newFromText( $parent );
|
2006-08-24 17:35:42 +00:00
|
|
|
if ( $nt ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
$stack[$parent] = $nt->getParentCategoryTree( $children + array( $parent => 1 ) );
|
2006-08-24 17:35:42 +00:00
|
|
|
}
|
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
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\array} Selection array
|
2004-09-30 05:21:20 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function pageCond() {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->mArticleID > 0 ) {
|
2008-12-08 23:10:24 +00:00
|
|
|
// PK avoids secondary lookups in InnoDB, shouldn't hurt other DBs
|
|
|
|
|
return array( 'page_id' => $this->mArticleID );
|
2008-12-08 22:30:58 +00:00
|
|
|
} else {
|
|
|
|
|
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
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $revId \type{\int} Revision ID. Get the revision that was before this one.
|
|
|
|
|
* @param $flags \type{\int} GAID_FOR_UPDATE
|
|
|
|
|
* @return \twotypes{\int,\bool} Old revision ID, or FALSE if none exists
|
2004-10-02 19:49:54 +00:00
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
public function getPreviousRevisionID( $revId, $flags = 0 ) {
|
|
|
|
|
$db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
|
2008-05-15 14:53:02 +00:00
|
|
|
return $db->selectField( 'revision', 'rev_id',
|
2008-05-23 09:00:08 +00:00
|
|
|
array(
|
2010-04-24 06:22:11 +00:00
|
|
|
'rev_page' => $this->getArticleId( $flags ),
|
2008-07-31 07:39:05 +00:00
|
|
|
'rev_id < ' . intval( $revId )
|
2008-05-23 09:00:08 +00:00
|
|
|
),
|
|
|
|
|
__METHOD__,
|
|
|
|
|
array( 'ORDER BY' => 'rev_id DESC' )
|
|
|
|
|
);
|
2004-10-02 19:49:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the revision ID of the next revision
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $revId \type{\int} Revision ID. Get the revision that was after this one.
|
|
|
|
|
* @param $flags \type{\int} GAID_FOR_UPDATE
|
|
|
|
|
* @return \twotypes{\int,\bool} Next revision ID, or FALSE if none exists
|
2004-10-02 19:49:54 +00:00
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
public function getNextRevisionID( $revId, $flags = 0 ) {
|
|
|
|
|
$db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
|
2008-05-15 14:53:02 +00:00
|
|
|
return $db->selectField( 'revision', 'rev_id',
|
2008-05-23 09:00:08 +00:00
|
|
|
array(
|
2010-04-24 06:22:11 +00:00
|
|
|
'rev_page' => $this->getArticleId( $flags ),
|
2008-07-31 07:39:05 +00:00
|
|
|
'rev_id > ' . intval( $revId )
|
2008-05-23 09:00:08 +00:00
|
|
|
),
|
|
|
|
|
__METHOD__,
|
|
|
|
|
array( 'ORDER BY' => 'rev_id' )
|
|
|
|
|
);
|
2004-10-02 19:49:54 +00:00
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-01-15 17:53:19 +00:00
|
|
|
/**
|
|
|
|
|
* Get the first revision of the page
|
|
|
|
|
*
|
|
|
|
|
* @param $flags \type{\int} GAID_FOR_UPDATE
|
|
|
|
|
* @return Revision (or NULL if page doesn't exist)
|
|
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
public function getFirstRevision( $flags = 0 ) {
|
|
|
|
|
$db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
|
|
|
|
|
$pageId = $this->getArticleId( $flags );
|
|
|
|
|
if ( !$pageId ) return null;
|
2009-01-15 17:53:19 +00:00
|
|
|
$row = $db->selectRow( 'revision', '*',
|
|
|
|
|
array( 'rev_page' => $pageId ),
|
|
|
|
|
__METHOD__,
|
|
|
|
|
array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 1 )
|
|
|
|
|
);
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$row ) {
|
2009-12-11 21:07:27 +00:00
|
|
|
return null;
|
2009-01-15 17:53:19 +00:00
|
|
|
} else {
|
|
|
|
|
return new Revision( $row );
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2008-12-21 09:33:04 +00:00
|
|
|
/**
|
|
|
|
|
* Check if this is a new page
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function isNewPage() {
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
return (bool)$dbr->selectField( 'page', 'page_is_new', $this->pageCond(), __METHOD__ );
|
|
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2008-10-28 13:42:05 +00:00
|
|
|
/**
|
|
|
|
|
* Get the oldest revision timestamp of this page
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return String: MW timestamp
|
2008-10-28 13:42:05 +00:00
|
|
|
*/
|
|
|
|
|
public function getEarliestRevTime() {
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->exists() ) {
|
2008-10-28 13:42:05 +00:00
|
|
|
$min = $dbr->selectField( 'revision',
|
|
|
|
|
'MIN(rev_timestamp)',
|
|
|
|
|
array( 'rev_page' => $this->getArticleId() ),
|
|
|
|
|
__METHOD__ );
|
|
|
|
|
return wfTimestampOrNull( TS_MW, $min );
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $old \type{\int} Revision ID.
|
|
|
|
|
* @param $new \type{\int} Revision ID.
|
|
|
|
|
* @return \type{\int} Number of revisions between these IDs.
|
2006-12-06 08:28:44 +00:00
|
|
|
*/
|
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 );
|
2009-09-30 16:05:40 +00:00
|
|
|
return (int)$dbr->selectField( 'revision', 'count(*)',
|
2006-12-06 08:28:44 +00:00
|
|
|
'rev_page = ' . intval( $this->getArticleId() ) .
|
|
|
|
|
' AND rev_id > ' . intval( $old ) .
|
2008-04-10 17:49:59 +00:00
|
|
|
' AND rev_id < ' . intval( $new ),
|
2009-02-28 11:58:06 +00:00
|
|
|
__METHOD__
|
|
|
|
|
);
|
2006-12-06 08:28:44 +00:00
|
|
|
}
|
|
|
|
|
|
2005-02-21 11:28:07 +00:00
|
|
|
/**
|
|
|
|
|
* Compare with another title.
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @param $title \type{Title}
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\bool} TRUE or FALSE
|
2005-02-21 11:28:07 +00:00
|
|
|
*/
|
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)
|
2010-03-15 23:22:50 +00:00
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return Integer: result of string comparison, or namespace comparison
|
2008-05-08 23:16:36 +00:00
|
|
|
*/
|
2009-02-28 11:58:06 +00:00
|
|
|
public static function compare( $a, $b ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $a->getNamespace() == $b->getNamespace() ) {
|
2008-05-08 23:16:36 +00:00
|
|
|
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
|
|
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} String representation of this title
|
2007-07-05 18:20:46 +00:00
|
|
|
*/
|
|
|
|
|
public function __toString() {
|
2010-02-01 04:57:42 +00:00
|
|
|
return $this->getPrefixedText();
|
2007-07-05 18:20:46 +00:00
|
|
|
}
|
2005-07-01 10:44:48 +00:00
|
|
|
|
2005-04-25 09:25:06 +00:00
|
|
|
/**
|
2008-12-13 02:40:53 +00:00
|
|
|
* Check if page exists. For historical reasons, this function simply
|
|
|
|
|
* checks for the existence of the title in the page table, and will
|
|
|
|
|
* thus return false for interwiki links, special pages and the like.
|
|
|
|
|
* If you want to know if a title can be meaningfully viewed, you should
|
|
|
|
|
* probably call the isKnown() method instead.
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2005-04-25 09:25:06 +00:00
|
|
|
*/
|
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
|
|
|
/**
|
2008-12-13 02:40:53 +00:00
|
|
|
* Should links to this title be shown as potentially viewable (i.e. as
|
|
|
|
|
* "bluelinks"), even if there's no record by this title in the page
|
|
|
|
|
* table?
|
|
|
|
|
*
|
|
|
|
|
* This function is semi-deprecated for public use, as well as somewhat
|
|
|
|
|
* misleadingly named. You probably just want to call isKnown(), which
|
|
|
|
|
* calls this function internally.
|
2005-07-01 10:44:48 +00:00
|
|
|
*
|
2008-12-13 04:14:40 +00:00
|
|
|
* (ISSUE: Most of these checks are cheap, but the file existence check
|
|
|
|
|
* can potentially be quite expensive. Including it here fixes a lot of
|
|
|
|
|
* existing code, but we might want to add an optional parameter to skip
|
|
|
|
|
* it and any other expensive checks.)
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2005-04-27 07:48:14 +00:00
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function isAlwaysKnown() {
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->mInterwiki != '' ) {
|
2008-12-13 02:40:53 +00:00
|
|
|
return true; // any interwiki link might be viewable, for all we know
|
|
|
|
|
}
|
2009-02-25 00:48:07 +00:00
|
|
|
switch( $this->mNamespace ) {
|
2008-12-13 02:40:53 +00:00
|
|
|
case NS_MEDIA:
|
|
|
|
|
case NS_FILE:
|
2010-06-16 21:48:31 +00:00
|
|
|
return (bool)wfFindFile( $this ); // file exists, possibly in a foreign repo
|
2008-12-13 02:40:53 +00:00
|
|
|
case NS_SPECIAL:
|
2009-05-24 08:29:10 +00:00
|
|
|
return SpecialPage::exists( $this->getDBkey() ); // valid special page
|
2008-12-13 02:40:53 +00:00
|
|
|
case NS_MAIN:
|
|
|
|
|
return $this->mDbkeyform == ''; // selflink, possibly with fragment
|
|
|
|
|
case NS_MEDIAWIKI:
|
|
|
|
|
// 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.
|
|
|
|
|
list( $basename, /* rest */ ) = explode( '/', $this->mDbkeyform, 2 );
|
2010-04-03 21:07:57 +00:00
|
|
|
return (bool)wfMsgWeirdKey( $basename ); // known system message
|
2008-12-13 02:40:53 +00:00
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Does this title refer to a page that can (or might) be meaningfully
|
|
|
|
|
* viewed? In particular, this function may be used to determine if
|
|
|
|
|
* links to the title should be rendered as "bluelinks" (as opposed to
|
|
|
|
|
* "redlinks" to non-existent pages).
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2008-12-13 02:40:53 +00:00
|
|
|
*/
|
|
|
|
|
public function isKnown() {
|
|
|
|
|
return $this->exists() || $this->isAlwaysKnown();
|
2005-04-27 07:48:14 +00:00
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-02 08:00:40 +00:00
|
|
|
/**
|
|
|
|
|
* Does this page have source text?
|
|
|
|
|
*
|
|
|
|
|
* @return Boolean
|
|
|
|
|
*/
|
|
|
|
|
public function hasSourceText() {
|
|
|
|
|
if ( $this->exists() )
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if ( $this->mNamespace == NS_MEDIAWIKI ) {
|
2010-04-03 21:07:57 +00:00
|
|
|
// If the page doesn't exist but is a known system message, default
|
|
|
|
|
// message content will be displayed, same for language subpages
|
|
|
|
|
// Also, 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.
|
2010-04-02 08:00:40 +00:00
|
|
|
list( $basename, /* rest */ ) = explode( '/', $this->mDbkeyform, 2 );
|
2010-04-03 21:07:57 +00:00
|
|
|
return (bool)wfMsgWeirdKey( $basename );
|
2010-04-02 08:00:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-02 19:52:57 +00:00
|
|
|
/**
|
|
|
|
|
* Is this in a namespace that allows actual pages?
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2010-03-15 23:22:50 +00:00
|
|
|
* @internal note -- uses hardcoded namespace index instead of constants
|
2009-01-02 19:52:57 +00:00
|
|
|
*/
|
|
|
|
|
public function canExist() {
|
2010-04-24 06:22:11 +00:00
|
|
|
return $this->mNamespace >= 0 && $this->mNamespace != NS_MEDIA;
|
2009-01-02 19:52:57 +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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @param $db DatabaseBase: optional db
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Last touched timestamp
|
2006-09-05 14:44:50 +00:00
|
|
|
*/
|
2009-12-11 21:07:27 +00:00
|
|
|
public function getTouched( $db = null ) {
|
2010-04-24 06:22:11 +00:00
|
|
|
$db = isset( $db ) ? $db : wfGetDB( DB_SLAVE );
|
2008-12-11 00:42:50 +00:00
|
|
|
$touched = $db->selectField( 'page', 'page_touched', $this->pageCond(), __METHOD__ );
|
|
|
|
|
return $touched;
|
2006-09-05 14:44:50 +00:00
|
|
|
}
|
2008-11-08 19:31:08 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the timestamp when this page was updated since the user last saw it.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @param $user User
|
|
|
|
|
* @return Mixed: string/null
|
2008-11-08 19:31:08 +00:00
|
|
|
*/
|
2009-12-11 21:07:27 +00:00
|
|
|
public function getNotificationTimestamp( $user = null ) {
|
2008-11-08 19:31:08 +00:00
|
|
|
global $wgUser, $wgShowUpdatedMarker;
|
|
|
|
|
// Assume current user if none given
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$user ) $user = $wgUser;
|
2008-11-08 19:31:08 +00:00
|
|
|
// Check cache first
|
|
|
|
|
$uid = $user->getId();
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( isset( $this->mNotificationTimestamp[$uid] ) ) {
|
2008-11-08 19:31:08 +00:00
|
|
|
return $this->mNotificationTimestamp[$uid];
|
|
|
|
|
}
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !$uid || !$wgShowUpdatedMarker ) {
|
2008-11-08 19:31:08 +00:00
|
|
|
return $this->mNotificationTimestamp[$uid] = false;
|
|
|
|
|
}
|
|
|
|
|
// Don't cache too much!
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( count( $this->mNotificationTimestamp ) >= self::CACHE_MAX ) {
|
2008-11-08 19:31:08 +00:00
|
|
|
$this->mNotificationTimestamp = array();
|
|
|
|
|
}
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
|
|
|
|
$this->mNotificationTimestamp[$uid] = $dbr->selectField( 'watchlist',
|
|
|
|
|
'wl_notificationtimestamp',
|
|
|
|
|
array( 'wl_namespace' => $this->getNamespace(),
|
|
|
|
|
'wl_title' => $this->getDBkey(),
|
|
|
|
|
'wl_user' => $user->getId()
|
|
|
|
|
),
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
return $this->mNotificationTimestamp[$uid];
|
|
|
|
|
}
|
2006-09-05 14:44:50 +00:00
|
|
|
|
2008-08-11 04:39:00 +00:00
|
|
|
/**
|
|
|
|
|
* Get the trackback URL for this page
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Trackback URL
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function trackbackURL() {
|
2009-03-16 20:11:36 +00:00
|
|
|
global $wgScriptPath, $wgServer, $wgScriptExtension;
|
2005-07-23 05:47:25 +00:00
|
|
|
|
2009-03-16 20:11:36 +00:00
|
|
|
return "$wgServer$wgScriptPath/trackback$wgScriptExtension?article="
|
2010-04-24 06:22:11 +00:00
|
|
|
. htmlspecialchars( urlencode( $this->getPrefixedDBkey() ) );
|
2005-07-23 05:47:25 +00:00
|
|
|
}
|
|
|
|
|
|
2008-08-11 04:39:00 +00:00
|
|
|
/**
|
|
|
|
|
* Get the trackback RDF for this page
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} Trackback RDF
|
|
|
|
|
*/
|
2007-04-16 15:24:04 +00:00
|
|
|
public function trackbackRDF() {
|
2010-04-24 06:22:11 +00:00
|
|
|
$url = htmlspecialchars( $this->getFullURL() );
|
|
|
|
|
$title = htmlspecialchars( $this->getText() );
|
2005-07-23 05:47:25 +00:00
|
|
|
$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
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2010-03-15 23:22:50 +00:00
|
|
|
* @param $prepend string defaults to 'nstab-'
|
2008-08-11 04:39:00 +00:00
|
|
|
* @return \type{\string} XML 'id' name
|
2006-03-16 02:51:11 +00:00
|
|
|
*/
|
2009-07-06 22:43:04 +00:00
|
|
|
public function getNamespaceKey( $prepend = 'nstab-' ) {
|
2009-10-16 04:06:30 +00:00
|
|
|
global $wgContLang;
|
2009-07-06 22:43:04 +00:00
|
|
|
// Gets the subject namespace if this title
|
|
|
|
|
$namespace = MWNamespace::getSubject( $this->getNamespace() );
|
|
|
|
|
// Checks if cononical namespace name exists for namespace
|
2009-10-16 04:06:30 +00:00
|
|
|
if ( MWNamespace::exists( $this->getNamespace() ) ) {
|
2009-07-06 22:43:04 +00:00
|
|
|
// Uses canonical namespace name
|
2009-10-16 04:06:30 +00:00
|
|
|
$namespaceKey = MWNamespace::getCanonicalName( $namespace );
|
2009-07-06 22:43:04 +00:00
|
|
|
} else {
|
|
|
|
|
// Uses text of namespace
|
|
|
|
|
$namespaceKey = $this->getSubjectNsText();
|
|
|
|
|
}
|
|
|
|
|
// Makes namespace key lowercase
|
|
|
|
|
$namespaceKey = $wgContLang->lc( $namespaceKey );
|
|
|
|
|
// Uses main
|
|
|
|
|
if ( $namespaceKey == '' ) {
|
|
|
|
|
$namespaceKey = 'main';
|
|
|
|
|
}
|
|
|
|
|
// Changes file to image for backwards compatibility
|
|
|
|
|
if ( $namespaceKey == 'file' ) {
|
|
|
|
|
$namespaceKey = 'image';
|
2006-03-16 02:51:11 +00:00
|
|
|
}
|
2009-07-06 22:43:04 +00:00
|
|
|
return $prepend . $namespaceKey;
|
2006-03-16 02:51:11 +00:00
|
|
|
}
|
2006-10-30 06:25:31 +00:00
|
|
|
|
2010-01-07 09:32:09 +00:00
|
|
|
/**
|
|
|
|
|
* Returns true if this is a special page.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2010-03-15 23:22:50 +00:00
|
|
|
* @return boolean
|
2010-01-07 09:32:09 +00:00
|
|
|
*/
|
|
|
|
|
public function isSpecialPage( ) {
|
|
|
|
|
return $this->getNamespace() == NS_SPECIAL;
|
|
|
|
|
}
|
|
|
|
|
|
2006-10-30 06:25:31 +00:00
|
|
|
/**
|
|
|
|
|
* Returns true if this title resolves to the named special page
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2008-08-11 04:39:00 +00:00
|
|
|
* @param $name \type{\string} The special page name
|
2010-03-15 23:22:50 +00:00
|
|
|
* @return boolean
|
2006-10-30 06:25:31 +00:00
|
|
|
*/
|
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,
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return \type{Title} A new Title which points to the local default.
|
|
|
|
|
* Otherwise, returns $this.
|
2006-10-30 06:25:31 +00:00
|
|
|
*/
|
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?
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2007-01-08 15:32:58 +00:00
|
|
|
*/
|
|
|
|
|
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-08-11 04:39:00 +00:00
|
|
|
/**
|
|
|
|
|
* Get all extant redirects to this Title
|
|
|
|
|
*
|
2009-12-14 20:37:51 +00:00
|
|
|
* @param $ns \twotypes{\int,\null} Single namespace to consider;
|
2008-08-11 04:39:00 +00:00
|
|
|
* NULL to consider all namespaces
|
2008-08-21 08:39:31 +00:00
|
|
|
* @return \type{\arrayof{Title}} Redirects to this title
|
2008-08-11 04:39:00 +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();
|
2009-12-14 20:37:51 +00:00
|
|
|
|
|
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2008-05-15 19:17:21 +00:00
|
|
|
$where = array(
|
|
|
|
|
'rd_namespace' => $this->getNamespace(),
|
|
|
|
|
'rd_title' => $this->getDBkey(),
|
|
|
|
|
'rd_from = page_id'
|
|
|
|
|
);
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( !is_null( $ns ) ) $where['page_namespace'] = $ns;
|
2009-12-14 20:37:51 +00:00
|
|
|
|
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__
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $res as $row ) {
|
2008-04-12 18:06:57 +00:00
|
|
|
$redirs[] = self::newFromRow( $row );
|
|
|
|
|
}
|
|
|
|
|
return $redirs;
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-01-21 20:42:32 +00:00
|
|
|
/**
|
|
|
|
|
* Check if this Title is a valid redirect target
|
|
|
|
|
*
|
2010-03-23 21:40:02 +00:00
|
|
|
* @return \type{\bool}
|
2009-01-21 20:42:32 +00:00
|
|
|
*/
|
|
|
|
|
public function isValidRedirectTarget() {
|
|
|
|
|
global $wgInvalidRedirectTargets;
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-01-21 20:42:32 +00:00
|
|
|
// invalid redirect targets are stored in a global array, but explicity disallow Userlogout here
|
2010-04-24 06:22:11 +00:00
|
|
|
if ( $this->isSpecial( 'Userlogout' ) ) {
|
2009-01-21 20:42:32 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-04-24 06:22:11 +00:00
|
|
|
foreach ( $wgInvalidRedirectTargets as $target ) {
|
|
|
|
|
if ( $this->isSpecial( $target ) ) {
|
2009-01-21 20:42:32 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-01-21 20:42:32 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2009-02-16 14:26:34 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a backlink cache object
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2010-03-15 23:22:50 +00:00
|
|
|
* @return object BacklinkCache
|
2009-02-16 14:26:34 +00:00
|
|
|
*/
|
|
|
|
|
function getBacklinkCache() {
|
|
|
|
|
if ( is_null( $this->mBacklinkCache ) ) {
|
|
|
|
|
$this->mBacklinkCache = new BacklinkCache( $this );
|
|
|
|
|
}
|
|
|
|
|
return $this->mBacklinkCache;
|
|
|
|
|
}
|
2009-08-31 19:19:12 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether the magic words __INDEX__ and __NOINDEX__ function for
|
|
|
|
|
* this page.
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
|
|
|
|
* @return Boolean
|
2009-08-31 19:19:12 +00:00
|
|
|
*/
|
2010-04-24 06:22:11 +00:00
|
|
|
public function canUseNoindex() {
|
2009-08-31 19:19:12 +00:00
|
|
|
global $wgArticleRobotPolicies, $wgContentNamespaces,
|
|
|
|
|
$wgExemptFromUserRobotsControl;
|
|
|
|
|
|
|
|
|
|
$bannedNamespaces = is_null( $wgExemptFromUserRobotsControl )
|
|
|
|
|
? $wgContentNamespaces
|
|
|
|
|
: $wgExemptFromUserRobotsControl;
|
|
|
|
|
|
|
|
|
|
return !in_array( $this->mNamespace, $bannedNamespaces );
|
|
|
|
|
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2010-03-15 23:22:50 +00:00
|
|
|
/**
|
|
|
|
|
* Returns restriction types for the current Title
|
2010-03-23 21:40:02 +00:00
|
|
|
*
|
2010-03-15 23:22:50 +00:00
|
|
|
* @return array applicable restriction types
|
|
|
|
|
*/
|
2009-11-09 12:05:30 +00:00
|
|
|
public function getRestrictionTypes() {
|
2009-11-06 10:27:44 +00:00
|
|
|
global $wgRestrictionTypes;
|
2010-04-24 06:22:11 +00:00
|
|
|
$types = $this->exists() ? $wgRestrictionTypes : array( 'create' );
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-11-06 10:27:44 +00:00
|
|
|
if ( $this->getNamespace() == NS_FILE ) {
|
|
|
|
|
$types[] = 'upload';
|
|
|
|
|
}
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-11-09 12:05:30 +00:00
|
|
|
wfRunHooks( 'TitleGetRestrictionTypes', array( $this, &$types ) );
|
2009-12-14 20:37:51 +00:00
|
|
|
|
2009-11-06 10:27:44 +00:00
|
|
|
return $types;
|
|
|
|
|
}
|
2007-12-16 19:57:40 +00:00
|
|
|
}
|