8 if (!class_exists(
'UtfNormal')) {
9 require_once(
'include/Unicode/UtfNormal.php');
15 define(
'NS_MAIN',
"nsmain");
16 define(
'NS_SPECIAL',
"nsspecial");
18 define(
'GAID_FOR_UPDATE', 1);
20 # Title::newFromTitle maintains a cache to avoid 21 # expensive re-normalization of commonly used titles. 22 # On a batch operation this can become a memory leak 23 # if not bounded. After hitting this many titles, 25 define(
'MW_TITLECACHE_MAX', 1000);
27 # Constants for pr_cascade bitfield 54 public $mTextform; # Text form (spaces not underscores) of the main part
55 public $mUrlform; # URL-encoded form of the main part
57 public $mNamespace; # Namespace index, i.e. one of the NS_xxxx constants
59 public
$mFragment;
# Title fragment (i.e. the bit after the #) 60 public $mArticleID; # Article ID, fetched from the link cache on demand
68 public $mPrefixedText; # Text form including
namespace/interwiki, initialised on demand
70 # Zero except in {{transclusion}} tags 81 $this->mInterwiki = $this->mUrlform =
82 $this->mTextform = $this->mDbkeyform =
'';
83 $this->mArticleID = -1;
85 $this->mRestrictionsLoaded =
false;
86 $this->mRestrictions =
array();
87 # Dont change the following, NS_MAIN is hardcoded in several place 89 $this->mDefaultNamespace =
NS_MAIN;
90 $this->mWatched = null;
91 $this->mLatestID =
false;
92 $this->mOldRestrictions =
false;
106 if (
$t->secureAndSplit()) {
126 if (is_object(
$text)) {
127 throw new MWException(
'Title::newFromText given an object');
148 $t->mDbkeyform = str_replace(
' ',
'_', $filteredText);
149 $t->mDefaultNamespace = $defaultNamespace;
151 static $cachedcount = 0 ;
152 if (
$t->secureAndSplit()) {
153 if ($defaultNamespace ==
NS_MAIN) {
155 # Avoid memory leaks on mass operations... 177 global $wgLegalTitleChars;
180 # For compatibility with old buggy URLs. "+" is usually not valid in titles, 181 # but some URLs used it as a space replacement and they still come 182 # from some external search tools. 183 if (strpos($wgLegalTitleChars,
'+') ===
false) {
187 $t->mDbkeyform = str_replace(
' ',
'_',
$url);
188 if (
$t->secureAndSplit()) {
206 $fname =
'Title::newFromID';
207 $dbr = wfGetDB(DB_SLAVE);
208 $row = $dbr->selectRow(
210 array(
'page_namespace',
'page_title' ),
214 if (
$row !==
false) {
227 $dbr = wfGetDB(DB_SLAVE);
230 array(
'page_namespace',
'page_title' ),
231 'page_id IN (' . $dbr->makeList($ids) .
')',
236 while (
$row = $dbr->fetchObject(
$res)) {
258 $t->mNamespace = intval($ns);
259 $t->mDbkeyform = str_replace(
' ',
'_',
$title);
260 $t->mArticleID = ($ns >= 0) ? -1 : 0;
261 $t->mUrlform = wfUrlencode(
$t->mDbkeyform);
262 $t->mTextform = str_replace(
'_',
' ',
$title);
279 if (
$t->secureAndSplit()) {
303 $mwRedir = MagicWord::get(
'redirect');
305 if ($mwRedir->matchStart(
$text)) {
307 if (preg_match(
'/\[{2}(.*?)(?:\||\]{2})/',
$text,
$m)) {
308 # categories are escaped using : for example one can enter: 309 # #REDIRECT [[:Category:Music]]. Need to remove it. 310 if (substr(
$m[1], 0, 1) ==
':') {
311 # We don't want to keep the ':' 312 $m[1] = substr(
$m[1], 1);
316 # Disallow redirects to Special:Userlogout 317 if (!is_null($rt) && $rt->isSpecial(
'Userlogout')) {
325 #---------------------------------------------------------------------------- 327 #---------------------------------------------------------------------------- 339 $fname =
'Title::nameOf';
340 $dbr = wfGetDB(DB_SLAVE);
342 $s = $dbr->selectRow(
'page',
array(
'page_namespace',
'page_title' ),
array(
'page_id' =>
$id ), $fname);
357 global $wgLegalTitleChars;
359 $wgLegalTitleChars =
" %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+";
361 return $wgLegalTitleChars;
377 $lc = SearchEngine::legalSearchChars() .
'&#;';
378 $t = $wgContLang->stripForSearch(
$title);
379 $t = preg_replace(
"/[^{$lc}]+/",
' ',
$t);
380 $t = $wgContLang->lc(
$t);
383 $t = preg_replace(
"/([{$lc}]+)'s( |$)/",
"\\1 \\1's ",
$t);
384 $t = preg_replace(
"/([{$lc}]+)s'( |$)/",
"\\1s ",
$t);
386 $t = preg_replace(
"/\\s+/",
' ',
$t);
388 if ($ns == NS_IMAGE) {
389 $t = preg_replace(
"/ (png|gif|jpg|jpeg|ogg)$/",
"",
$t);
404 $n = $wgContLang->getNsText($ns);
405 return $n ==
'' ?
$title :
"$n:$title";
417 global $wgMemc, $wgInterwikiExpiry;
418 global $wgInterwikiCache, $wgContLang;
422 $fname =
'Title::getInterwikiLink';
426 $k = wfMemcKey(
'interwiki',
$key);
431 if ($wgInterwikiCache) {
435 $s = $wgMemc->get($k);
436 # Ignore old keys with no iw_local 437 if (
$s && isset(
$s->iw_local) && isset(
$s->iw_trans)) {
442 $dbr = wfGetDB(DB_SLAVE);
445 array(
'iw_url',
'iw_local',
'iw_trans' ),
453 $s = $dbr->fetchObject(
$res);
455 # Cache non-existence: create a blank object and save it to memcached 461 $wgMemc->set($k,
$s, $wgInterwikiExpiry);
476 global $wgInterwikiCache, $wgInterwikiScopes, $wgInterwikiFallbackSite;
480 $db=dba_open($wgInterwikiCache,
'r',
'cdb');
483 if ($wgInterwikiScopes>=3 and !$site) {
484 $site = dba_fetch(
'__sites:' . wfWikiID(), $db);
486 $site = $wgInterwikiFallbackSite;
489 $value = dba_fetch(wfMemcKey(
$key), $db);
490 if ($value==
'' and $wgInterwikiScopes>=3) {
492 $value = dba_fetch(
"_{$site}:{$key}", $db);
494 if ($value==
'' and $wgInterwikiScopes>=2) {
496 $value = dba_fetch(
"__global:{$key}", $db);
498 if ($value==
'undef') {
506 list($local,
$url)=explode(
' ', $value, 2);
508 $s->iw_local=(int) $local;
522 if ($this->mInterwiki !=
'') {
523 # Make sure key is loaded into cache 525 $k = wfMemcKey(
'interwiki', $this->mInterwiki);
540 if ($this->mInterwiki ==
'') {
543 # Make sure key is loaded into cache 545 $k = wfMemcKey(
'interwiki', $this->mInterwiki);
554 $fragment = str_replace(
' ',
'_', $fragment);
556 $replaceArray =
array(
560 return strtr($fragment, $replaceArray);
563 #---------------------------------------------------------------------------- 565 #---------------------------------------------------------------------------- 606 global $wgContLang, $wgCanonicalNamespaceNames;
608 if (
'' != $this->mInterwiki) {
615 if (isset($wgCanonicalNamespaceNames[$this->mNamespace])) {
619 return $wgContLang->getNsText($this->mNamespace);
669 if ($this->mFragment ==
'') {
701 $s = $this->
prefix($this->mDbkeyform);
702 $s = str_replace(
' ',
'_',
$s);
713 if (empty($this->mPrefixedText)) {
714 $s = $this->
prefix($this->mTextform);
715 $s = str_replace(
'_',
' ',
$s);
716 $this->mPrefixedText =
$s;
730 if (
'' != $this->mFragment) {
742 global $wgNamespacesWithSubpages;
743 if (isset($wgNamespacesWithSubpages[ $this->mNamespace ]) && $wgNamespacesWithSubpages[ $this->mNamespace ]) {
744 $parts = explode(
'/', $this->
getText());
745 # Don't discard the real title if there's no subpage involved 746 if (count($parts) > 1) {
747 unset($parts[ count($parts) - 1 ]);
749 return implode(
'/', $parts);
761 global $wgNamespacesWithSubpages;
762 if (isset($wgNamespacesWithSubpages[ $this->mNamespace ]) && $wgNamespacesWithSubpages[ $this->mNamespace ]) {
763 $parts = explode(
'/', $this->mTextform);
764 return($parts[ count($parts) - 1 ]);
766 return($this->mTextform);
777 $text = wfUrlencode(str_replace(
' ',
'_',
$text));
778 $text = str_replace(
'%28',
'(', str_replace(
'%29',
')',
$text)); # Clean
up the URL; per below,
this might not be safe
788 $s = $this->
prefix($this->mDbkeyform);
789 $s = str_replace(
' ',
'_',
$s);
791 $s = wfUrlencode(
$s) ;
793 # Cleaning up URL to make it look nice -- is this safe? 794 $s = str_replace(
'%28',
'(',
$s);
795 $s = str_replace(
'%29',
')',
$s);
811 global $wgContLang, $wgServer, $wgRequest;
813 if (
'' == $this->mInterwiki) {
818 if ($wgRequest->getVal(
'action') !=
'render') {
826 # Can this actually happen? Interwikis shouldn't be parsed. 827 # Yes! It can in interwiki transclusion. But... it probably shouldn't. 834 # Finally, add the fragment. 851 global $wgArticlePath, $wgScript, $wgServer, $wgRequest;
852 global $wgVariantArticlePath, $wgContLang, $wgUser;
855 if ($variant ==
false && $wgContLang->hasVariants() && !$wgUser->isLoggedIn()) {
856 $pref = $wgContLang->getPreferredVariant(
false);
857 if ($pref != $wgContLang->getCode()) {
874 if ($variant!=
false && $wgContLang->hasVariants()) {
875 if ($wgVariantArticlePath==
false) {
876 $variantArticlePath =
"$wgScript?title=$1&variant=$2";
878 $variantArticlePath = $wgVariantArticlePath;
880 $url = str_replace(
'$2', urlencode($variant), $variantArticlePath);
881 $url = str_replace(
'$1', $dbkey,
$url);
883 $url = str_replace(
'$1', $dbkey, $wgArticlePath);
886 global $wgActionPaths;
889 if (!empty($wgActionPaths) &&
890 preg_match(
'/^(.*&|)action=([^&]*)(&(.*)|)$/',
$query, $matches)) {
891 $action = urldecode($matches[2]);
892 if (isset($wgActionPaths[
$action])) {
894 if (isset($matches[4])) {
897 $url = str_replace(
'$1', $dbkey, $wgActionPaths[$action]);
903 if (
$url ===
false) {
907 $url =
"{$wgScript}?title={$dbkey}&{$query}";
913 if ($wgRequest->getVal(
'action') ==
'render') {
955 global $wgInternalServer;
968 if (
'' != $this->mInterwiki) {
992 return (
'' != $this->mInterwiki);
1005 if (count($restrictions) > 0) {
1006 foreach ($restrictions as $restriction) {
1007 if (strtolower($restriction) !=
'autoconfirmed') {
1017 # If it doesn't exist, it can't be protected 1030 global $wgRestrictionLevels;
1032 # Special pages have inherent protection 1037 # Check regular protection levels 1040 foreach ($wgRestrictionLevels as $level) {
1041 if (in_array($level,
$r) && $level !=
'') {
1049 foreach ($wgRestrictionLevels as $level) {
1050 if (in_array($level,
$r) && $level !=
'') {
1067 if (is_null($this->mWatched)) {
1068 if (
NS_SPECIAL == $this->mNamespace || !$wgUser->isLoggedIn()) {
1069 $this->mWatched =
false;
1071 $this->mWatched = $wgUser->isWatched($this);
1102 $fname =
'Title::userCan';
1103 wfProfileIn($fname);
1105 global $wgUser, $wgNamespaceProtection;
1110 wfProfileOut($fname);
1115 wfProfileOut($fname);
1119 if (array_key_exists($this->mNamespace, $wgNamespaceProtection)) {
1121 if (!is_array($nsProt)) {
1122 $nsProt =
array($nsProt);
1124 foreach ($nsProt as $right) {
1125 if (
'' != $right && !$wgUser->isAllowed($right)) {
1126 wfProfileOut($fname);
1132 if ($this->mDbkeyform ==
'_') {
1133 # FIXME: Is this necessary? Shouldn't be allowed anyway... 1134 wfProfileOut($fname);
1138 # protect css/js subpages of user pages 1139 # XXX: this might be better using restrictions 1140 # XXX: Find a way to work around the php bug that prevents using $this->userCanEditCssJsSubpage() from working 1142 && !$wgUser->isAllowed(
'editinterface')
1143 && !preg_match(
'/^' . preg_quote($wgUser->getName(),
'/') .
'\//', $this->mTextform)) {
1144 wfProfileOut($fname);
1149 # We /could/ use the protection level on the source page, but it's fairly ugly 1150 # as we have to establish a precedence hierarchy for pages included by multiple 1151 # cascade-protected pages. So just restrict it to people with 'protect' permission, 1152 # as they could remove the protection anyway. 1154 # Cascading protection depends on more than this page... 1155 # Several cascading protected pages may include this page... 1156 # Check each cascading level 1157 # This is only for protection restrictions, not for all actions 1158 if ($cascadingSources > 0 && isset($restrictions[
$action])) {
1159 foreach ($restrictions[$action] as $right) {
1160 $right = ($right ==
'sysop') ?
'protect' : $right;
1161 if (
'' != $right && !$wgUser->isAllowed($right)) {
1162 wfProfileOut($fname);
1171 if ($right ==
'sysop') {
1174 if (
'' != $right && !$wgUser->isAllowed($right)) {
1175 wfProfileOut($fname);
1181 !($this->isMovable() && $wgUser->isAllowed(
'move'))) {
1182 wfProfileOut($fname);
1187 if (($this->isTalkPage() && !$wgUser->isAllowed(
'createtalk')) ||
1188 (!$this->isTalkPage() && !$wgUser->isAllowed(
'createpage'))) {
1189 wfProfileOut($fname);
1194 wfProfileOut($fname);
1205 return $this->
userCan(
'edit', $doExpensiveQueries);
1215 return $this->
userCan(
'create', $doExpensiveQueries);
1225 return $this->
userCan(
'move', $doExpensiveQueries);
1249 wfRunHooks(
'userCan',
array( &$this, &$wgUser,
'read', &
$result ));
1254 if ($wgUser->isAllowed(
'read')) {
1257 global $wgWhitelistRead;
1269 if ($wgWhitelistRead && in_array(
$name, $wgWhitelistRead)) {
1273 # Compatibility with old settings 1275 if (in_array(
':' .
$name, $wgWhitelistRead)) {
1297 global $wgNamespacesWithSubpages;
1299 if (isset($wgNamespacesWithSubpages[ $this->mNamespace ])) {
1300 return (strpos($this->
getText(),
'/') !==
false && $wgNamespacesWithSubpages[ $this->mNamespace ] ==
true);
1312 return (NS_USER == $this->mNamespace and preg_match(
"/\\/.*\\.(?:css|js)$/", $this->mTextform));
1321 $skinNames = Skin::getSkinNames();
1332 $subpage = explode(
'/', $this->mTextform);
1333 $subpage = $subpage[ count($subpage) - 1 ];
1334 return(str_replace(
array(
'.css',
'.js' ),
array(
'',
'' ), $subpage));
1342 return (NS_USER == $this->mNamespace and preg_match(
"/\\/.*\\.css$/", $this->mTextform));
1350 return (NS_USER == $this->mNamespace and preg_match(
"/\\/.*\\.js$/", $this->mTextform));
1362 return ($wgUser->isAllowed(
'editinterface') or preg_match(
'/^' . preg_quote($wgUser->getName(),
'/') .
'\//', $this->mTextform));
1373 return ($sources > 0);
1386 global $wgEnableCascadingProtection, $wgRestrictionTypes;
1388 # Define our dimension of restrictions types 1389 $pagerestrictions =
array();
1390 foreach ($wgRestrictionTypes as
$action) {
1394 if (!$wgEnableCascadingProtection) {
1395 return array(
false, $pagerestrictions );
1398 if (isset($this->mCascadeSources) && $get_pages) {
1399 return array( $this->mCascadeSources, $this->mCascadingRestrictions );
1400 } elseif (isset($this->mHasCascadingRestrictions) && !$get_pages) {
1401 return array( $this->mHasCascadingRestrictions, $pagerestrictions );
1404 wfProfileIn(__METHOD__);
1406 $dbr = wfGetDb(DB_SLAVE);
1409 $tables =
array(
'imagelinks',
'page_restrictions');
1410 $where_clauses =
array(
1413 'pr_cascade' => 1 );
1415 $tables =
array(
'templatelinks',
'page_restrictions');
1416 $where_clauses =
array(
1420 'pr_cascade' => 1 );
1424 $cols =
array(
'pr_page',
'page_namespace',
'page_title',
'pr_expiry',
'pr_type',
'pr_level' );
1425 $where_clauses[] =
'page_id=pr_page';
1431 $res = $dbr->select($tables,
$cols, $where_clauses, __METHOD__);
1433 $sources = $get_pages ?
array() :
false;
1434 $now = wfTimestampNow();
1435 $purgeExpired =
false;
1437 while (
$row = $dbr->fetchObject(
$res)) {
1438 $expiry = Block::decodeExpiry(
$row->pr_expiry);
1439 if ($expiry > $now) {
1441 $page_id =
$row->pr_page;
1442 $page_ns =
$row->page_namespace;
1443 $page_title =
$row->page_title;
1445 # Add groups needed for each restriction type if its not already there 1446 # Make sure this restriction type still exists 1447 if (isset($pagerestrictions[
$row->pr_type]) && !in_array(
$row->pr_level, $pagerestrictions[
$row->pr_type])) {
1448 $pagerestrictions[
$row->pr_type][]=
$row->pr_level;
1455 $purgeExpired =
true;
1458 if ($purgeExpired) {
1462 wfProfileOut(__METHOD__);
1465 $this->mCascadeSources = $sources;
1466 $this->mCascadingRestrictions = $pagerestrictions;
1468 $this->mHasCascadingRestrictions = $sources;
1471 return array( $sources, $pagerestrictions );
1476 if (!$this->mRestrictionsLoaded) {
1489 $dbr = wfGetDb(DB_SLAVE);
1491 $this->mRestrictions[
'edit'] =
array();
1492 $this->mRestrictions[
'move'] =
array();
1494 # Backwards-compatibility: also load the restrictions from the page record (old format). 1496 if ($oldFashionedRestrictions == null) {
1497 $oldFashionedRestrictions = $dbr->selectField(
'page',
'page_restrictions',
array(
'page_id' => $this->getArticleId() ), __METHOD__);
1500 if ($oldFashionedRestrictions !=
'') {
1501 foreach (explode(
':', trim($oldFashionedRestrictions)) as $restrict) {
1502 $temp = explode(
'=', trim($restrict));
1503 if (count($temp) == 1) {
1505 $this->mRestrictions[
"edit"] = explode(
',', trim($temp[0]));
1506 $this->mRestrictions[
"move"] = explode(
',', trim($temp[0]));
1508 $this->mRestrictions[$temp[0]] = explode(
',', trim($temp[1]));
1512 $this->mOldRestrictions =
true;
1513 $this->mCascadeRestriction =
false;
1514 $this->mRestrictionsExpiry = Block::decodeExpiry(
'');
1517 if ($dbr->numRows(
$res)) {
1518 # Current system - load second to make them override. 1519 $now = wfTimestampNow();
1520 $purgeExpired =
false;
1522 while (
$row = $dbr->fetchObject(
$res)) {
1523 # Cycle through all the restrictions. 1527 $expiry = Block::decodeExpiry(
$row->pr_expiry);
1530 if (!$expiry || $expiry > $now) {
1531 $this->mRestrictionsExpiry = $expiry;
1532 $this->mRestrictions[
$row->pr_type] = explode(
',', trim(
$row->pr_level));
1534 $this->mCascadeRestriction |=
$row->pr_cascade;
1537 $purgeExpired =
true;
1541 if ($purgeExpired) {
1546 $this->mRestrictionsLoaded =
true;
1551 if (!$this->mRestrictionsLoaded) {
1552 $dbr = wfGetDB(DB_SLAVE);
1554 $res = $dbr->select(
1555 'page_restrictions',
1557 array(
'pr_page' => $this->getArticleId() ),
1570 $dbw = wfGetDB(DB_MASTER);
1572 'page_restrictions',
1573 array(
'pr_expiry < ' . $dbw->addQuotes($dbw->timestamp()) ),
1587 if (!$this->mRestrictionsLoaded) {
1590 return isset($this->mRestrictions[
$action])
1591 ? $this->mRestrictions[
$action]
1604 $fname =
'Title::isDeleted';
1608 $dbr = wfGetDB(DB_SLAVE);
1609 $n = $dbr->selectField(
'archive',
'COUNT(*)',
array(
'ar_namespace' => $this->
getNamespace(),
1610 'ar_title' => $this->
getDBkey() ), $fname);
1612 $n += $dbr->selectField(
1632 $linkCache =&LinkCache::singleton();
1634 $oldUpdate = $linkCache->forUpdate(
true);
1635 $this->mArticleID = $linkCache->addLinkObj($this);
1636 $linkCache->forUpdate($oldUpdate);
1638 if (-1 == $this->mArticleID) {
1639 $this->mArticleID = $linkCache->addLinkObj($this);
1647 if ($this->mLatestID !==
false) {
1651 $db = wfGetDB(DB_SLAVE);
1652 return $this->mLatestID = $db->selectField(
1656 'Title::getLatestRevID' 1672 $linkCache =&LinkCache::singleton();
1676 $this->mArticleID = -1;
1678 $this->mArticleID = $newid;
1680 $this->mRestrictionsLoaded =
false;
1681 $this->mRestrictions =
array();
1690 global $wgUseFileCache;
1696 $dbw = wfGetDB(DB_MASTER);
1700 'page_touched' => $dbw->timestamp()
1706 'Title::invalidateCache' 1709 if ($wgUseFileCache) {
1710 $cache =
new HTMLFileCache($this);
1711 @unlink($cache->fileCacheName());
1728 if (
'' != $this->mInterwiki) {
1729 $p = $this->mInterwiki .
':';
1731 if (0 != $this->mNamespace) {
1749 global $wgContLang, $wgLocalInterwiki, $wgCapitalLinks;
1752 static $rxTc =
false;
1754 # % is needed as well 1758 $this->mInterwiki = $this->mFragment =
'';
1763 # Strip Unicode bidi override characters. 1764 # Sometimes they slip into cut-n-pasted page titles, where the 1765 # override chars get included in list displays. 1766 $dbkey = str_replace(
"\xE2\x80\x8E",
'', $dbkey);
1767 $dbkey = str_replace(
"\xE2\x80\x8F",
'', $dbkey);
1769 # Clean up whitespace 1771 $dbkey = preg_replace(
'/[ _]+/',
'_', $dbkey);
1772 $dbkey = trim($dbkey,
'_');
1779 # Contained illegal UTF-8 sequences or forbidden Unicode chars. 1783 $this->mDbkeyform = $dbkey;
1785 # Initial colon indicates main namespace rather than specified default 1786 # but should not create invalid {ns,title} pairs such as {0,Project:Foo} 1787 if (
':' == $dbkey{0}) {
1789 $dbkey = substr($dbkey, 1); #
remove the colon but
continue processing
1790 $dbkey = trim($dbkey,
'_'); #
remove any subsequent whitespace
1793 # Namespace or interwiki prefix 1797 if (preg_match(
"/^(.+?)_*:_*(.*)$/S", $dbkey,
$m)) {
1799 if ($ns = $wgContLang->getNsIndex($p)) {
1800 # Ordinary namespace 1802 $this->mNamespace = $ns;
1805 # Can't make a local interwiki link to an interwiki link. 1806 # That's just crazy! 1812 $this->mInterwiki = $wgContLang->lc($p);
1814 # Redundant interwiki prefix to the local wiki 1815 if (0 == strcasecmp($this->mInterwiki, $wgLocalInterwiki)) {
1817 # Can't have an empty self-link 1820 $this->mInterwiki =
'';
1822 # Do another namespace split... 1826 # If there's an initial colon after the interwiki, that also 1827 # resets the default namespace 1828 if ($dbkey !==
'' && $dbkey[0] ==
':') {
1830 $dbkey = substr($dbkey, 1);
1833 # If there's no recognized interwiki or namespace, 1834 # then let the colon expression be part of the title. 1839 # We already know that some pages won't be in the database! 1841 if (
'' != $this->mInterwiki ||
NS_SPECIAL == $this->mNamespace) {
1842 $this->mArticleID = 0;
1844 $fragment = strstr($dbkey,
'#');
1845 if (
false !== $fragment) {
1847 $dbkey = substr($dbkey, 0, strlen($dbkey) - strlen($fragment));
1848 # remove whitespace again: prevents "Foo_bar_#" 1849 # becoming "Foo_bar_" 1850 $dbkey = preg_replace(
'/_*$/',
'', $dbkey);
1853 # Reject illegal characters. 1855 if (preg_match($rxTc, $dbkey)) {
1864 if (strpos($dbkey,
'.') !==
false &&
1865 ($dbkey ===
'.' || $dbkey ===
'..' ||
1866 strpos($dbkey,
'./') === 0 ||
1867 strpos($dbkey,
'../') === 0 ||
1868 strpos($dbkey,
'/./') !==
false ||
1869 strpos($dbkey,
'/../') !==
false)) {
1876 if (strpos($dbkey,
'~~~') !==
false) {
1887 if (($this->mNamespace !=
NS_SPECIAL && strlen($dbkey) > 255) ||
1888 strlen($dbkey) > 512) {
1900 if ($wgCapitalLinks && $this->mInterwiki ==
'') {
1901 $dbkey = $wgContLang->ucfirst($dbkey);
1910 $this->mInterwiki ==
'' &&
1911 $this->mNamespace !=
NS_MAIN) {
1916 if ($dbkey !==
'' &&
':' == $dbkey{0}) {
1921 $this->mDbkeyform = $dbkey;
1924 $this->mTextform = str_replace(
'_',
' ', $dbkey);
1940 $this->mFragment = str_replace(
'_',
' ', substr($fragment, 1));
1973 $linkCache =&LinkCache::singleton();
1976 $db = wfGetDB(DB_MASTER);
1978 $db = wfGetDB(DB_SLAVE);
1983 array(
'page_namespace',
'page_title',
'page_id' ),
1985 "{$prefix}_from=page_id",
1987 "{$prefix}_title" => $this->getDbKey() ),
1988 'Title::getLinksTo',
1993 if ($db->numRows(
$res)) {
1994 while (
$row = $db->fetchObject(
$res)) {
1996 $linkCache->addGoodLinkObj(
$row->page_id, $titleObj);
1997 $retVal[] = $titleObj;
2001 $db->freeResult(
$res);
2029 $db = wfGetDB(DB_MASTER);
2031 $db = wfGetDB(DB_SLAVE);
2034 $res = $db->safeQuery(
2035 "SELECT pl_namespace, pl_title 2038 ON pl_namespace=page_namespace 2039 AND pl_title=page_title 2041 AND page_namespace IS NULL 2043 $db->tableName(
'pagelinks'),
2044 $db->tableName(
'page'),
2045 $this->getArticleId(),
2050 if ($db->numRows(
$res)) {
2051 while (
$row = $db->fetchObject(
$res)) {
2055 $db->freeResult(
$res);
2076 if ($wgContLang->hasVariants()) {
2077 $variants = $wgContLang->getVariants();
2078 foreach ($variants as $vCode) {
2079 if ($vCode==$wgContLang->getCode()) {
2094 $u =
new SquidUpdate(
$urls);
2105 return $this->
moveTo($nt,
false);
2119 if (!$this or !$nt) {
2120 return 'badtitletext';
2122 if ($this->
equals($nt)) {
2125 if (!$this->isMovable() || !$nt->isMovable()) {
2126 return 'immobile_namespace';
2130 $newid = $nt->getArticleID();
2132 if (strlen($nt->getDBkey()) < 1) {
2133 return 'articleexists';
2137 (
'' == $nt->getDBkey())) {
2138 return 'badarticleerror';
2142 !$this->
userCan(
'edit') || !$nt->userCan(
'edit') ||
2143 !$this->
userCan(
'move') || !$nt->userCan(
'move')
2145 return 'protectedpage';
2148 # The move is allowed only if (1) the target doesn't exist, or 2149 # (2) the target is a redirect to the source, and has no history 2150 # (so we can undo bad moves right after they're done). 2152 if (0 != $newid) { # Target
exists; check
for validity
2154 return 'articleexists';
2170 if (is_string($err)) {
2175 if ($nt->exists()) {
2177 $pageCountChange = 0;
2178 }
else { # Target didn
't exist, do normal move. 2179 $this->moveToNewTitle($nt, $reason); 2180 $pageCountChange = 1; 2182 $redirid = $this->getArticleID(); 2184 # Fixing category links (those without piped 'alternate
' names) to be sorted under the new title 2185 $dbw = wfGetDB(DB_MASTER); 2186 $categorylinks = $dbw->tableName('categorylinks
'); 2187 $sql = "UPDATE $categorylinks SET cl_sortkey=" . $dbw->addQuotes($nt->getPrefixedText()) . 2188 " WHERE cl_from=" . $dbw->addQuotes($pageid) . 2189 " AND cl_sortkey=" . $dbw->addQuotes($this->getPrefixedText()); 2190 $dbw->query($sql, 'SpecialMovepage::doSubmit
'); 2194 $oldnamespace = $this->getNamespace() & ~1; 2195 $newnamespace = $nt->getNamespace() & ~1; 2196 $oldtitle = $this->getDBkey(); 2197 $newtitle = $nt->getDBkey(); 2199 if ($oldnamespace != $newnamespace || $oldtitle != $newtitle) { 2200 WatchedItem::duplicateEntries($this, $nt); 2203 # Update search engine 2204 $u = new SearchUpdate($pageid, $nt->getPrefixedDBkey()); 2206 $u = new SearchUpdate($redirid, $this->getPrefixedDBkey(), ''); 2210 if ($this->isContentPage() && !$nt->isContentPage()) { 2211 # No longer a content page 2212 # Not viewed, edited, removing 2213 $u = new SiteStatsUpdate(0, 1, -1, $pageCountChange); 2214 } elseif (!$this->isContentPage() && $nt->isContentPage()) { 2215 # Now a content page 2216 # Not viewed, edited, adding 2217 $u = new SiteStatsUpdate(0, 1, +1, $pageCountChange); 2218 } elseif ($pageCountChange) { 2220 $u = new SiteStatsUpdate(0, 0, 0, 1); 2230 wfRunHooks('TitleMoveComplete
', array( &$this, &$nt, &$wgUser, $pageid, $redirid )); 2241 private function moveOverExistingRedirect(&$nt, $reason = '') 2245 $comment = wfMsgForContent('1movedto2_redir
', $this->getPrefixedText(), $nt->getPrefixedText()); 2248 $comment .= ": $reason"; 2251 $now = wfTimestampNow(); 2252 $newid = $nt->getArticleID(); 2253 $oldid = $this->getArticleID(); 2254 $dbw = wfGetDB(DB_MASTER); 2255 $linkCache =&LinkCache::singleton(); 2257 # Delete the old redirect. We don't save it
to history since
2258 # by definition if we've got here it's rather uninteresting. 2259 # We have to remove it so that the next step doesn't trigger 2260 # a conflict on the unique namespace+title index... 2261 $dbw->delete(
'page',
array(
'page_id' => $newid ), $fname);
2263 # Save a null revision in the page's history notifying of the move 2264 $nullRevision = Revision::newNullRevision($dbw, $oldid,
$comment,
true);
2265 $nullRevId = $nullRevision->insertOn($dbw);
2267 # Change the name of the target page: 2272 'page_touched' => $dbw->timestamp($now),
2273 'page_namespace' => $nt->getNamespace(),
2274 'page_title' => $nt->getDBkey(),
2275 'page_latest' => $nullRevId,
2278 array(
'page_id' => $oldid ),
2281 $linkCache->clearLink($nt->getPrefixedDBkey());
2283 # Recreate the redirect, this time in the other direction. 2284 $mwRedir = MagicWord::get(
'redirect');
2285 $redirectText = $mwRedir->getSynonym(0) .
' [[' . $nt->getPrefixedText() .
"]]\n";
2286 $redirectArticle =
new Article($this);
2287 $newid = $redirectArticle->insertOn($dbw);
2288 $redirectRevision =
new Revision(
array(
2291 'text' => $redirectText ));
2292 $redirectRevision->insertOn($dbw);
2293 $redirectArticle->updateRevisionOn($dbw, $redirectRevision, 0);
2297 $log =
new LogPage(
'move');
2298 $log->addEntry(
'move_redir', $this, $reason,
array( 1 => $nt->getPrefixedText() ));
2300 # Now, we record the link from the redirect to the new title. 2301 # It should have no other outgoing links... 2302 $dbw->delete(
'pagelinks',
array(
'pl_from' => $newid ), $fname);
2306 'pl_from' => $newid,
2307 'pl_namespace' => $nt->getNamespace(),
2308 'pl_title' => $nt->getDbKey() ),
2315 $u =
new SquidUpdate(
$urls);
2327 $fname =
'MovePageForm::moveToNewTitle';
2333 $newid = $nt->getArticleID();
2335 $dbw = wfGetDB(DB_MASTER);
2336 $now = $dbw->timestamp();
2337 $linkCache =&LinkCache::singleton();
2339 # Save a null revision in the page's history notifying of the move 2340 $nullRevision = Revision::newNullRevision($dbw, $oldid,
$comment,
true);
2341 $nullRevId = $nullRevision->insertOn($dbw);
2348 'page_touched' => $now,
2349 'page_namespace' => $nt->getNamespace(),
2350 'page_title' => $nt->getDBkey(),
2351 'page_latest' => $nullRevId,
2354 array(
'page_id' => $oldid ),
2358 $linkCache->clearLink($nt->getPrefixedDBkey());
2361 $mwRedir = MagicWord::get(
'redirect');
2362 $redirectText = $mwRedir->getSynonym(0) .
' [[' . $nt->getPrefixedText() .
"]]\n";
2363 $redirectArticle =
new Article($this);
2364 $newid = $redirectArticle->insertOn($dbw);
2365 $redirectRevision =
new Revision(
array(
2368 'text' => $redirectText ));
2369 $redirectRevision->insertOn($dbw);
2370 $redirectArticle->updateRevisionOn($dbw, $redirectRevision, 0);
2374 $log =
new LogPage(
'move');
2375 $log->addEntry(
'move', $this, $reason,
array( 1 => $nt->getPrefixedText()));
2377 # Purge caches as per article creation 2378 Article::onArticleCreate($nt);
2380 # Record the just-created redirect's linking to the page 2384 'pl_from' => $newid,
2385 'pl_namespace' => $nt->getNamespace(),
2386 'pl_title' => $nt->getDBkey() ),
2390 # Purge old title from squid 2391 # The new title, and links to the new title, are purged in Article::onArticleCreate() 2403 $fname =
'Title::isValidMoveTarget';
2404 $dbw = wfGetDB(DB_MASTER);
2407 $id = $nt->getArticleID();
2408 $obj = $dbw->selectRow(
2409 array(
'page',
'revision',
'text'),
2410 array(
'page_is_redirect',
'old_text',
'old_flags' ),
2411 array(
'page_id' =>
$id,
'page_latest=rev_id',
'rev_text_id=old_id' ),
2416 if (!$obj || 0 == $obj->page_is_redirect) {
2418 wfDebug(__METHOD__ .
": not a redirect\n");
2421 $text = Revision::getRevisionText($obj);
2423 # Does the redirect point to the source? 2424 # Or is it a broken self-redirect, usually caused by namespace collisions? 2426 if (preg_match(
"/\\[\\[\\s*([^\\]\\|]*)]]/",
$text,
$m)) {
2428 if (!is_object($redirTitle) ||
2430 $redirTitle->getPrefixedDBkey() != $nt->getPrefixedDBkey())) {
2431 wfDebug(__METHOD__ .
": redirect points to other page\n");
2436 wfDebug(__METHOD__ .
": failsafe\n");
2440 # Does the article have a history? 2441 $row = $dbw->selectRow(
2442 array(
'page',
'revision'),
2444 array(
'page_namespace' => $nt->getNamespace(),
2445 'page_title' => $nt->getDBkey(),
2446 'page_id=rev_page AND page_latest != rev_id' 2452 # Return true if there was no history 2453 return $row ===
false;
2467 $titlekey = $this->getArticleId();
2468 $dbr = wfGetDB(DB_SLAVE);
2469 $categorylinks = $dbr->tableName(
'categorylinks');
2472 $sql =
"SELECT * FROM $categorylinks" 2473 .
" WHERE cl_from='$titlekey'" 2474 .
" AND cl_from <> '0'" 2475 .
" ORDER BY cl_sortkey";
2477 $res = $dbr->query($sql) ;
2479 if ($dbr->numRows(
$res) > 0) {
2480 while (
$x = $dbr->fetchObject(
$res)) {
2484 $dbr->freeResult(
$res) ;
2500 if ($parents !=
'') {
2501 foreach ($parents as $parent =>
$current) {
2502 if (array_key_exists($parent, $children)) {
2503 # Circular reference 2504 $stack[$parent] =
array();
2508 $stack[$parent] = $nt->getParentCategoryTree($children +
array($parent => 1));
2527 return array(
'page_namespace' => $this->mNamespace,
'page_title' => $this->mDbkeyform );
2538 $dbr = wfGetDB(DB_SLAVE);
2539 return $dbr->selectField(
2542 'rev_page=' . intval($this->getArticleId()) .
2543 ' AND rev_id<' . intval($revision) .
' ORDER BY rev_id DESC' 2555 $dbr = wfGetDB(DB_SLAVE);
2556 return $dbr->selectField(
2559 'rev_page=' . intval($this->getArticleId()) .
2560 ' AND rev_id>' . intval($revision) .
' ORDER BY rev_id' 2573 $dbr = wfGetDB(DB_SLAVE);
2574 return $dbr->selectField(
2577 'rev_page = ' . intval($this->getArticleId()) .
2578 ' AND rev_id > ' . intval(
$old) .
2579 ' AND rev_id < ' . intval(
$new)
2594 && $this->getDbkey() ===
$title->getDbkey();
2603 return $this->getArticleId() != 0;
2625 $u =
new HTMLCacheUpdate($this,
'pagelinks');
2629 $u =
new HTMLCacheUpdate($this,
'categorylinks');
2639 $dbr = wfGetDB(DB_SLAVE);
2640 $touched = $dbr->selectField(
2654 global $wgTitle, $wgScriptPath, $wgServer;
2656 return "$wgServer$wgScriptPath/trackback.php?article=" 2657 . htmlspecialchars(urlencode($wgTitle->getPrefixedDBkey()));
2667 <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" 2668 xmlns:dc=\"http://purl.org/dc/elements/1.1/\" 2669 xmlns:trackback=\"http://madskills.com/public/xml/rss/module/trackback/\"> 2672 dc:identifier=\"$url\" 2674 trackback:ping=\"$tburl\" /> 2688 return 'nstab-main';
2691 return 'nstab-user';
2693 return 'nstab-media';
2695 return 'nstab-special';
2697 case NS_PROJECT_TALK:
2698 return 'nstab-project';
2701 return 'nstab-image';
2703 case NS_MEDIAWIKI_TALK:
2704 return 'nstab-mediawiki';
2706 case NS_TEMPLATE_TALK:
2707 return 'nstab-template';
2710 return 'nstab-help';
2712 case NS_CATEGORY_TALK:
2713 return 'nstab-category';
2715 return 'nstab-' . $wgContLang->lc($this->getSubjectNsText());
2726 list($thisName, ) = SpecialPage::resolveAliasWithSubpage($this->
getDBkey());
2727 if (
$name == $thisName) {
2741 $canonicalName = SpecialPage::resolveAlias($this->mDbkeyform);
2742 if ($canonicalName) {
2743 $localName = SpecialPage::getLocalNameFor($canonicalName);
2744 if ($localName != $this->mDbkeyform) {
isAlwaysKnown()
Should a link should be displayed as a known link, just based on its title?
static getInterwikiCached($key)
Fetch interwiki prefix data from local cache in constant database.
static purgeExpiredRestrictions()
Purge expired restrictions from the page_restrictions table.
if($err=$client->getError()) $namespace
setFragment($fragment)
Set the fragment for this title This is kind of bad, since except for this rarely-used function...
loadRestrictionsFromRow($res, $oldFashionedRestrictions=null)
Loads a string into mRestrictions array.
touchLinks()
Update page_touched timestamps and send squid purge messages for pages linking to this title...
userCanEditCssJsSubpage()
Protect css/js subpages of user pages: can $wgUser edit this page?
getFragment()
Get the Title fragment (i.e.
countRevisionsBetween($old, $new)
Get the number of revisions between the given revision IDs.
getLinksTo($options='', $table='pagelinks', $prefix='pl')
Get a Title object associated with the talk page of this article.
isJsSubpage()
Is this a .js subpage of a user page?
getSquidURLs()
Get a list of URLs to purge from the Squid cache when this page changes.
invalidateCache()
Updates page_touched for this page; called from LinksUpdate.php.
isSpecial($name)
Returns true if this title resolves to the named special page.
getArticleID($flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
getText()
Simple accessors.
getSubpageText()
Get the lowest-level subpage name, i.e.
getBaseText()
Get the base name, i.e.
nameOf($id)
Get the prefixed DB key associated with an ID.
static newMainPage()
Create a new Title for the Main Page.
isCssJsSubpage()
Is this a .css or .js subpage of a user page?
secureAndSplit()
Secure and split - main initialisation function for this object.
moveNoAuth(&$nt)
Move this page without authentication.
getInterwikiLink($key)
Returns the URL associated with an interwiki prefix.
prefix($name)
Prefix some arbitrary text with the namespace or interwiki prefix of this object. ...
isProtected($action='')
Does the title correspond to a protected article?
static escapeFragmentForURL($fragment)
Escape a text fragment, say from a link, for a URL.
isValidMoveTarget($nt)
Checks if $this can be moved to a given Title.
getLocalURL($query='', $variant=false)
Get a URL with no fragment or server name.
escapeLocalURL($query='')
Get an HTML-escaped version of the URL form, suitable for using in a link, without a server name or f...
if(!array_key_exists('StateId', $_REQUEST)) $id
$mHasCascadingRestrictions
exists()
Check if page exists.
getPrefixedText()
Get the prefixed title with spaces.
static newFromText($text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
getIndexTitle()
Get title for search index.
getParentCategories()
Get categories to which this Title belongs and return an array of categories' names.
getSkinFromCssJsSubpage()
Trim down a .css or .js subpage title to get the corresponding skin name.
static makeName($ns, $title)
getNamespaceKey()
Generate strings used for xml 'id' names in monobook tabs.
fixSpecialName()
If the Title refers to a special page alias which is not the local default, returns a new Title which...
userCanCreate($doExpensiveQueries=true)
Can $wgUser create this page?
userCanMove($doExpensiveQueries=true)
Can $wgUser move this page?
static decodeCharReferences($text)
Decode any character references, numeric or named entities, in the text and return a UTF-8 string...
userCanRead()
Would anybody with sufficient privileges be able to move this page? Some pages just aren't movable...
getNsText()
Get the namespace text.
isExternal()
Is this Title interwiki?
Done rendering charts as images
static newFromIDs($ids)
Make an array of titles from an array of IDs.
escapeFullURL($query='')
Get an HTML-escaped version of the URL form, suitable for using in a link, including the server name ...
getDBkey()
Get the main part with underscores.
getPrefixedURL()
Get a URL-encoded title (not an actual URL) including interwiki.
areRestrictionsCascading()
static newFromDBkey($key)
Create a new Title from a prefixed DB key.
getFullURL($query='', $variant=false)
Get a real URL referring to this title, with interwiki link and fragment.
getBrokenLinksFrom($options='')
Get an array of Title objects referring to non-existent articles linked from this page...
foreach($_POST as $key=> $value) $res
isCascadeProtected()
Cascading protection: Return true if cascading restrictions apply to this page, false if not...
getDefaultNamespace()
Get the default namespace index, for when there is no namespace.
getNextRevisionID($revision)
Get the revision ID of the next revision.
getFullText()
Get the prefixed title with spaces, plus any fragment (part beginning with '#')
isCssSubpage()
Is this a .css subpage of a user page?
static $titleCache
Static cache variables.
static indexTitle($ns, $title)
Get a string representation of a title suitable for including in a search index.
getTouched()
Get the last touched timestamp.
getNamespace()
Get the namespace index, i.e.
getCascadeProtectionSources($get_pages=true)
Cascading protection: Get the source of any cascading restrictions on this page.
static newFromRedirect($text)
Create a new Title for a redirect.
getPreviousRevisionID($revision)
Get the revision ID of the previous revision.
isSubpage()
Is this a talk page of some sort?
getInterwiki()
Get the namespace text of the subject (rather than talk) page.
static newFromID($id)
Create a new Title from an article ID.
getRestrictions($action)
Accessor/initialisation for mRestrictions.
quickUserCan($action)
Can $wgUser perform $action on this page? This skips potentially expensive cascading permission check...
getEditURL()
Get the edit URL for this Title.
static makeTitleSafe($ns, $title)
Create a new Title from a namespace index and a DB key.
Create styles array
The data for the language used.
loadRestrictions($oldFashionedRestrictions=null)
getSubpageUrlForm()
Get a URL-encoded form of the subpage text.
moveTo(&$nt, $auth=true, $reason='')
Move a title to a new location.
getEscapedText()
Get the HTML-escaped displayable text form.
moveToNewTitle(&$nt, $reason='')
Move page to non-existing title.
isTrans()
Determine whether the object refers to a page within this project and is transcludable.
static newFromURL($url)
Create a new Title from URL-encoded text.
getTemplateLinksTo($options='')
Get an array of Title objects using this Title as a template Also stores the IDs in the link cache...
moveOverExistingRedirect(&$nt, $reason='')
Move page to a title which is at present a redirect to the source page.
Create new PHPExcel object
obj_idprivate
getFragmentForURL()
Get the fragment in URL form, including the "#" character if there is one.
pageCond()
Get an associative array for selecting this title from the "page" table.
$mTextform
All member variables should be considered private Please use the accessor functions.
isValidMoveOperation(&$nt, $auth=true)
Check whether a given move operation would be valid.
static legalChars()
Get a regex character class describing the legal characters in a link.
static wfUrlencode($s)
From GlobalFunctions.php.
isDeleted()
Is there a version of this page in the deletion archive?
isLocal()
Determine whether the object refers to a page within this project.
static & makeTitle($ns, $title)
Create a new Title from a namespace index and a DB key.
isValidCssJsSubpage()
Is this a valid .css or .js subpage of a user page? Check that the corresponding skin exists...
userCanEdit($doExpensiveQueries=true)
Can $wgUser edit this page?
getParentCategoryTree($children=array())
Get a tree of parent categories.
if(empty($password)) $table
getInternalURL($query='', $variant=false)
Get the URL form for an internal link.
userCan($action, $doExpensiveQueries=true)
Can $wgUser perform $action on this page?
isSemiProtected($action='edit')
Is this page "semi-protected" - the only protection is autoconfirm?
userIsWatching()
Is $wgUser is watching this page?
$mCascadeRestrictionSources
equals($title)
Compare with another title.
resetArticleID($newid)
This clears some fields in this object, and clears any associated keys in the "bad links" section of ...
getPartialURL()
Get the URL-encoded form of the main part.
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
getPrefixedDBkey()
Get the prefixed database key form.