MediaWiki  1.33.0
Title.php
Go to the documentation of this file.
1 <?php
31 
40 class Title implements LinkTarget, IDBAccessObject {
42  private static $titleCache = null;
43 
49  const CACHE_MAX = 1000;
50 
55  const GAID_FOR_UPDATE = 1;
56 
64  const NEW_CLONE = 'clone';
65 
71  // @{
72 
74  public $mTextform = '';
75 
77  public $mUrlform = '';
78 
80  public $mDbkeyform = '';
81 
83  protected $mUserCaseDBKey;
84 
86  public $mNamespace = NS_MAIN;
87 
89  public $mInterwiki = '';
90 
92  private $mLocalInterwiki = false;
93 
95  public $mFragment = '';
96 
98  public $mArticleID = -1;
99 
101  protected $mLatestID = false;
102 
107  private $mContentModel = false;
108 
113  private $mForcedContentModel = false;
114 
117 
119  public $mRestrictions = [];
120 
127  protected $mOldRestrictions = false;
128 
131 
134 
136  protected $mRestrictionsExpiry = [];
137 
140 
143 
145  public $mRestrictionsLoaded = false;
146 
155  public $prefixedText = null;
156 
159 
166 
168  protected $mLength = -1;
169 
171  public $mRedirect = null;
172 
175 
177  private $mHasSubpages;
178 
180  private $mPageLanguage = false;
181 
184  private $mDbPageLanguage = false;
185 
187  private $mTitleValue = null;
188 
190  private $mIsBigDeletion = null;
191  // @}
192 
201  private static function getTitleFormatter() {
202  return MediaWikiServices::getInstance()->getTitleFormatter();
203  }
204 
213  private static function getInterwikiLookup() {
214  return MediaWikiServices::getInstance()->getInterwikiLookup();
215  }
216 
220  function __construct() {
221  }
222 
231  public static function newFromDBkey( $key ) {
232  $t = new self();
233  $t->mDbkeyform = $key;
234 
235  try {
236  $t->secureAndSplit();
237  return $t;
238  } catch ( MalformedTitleException $ex ) {
239  return null;
240  }
241  }
242 
254  public static function newFromTitleValue( TitleValue $titleValue, $forceClone = '' ) {
255  return self::newFromLinkTarget( $titleValue, $forceClone );
256  }
257 
269  public static function newFromLinkTarget( LinkTarget $linkTarget, $forceClone = '' ) {
270  if ( $linkTarget instanceof Title ) {
271  // Special case if it's already a Title object
272  if ( $forceClone === self::NEW_CLONE ) {
273  return clone $linkTarget;
274  } else {
275  return $linkTarget;
276  }
277  }
278  return self::makeTitle(
279  $linkTarget->getNamespace(),
280  $linkTarget->getText(),
281  $linkTarget->getFragment(),
282  $linkTarget->getInterwiki()
283  );
284  }
285 
306  public static function newFromText( $text, $defaultNamespace = NS_MAIN ) {
307  // DWIM: Integers can be passed in here when page titles are used as array keys.
308  if ( $text !== null && !is_string( $text ) && !is_int( $text ) ) {
309  throw new InvalidArgumentException( '$text must be a string.' );
310  }
311  if ( $text === null ) {
312  return null;
313  }
314 
315  try {
316  return self::newFromTextThrow( (string)$text, $defaultNamespace );
317  } catch ( MalformedTitleException $ex ) {
318  return null;
319  }
320  }
321 
343  public static function newFromTextThrow( $text, $defaultNamespace = NS_MAIN ) {
344  if ( is_object( $text ) ) {
345  throw new MWException( '$text must be a string, given an object' );
346  } elseif ( $text === null ) {
347  // Legacy code relies on MalformedTitleException being thrown in this case
348  // (happens when URL with no title in it is parsed). TODO fix
349  throw new MalformedTitleException( 'title-invalid-empty' );
350  }
351 
353 
354  // Wiki pages often contain multiple links to the same page.
355  // Title normalization and parsing can become expensive on pages with many
356  // links, so we can save a little time by caching them.
357  // In theory these are value objects and won't get changed...
358  if ( $defaultNamespace == NS_MAIN ) {
359  $t = $titleCache->get( $text );
360  if ( $t ) {
361  return $t;
362  }
363  }
364 
365  // Convert things like &eacute; &#257; or &#x3017; into normalized (T16952) text
366  $filteredText = Sanitizer::decodeCharReferencesAndNormalize( $text );
367 
368  $t = new Title();
369  $t->mDbkeyform = strtr( $filteredText, ' ', '_' );
370  $t->mDefaultNamespace = (int)$defaultNamespace;
371 
372  $t->secureAndSplit();
373  if ( $defaultNamespace == NS_MAIN ) {
374  $titleCache->set( $text, $t );
375  }
376  return $t;
377  }
378 
394  public static function newFromURL( $url ) {
395  $t = new Title();
396 
397  # For compatibility with old buggy URLs. "+" is usually not valid in titles,
398  # but some URLs used it as a space replacement and they still come
399  # from some external search tools.
400  if ( strpos( self::legalChars(), '+' ) === false ) {
401  $url = strtr( $url, '+', ' ' );
402  }
403 
404  $t->mDbkeyform = strtr( $url, ' ', '_' );
405 
406  try {
407  $t->secureAndSplit();
408  return $t;
409  } catch ( MalformedTitleException $ex ) {
410  return null;
411  }
412  }
413 
417  private static function getTitleCache() {
418  if ( self::$titleCache === null ) {
419  self::$titleCache = new MapCacheLRU( self::CACHE_MAX );
420  }
421  return self::$titleCache;
422  }
423 
431  protected static function getSelectFields() {
433 
434  $fields = [
435  'page_namespace', 'page_title', 'page_id',
436  'page_len', 'page_is_redirect', 'page_latest',
437  ];
438 
439  if ( $wgContentHandlerUseDB ) {
440  $fields[] = 'page_content_model';
441  }
442 
443  if ( $wgPageLanguageUseDB ) {
444  $fields[] = 'page_lang';
445  }
446 
447  return $fields;
448  }
449 
457  public static function newFromID( $id, $flags = 0 ) {
458  $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
459  $row = $db->selectRow(
460  'page',
461  self::getSelectFields(),
462  [ 'page_id' => $id ],
463  __METHOD__
464  );
465  if ( $row !== false ) {
466  $title = self::newFromRow( $row );
467  } else {
468  $title = null;
469  }
470 
471  return $title;
472  }
473 
480  public static function newFromIDs( $ids ) {
481  if ( !count( $ids ) ) {
482  return [];
483  }
484  $dbr = wfGetDB( DB_REPLICA );
485 
486  $res = $dbr->select(
487  'page',
488  self::getSelectFields(),
489  [ 'page_id' => $ids ],
490  __METHOD__
491  );
492 
493  $titles = [];
494  foreach ( $res as $row ) {
495  $titles[] = self::newFromRow( $row );
496  }
497  return $titles;
498  }
499 
506  public static function newFromRow( $row ) {
507  $t = self::makeTitle( $row->page_namespace, $row->page_title );
508  $t->loadFromRow( $row );
509  return $t;
510  }
511 
518  public function loadFromRow( $row ) {
519  if ( $row ) { // page found
520  if ( isset( $row->page_id ) ) {
521  $this->mArticleID = (int)$row->page_id;
522  }
523  if ( isset( $row->page_len ) ) {
524  $this->mLength = (int)$row->page_len;
525  }
526  if ( isset( $row->page_is_redirect ) ) {
527  $this->mRedirect = (bool)$row->page_is_redirect;
528  }
529  if ( isset( $row->page_latest ) ) {
530  $this->mLatestID = (int)$row->page_latest;
531  }
532  if ( !$this->mForcedContentModel && isset( $row->page_content_model ) ) {
533  $this->mContentModel = (string)$row->page_content_model;
534  } elseif ( !$this->mForcedContentModel ) {
535  $this->mContentModel = false; # initialized lazily in getContentModel()
536  }
537  if ( isset( $row->page_lang ) ) {
538  $this->mDbPageLanguage = (string)$row->page_lang;
539  }
540  if ( isset( $row->page_restrictions ) ) {
541  $this->mOldRestrictions = $row->page_restrictions;
542  }
543  } else { // page not found
544  $this->mArticleID = 0;
545  $this->mLength = 0;
546  $this->mRedirect = false;
547  $this->mLatestID = 0;
548  if ( !$this->mForcedContentModel ) {
549  $this->mContentModel = false; # initialized lazily in getContentModel()
550  }
551  }
552  }
553 
576  public static function makeTitle( $ns, $title, $fragment = '', $interwiki = '' ) {
577  $t = new Title();
578  $t->mInterwiki = $interwiki;
579  $t->mFragment = $fragment;
580  $t->mNamespace = $ns = (int)$ns;
581  $t->mDbkeyform = strtr( $title, ' ', '_' );
582  $t->mArticleID = ( $ns >= 0 ) ? -1 : 0;
583  $t->mUrlform = wfUrlencode( $t->mDbkeyform );
584  $t->mTextform = strtr( $title, '_', ' ' );
585  $t->mContentModel = false; # initialized lazily in getContentModel()
586  return $t;
587  }
588 
604  public static function makeTitleSafe( $ns, $title, $fragment = '', $interwiki = '' ) {
605  // NOTE: ideally, this would just call makeTitle() and then isValid(),
606  // but presently, that means more overhead on a potential performance hotspot.
607 
608  if ( !MWNamespace::exists( $ns ) ) {
609  return null;
610  }
611 
612  $t = new Title();
613  $t->mDbkeyform = self::makeName( $ns, $title, $fragment, $interwiki, true );
614 
615  try {
616  $t->secureAndSplit();
617  return $t;
618  } catch ( MalformedTitleException $ex ) {
619  return null;
620  }
621  }
622 
632  public static function newMainPage() {
633  $title = self::newFromText( wfMessage( 'mainpage' )->inContentLanguage()->text() );
634  // Don't give fatal errors if the message is broken
635  if ( !$title ) {
636  $title = self::newFromText( 'Main Page' );
637  }
638  return $title;
639  }
640 
647  public static function nameOf( $id ) {
648  $dbr = wfGetDB( DB_REPLICA );
649 
650  $s = $dbr->selectRow(
651  'page',
652  [ 'page_namespace', 'page_title' ],
653  [ 'page_id' => $id ],
654  __METHOD__
655  );
656  if ( $s === false ) {
657  return null;
658  }
659 
660  $n = self::makeName( $s->page_namespace, $s->page_title );
661  return $n;
662  }
663 
669  public static function legalChars() {
670  global $wgLegalTitleChars;
671  return $wgLegalTitleChars;
672  }
673 
683  public static function convertByteClassToUnicodeClass( $byteClass ) {
684  $length = strlen( $byteClass );
685  // Input token queue
686  $x0 = $x1 = $x2 = '';
687  // Decoded queue
688  $d0 = $d1 = $d2 = '';
689  // Decoded integer codepoints
690  $ord0 = $ord1 = $ord2 = 0;
691  // Re-encoded queue
692  $r0 = $r1 = $r2 = '';
693  // Output
694  $out = '';
695  // Flags
696  $allowUnicode = false;
697  for ( $pos = 0; $pos < $length; $pos++ ) {
698  // Shift the queues down
699  $x2 = $x1;
700  $x1 = $x0;
701  $d2 = $d1;
702  $d1 = $d0;
703  $ord2 = $ord1;
704  $ord1 = $ord0;
705  $r2 = $r1;
706  $r1 = $r0;
707  // Load the current input token and decoded values
708  $inChar = $byteClass[$pos];
709  if ( $inChar == '\\' ) {
710  if ( preg_match( '/x([0-9a-fA-F]{2})/A', $byteClass, $m, 0, $pos + 1 ) ) {
711  $x0 = $inChar . $m[0];
712  $d0 = chr( hexdec( $m[1] ) );
713  $pos += strlen( $m[0] );
714  } elseif ( preg_match( '/[0-7]{3}/A', $byteClass, $m, 0, $pos + 1 ) ) {
715  $x0 = $inChar . $m[0];
716  $d0 = chr( octdec( $m[0] ) );
717  $pos += strlen( $m[0] );
718  } elseif ( $pos + 1 >= $length ) {
719  $x0 = $d0 = '\\';
720  } else {
721  $d0 = $byteClass[$pos + 1];
722  $x0 = $inChar . $d0;
723  $pos += 1;
724  }
725  } else {
726  $x0 = $d0 = $inChar;
727  }
728  $ord0 = ord( $d0 );
729  // Load the current re-encoded value
730  if ( $ord0 < 32 || $ord0 == 0x7f ) {
731  $r0 = sprintf( '\x%02x', $ord0 );
732  } elseif ( $ord0 >= 0x80 ) {
733  // Allow unicode if a single high-bit character appears
734  $r0 = sprintf( '\x%02x', $ord0 );
735  $allowUnicode = true;
736  // @phan-suppress-next-line PhanParamSuspiciousOrder false positive
737  } elseif ( strpos( '-\\[]^', $d0 ) !== false ) {
738  $r0 = '\\' . $d0;
739  } else {
740  $r0 = $d0;
741  }
742  // Do the output
743  if ( $x0 !== '' && $x1 === '-' && $x2 !== '' ) {
744  // Range
745  if ( $ord2 > $ord0 ) {
746  // Empty range
747  } elseif ( $ord0 >= 0x80 ) {
748  // Unicode range
749  $allowUnicode = true;
750  if ( $ord2 < 0x80 ) {
751  // Keep the non-unicode section of the range
752  $out .= "$r2-\\x7F";
753  }
754  } else {
755  // Normal range
756  $out .= "$r2-$r0";
757  }
758  // Reset state to the initial value
759  $x0 = $x1 = $d0 = $d1 = $r0 = $r1 = '';
760  } elseif ( $ord2 < 0x80 ) {
761  // ASCII character
762  $out .= $r2;
763  }
764  }
765  if ( $ord1 < 0x80 ) {
766  $out .= $r1;
767  }
768  if ( $ord0 < 0x80 ) {
769  $out .= $r0;
770  }
771  if ( $allowUnicode ) {
772  $out .= '\u0080-\uFFFF';
773  }
774  return $out;
775  }
776 
788  public static function makeName( $ns, $title, $fragment = '', $interwiki = '',
789  $canonicalNamespace = false
790  ) {
791  if ( $canonicalNamespace ) {
792  $namespace = MWNamespace::getCanonicalName( $ns );
793  } else {
794  $namespace = MediaWikiServices::getInstance()->getContentLanguage()->getNsText( $ns );
795  }
796  $name = $namespace == '' ? $title : "$namespace:$title";
797  if ( strval( $interwiki ) != '' ) {
798  $name = "$interwiki:$name";
799  }
800  if ( strval( $fragment ) != '' ) {
801  $name .= '#' . $fragment;
802  }
803  return $name;
804  }
805 
814  public static function compare( LinkTarget $a, LinkTarget $b ) {
815  return $a->getNamespace() <=> $b->getNamespace()
816  ?: strcmp( $a->getText(), $b->getText() );
817  }
818 
833  public function isValid() {
834  if ( !MWNamespace::exists( $this->mNamespace ) ) {
835  return false;
836  }
837 
838  try {
839  $parser = MediaWikiServices::getInstance()->getTitleParser();
840  $parser->parseTitle( $this->mDbkeyform, $this->mNamespace );
841  return true;
842  } catch ( MalformedTitleException $ex ) {
843  return false;
844  }
845  }
846 
854  public function isLocal() {
855  if ( $this->isExternal() ) {
856  $iw = self::getInterwikiLookup()->fetch( $this->mInterwiki );
857  if ( $iw ) {
858  return $iw->isLocal();
859  }
860  }
861  return true;
862  }
863 
869  public function isExternal() {
870  return $this->mInterwiki !== '';
871  }
872 
880  public function getInterwiki() {
881  return $this->mInterwiki;
882  }
883 
889  public function wasLocalInterwiki() {
890  return $this->mLocalInterwiki;
891  }
892 
899  public function isTrans() {
900  if ( !$this->isExternal() ) {
901  return false;
902  }
903 
904  return self::getInterwikiLookup()->fetch( $this->mInterwiki )->isTranscludable();
905  }
906 
912  public function getTransWikiID() {
913  if ( !$this->isExternal() ) {
914  return false;
915  }
916 
917  return self::getInterwikiLookup()->fetch( $this->mInterwiki )->getWikiID();
918  }
919 
929  public function getTitleValue() {
930  if ( $this->mTitleValue === null ) {
931  try {
932  $this->mTitleValue = new TitleValue(
933  $this->mNamespace,
934  $this->mDbkeyform,
935  $this->mFragment,
936  $this->mInterwiki
937  );
938  } catch ( InvalidArgumentException $ex ) {
939  wfDebug( __METHOD__ . ': Can\'t create a TitleValue for [[' .
940  $this->getPrefixedText() . ']]: ' . $ex->getMessage() . "\n" );
941  }
942  }
943 
944  return $this->mTitleValue;
945  }
946 
952  public function getText() {
953  return $this->mTextform;
954  }
955 
961  public function getPartialURL() {
962  return $this->mUrlform;
963  }
964 
970  public function getDBkey() {
971  return $this->mDbkeyform;
972  }
973 
980  function getUserCaseDBKey() {
981  if ( !is_null( $this->mUserCaseDBKey ) ) {
982  return $this->mUserCaseDBKey;
983  } else {
984  // If created via makeTitle(), $this->mUserCaseDBKey is not set.
985  return $this->mDbkeyform;
986  }
987  }
988 
994  public function getNamespace() {
995  return $this->mNamespace;
996  }
997 
1006  public function getContentModel( $flags = 0 ) {
1007  if ( !$this->mForcedContentModel
1008  && ( !$this->mContentModel || $flags === self::GAID_FOR_UPDATE )
1009  && $this->getArticleID( $flags )
1010  ) {
1011  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
1012  $linkCache->addLinkObj( $this ); # in case we already had an article ID
1013  $this->mContentModel = $linkCache->getGoodLinkFieldObj( $this, 'model' );
1014  }
1015 
1016  if ( !$this->mContentModel ) {
1017  $this->mContentModel = ContentHandler::getDefaultModelFor( $this );
1018  }
1019 
1020  return $this->mContentModel;
1021  }
1022 
1029  public function hasContentModel( $id ) {
1030  return $this->getContentModel() == $id;
1031  }
1032 
1044  public function setContentModel( $model ) {
1045  $this->mContentModel = $model;
1046  $this->mForcedContentModel = true;
1047  }
1048 
1054  public function getNsText() {
1055  if ( $this->isExternal() ) {
1056  // This probably shouldn't even happen, except for interwiki transclusion.
1057  // If possible, use the canonical name for the foreign namespace.
1058  $nsText = MWNamespace::getCanonicalName( $this->mNamespace );
1059  if ( $nsText !== false ) {
1060  return $nsText;
1061  }
1062  }
1063 
1064  try {
1065  $formatter = self::getTitleFormatter();
1066  return $formatter->getNamespaceName( $this->mNamespace, $this->mDbkeyform );
1067  } catch ( InvalidArgumentException $ex ) {
1068  wfDebug( __METHOD__ . ': ' . $ex->getMessage() . "\n" );
1069  return false;
1070  }
1071  }
1072 
1078  public function getSubjectNsText() {
1079  return MediaWikiServices::getInstance()->getContentLanguage()->
1080  getNsText( MWNamespace::getSubject( $this->mNamespace ) );
1081  }
1082 
1088  public function getTalkNsText() {
1089  return MediaWikiServices::getInstance()->getContentLanguage()->
1090  getNsText( MWNamespace::getTalk( $this->mNamespace ) );
1091  }
1092 
1101  public function canHaveTalkPage() {
1102  return MWNamespace::hasTalkNamespace( $this->mNamespace );
1103  }
1104 
1110  public function canExist() {
1111  return $this->mNamespace >= NS_MAIN;
1112  }
1113 
1119  public function isWatchable() {
1120  return !$this->isExternal() && MWNamespace::isWatchable( $this->mNamespace );
1121  }
1122 
1128  public function isSpecialPage() {
1129  return $this->mNamespace == NS_SPECIAL;
1130  }
1131 
1138  public function isSpecial( $name ) {
1139  if ( $this->isSpecialPage() ) {
1140  list( $thisName, /* $subpage */ ) =
1141  MediaWikiServices::getInstance()->getSpecialPageFactory()->
1142  resolveAlias( $this->mDbkeyform );
1143  if ( $name == $thisName ) {
1144  return true;
1145  }
1146  }
1147  return false;
1148  }
1149 
1156  public function fixSpecialName() {
1157  if ( $this->isSpecialPage() ) {
1158  $spFactory = MediaWikiServices::getInstance()->getSpecialPageFactory();
1159  list( $canonicalName, $par ) = $spFactory->resolveAlias( $this->mDbkeyform );
1160  if ( $canonicalName ) {
1161  $localName = $spFactory->getLocalNameFor( $canonicalName, $par );
1162  if ( $localName != $this->mDbkeyform ) {
1163  return self::makeTitle( NS_SPECIAL, $localName );
1164  }
1165  }
1166  }
1167  return $this;
1168  }
1169 
1180  public function inNamespace( $ns ) {
1181  return MWNamespace::equals( $this->mNamespace, $ns );
1182  }
1183 
1191  public function inNamespaces( /* ... */ ) {
1192  $namespaces = func_get_args();
1193  if ( count( $namespaces ) > 0 && is_array( $namespaces[0] ) ) {
1194  $namespaces = $namespaces[0];
1195  }
1196 
1197  foreach ( $namespaces as $ns ) {
1198  if ( $this->inNamespace( $ns ) ) {
1199  return true;
1200  }
1201  }
1202 
1203  return false;
1204  }
1205 
1219  public function hasSubjectNamespace( $ns ) {
1220  return MWNamespace::subjectEquals( $this->mNamespace, $ns );
1221  }
1222 
1230  public function isContentPage() {
1231  return MWNamespace::isContent( $this->mNamespace );
1232  }
1233 
1240  public function isMovable() {
1241  if ( !MWNamespace::isMovable( $this->mNamespace ) || $this->isExternal() ) {
1242  // Interwiki title or immovable namespace. Hooks don't get to override here
1243  return false;
1244  }
1245 
1246  $result = true;
1247  Hooks::run( 'TitleIsMovable', [ $this, &$result ] );
1248  return $result;
1249  }
1250 
1261  public function isMainPage() {
1262  return $this->equals( self::newMainPage() );
1263  }
1264 
1270  public function isSubpage() {
1271  return MWNamespace::hasSubpages( $this->mNamespace )
1272  ? strpos( $this->getText(), '/' ) !== false
1273  : false;
1274  }
1275 
1281  public function isConversionTable() {
1282  // @todo ConversionTable should become a separate content model.
1283 
1284  return $this->mNamespace == NS_MEDIAWIKI &&
1285  strpos( $this->getText(), 'Conversiontable/' ) === 0;
1286  }
1287 
1293  public function isWikitextPage() {
1294  return $this->hasContentModel( CONTENT_MODEL_WIKITEXT );
1295  }
1296 
1311  public function isSiteConfigPage() {
1312  return (
1313  $this->isSiteCssConfigPage()
1314  || $this->isSiteJsonConfigPage()
1315  || $this->isSiteJsConfigPage()
1316  );
1317  }
1318 
1325  public function isUserConfigPage() {
1326  return (
1327  $this->isUserCssConfigPage()
1328  || $this->isUserJsonConfigPage()
1329  || $this->isUserJsConfigPage()
1330  );
1331  }
1332 
1339  public function getSkinFromConfigSubpage() {
1340  $subpage = explode( '/', $this->mTextform );
1341  $subpage = $subpage[count( $subpage ) - 1];
1342  $lastdot = strrpos( $subpage, '.' );
1343  if ( $lastdot === false ) {
1344  return $subpage; # Never happens: only called for names ending in '.css'/'.json'/'.js'
1345  }
1346  return substr( $subpage, 0, $lastdot );
1347  }
1348 
1355  public function isUserCssConfigPage() {
1356  return (
1357  NS_USER == $this->mNamespace
1358  && $this->isSubpage()
1359  && $this->hasContentModel( CONTENT_MODEL_CSS )
1360  );
1361  }
1362 
1369  public function isUserJsonConfigPage() {
1370  return (
1371  NS_USER == $this->mNamespace
1372  && $this->isSubpage()
1373  && $this->hasContentModel( CONTENT_MODEL_JSON )
1374  );
1375  }
1376 
1383  public function isUserJsConfigPage() {
1384  return (
1385  NS_USER == $this->mNamespace
1386  && $this->isSubpage()
1388  );
1389  }
1390 
1397  public function isSiteCssConfigPage() {
1398  return (
1399  NS_MEDIAWIKI == $this->mNamespace
1400  && (
1402  // paranoia - a MediaWiki: namespace page with mismatching extension and content
1403  // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
1404  || substr( $this->mDbkeyform, -4 ) === '.css'
1405  )
1406  );
1407  }
1408 
1415  public function isSiteJsonConfigPage() {
1416  return (
1417  NS_MEDIAWIKI == $this->mNamespace
1418  && (
1420  // paranoia - a MediaWiki: namespace page with mismatching extension and content
1421  // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
1422  || substr( $this->mDbkeyform, -5 ) === '.json'
1423  )
1424  );
1425  }
1426 
1433  public function isSiteJsConfigPage() {
1434  return (
1435  NS_MEDIAWIKI == $this->mNamespace
1436  && (
1438  // paranoia - a MediaWiki: namespace page with mismatching extension and content
1439  // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
1440  || substr( $this->mDbkeyform, -3 ) === '.js'
1441  )
1442  );
1443  }
1444 
1451  public function isRawHtmlMessage() {
1452  global $wgRawHtmlMessages;
1453 
1454  if ( !$this->inNamespace( NS_MEDIAWIKI ) ) {
1455  return false;
1456  }
1457  $message = lcfirst( $this->getRootTitle()->getDBkey() );
1458  return in_array( $message, $wgRawHtmlMessages, true );
1459  }
1460 
1466  public function isTalkPage() {
1467  return MWNamespace::isTalk( $this->mNamespace );
1468  }
1469 
1475  public function getTalkPage() {
1476  return self::makeTitle( MWNamespace::getTalk( $this->mNamespace ), $this->mDbkeyform );
1477  }
1478 
1488  public function getTalkPageIfDefined() {
1489  if ( !$this->canHaveTalkPage() ) {
1490  return null;
1491  }
1492 
1493  return $this->getTalkPage();
1494  }
1495 
1502  public function getSubjectPage() {
1503  // Is this the same title?
1504  $subjectNS = MWNamespace::getSubject( $this->mNamespace );
1505  if ( $this->mNamespace == $subjectNS ) {
1506  return $this;
1507  }
1508  return self::makeTitle( $subjectNS, $this->mDbkeyform );
1509  }
1510 
1519  public function getOtherPage() {
1520  if ( $this->isSpecialPage() ) {
1521  throw new MWException( 'Special pages cannot have other pages' );
1522  }
1523  if ( $this->isTalkPage() ) {
1524  return $this->getSubjectPage();
1525  } else {
1526  if ( !$this->canHaveTalkPage() ) {
1527  throw new MWException( "{$this->getPrefixedText()} does not have an other page" );
1528  }
1529  return $this->getTalkPage();
1530  }
1531  }
1532 
1538  public function getDefaultNamespace() {
1539  return $this->mDefaultNamespace;
1540  }
1541 
1549  public function getFragment() {
1550  return $this->mFragment;
1551  }
1552 
1559  public function hasFragment() {
1560  return $this->mFragment !== '';
1561  }
1562 
1568  public function getFragmentForURL() {
1569  if ( !$this->hasFragment() ) {
1570  return '';
1571  } elseif ( $this->isExternal() ) {
1572  // Note: If the interwiki is unknown, it's treated as a namespace on the local wiki,
1573  // so we treat it like a local interwiki.
1574  $interwiki = self::getInterwikiLookup()->fetch( $this->mInterwiki );
1575  if ( $interwiki && !$interwiki->isLocal() ) {
1576  return '#' . Sanitizer::escapeIdForExternalInterwiki( $this->mFragment );
1577  }
1578  }
1579 
1580  return '#' . Sanitizer::escapeIdForLink( $this->mFragment );
1581  }
1582 
1595  public function setFragment( $fragment ) {
1596  $this->mFragment = strtr( substr( $fragment, 1 ), '_', ' ' );
1597  }
1598 
1606  public function createFragmentTarget( $fragment ) {
1607  return self::makeTitle(
1608  $this->mNamespace,
1609  $this->getText(),
1610  $fragment,
1611  $this->mInterwiki
1612  );
1613  }
1614 
1622  private function prefix( $name ) {
1623  $p = '';
1624  if ( $this->isExternal() ) {
1625  $p = $this->mInterwiki . ':';
1626  }
1627 
1628  if ( $this->mNamespace != 0 ) {
1629  $nsText = $this->getNsText();
1630 
1631  if ( $nsText === false ) {
1632  // See T165149. Awkward, but better than erroneously linking to the main namespace.
1633  $nsText = MediaWikiServices::getInstance()->getContentLanguage()->
1634  getNsText( NS_SPECIAL ) . ":Badtitle/NS{$this->mNamespace}";
1635  }
1636 
1637  $p .= $nsText . ':';
1638  }
1639  return $p . $name;
1640  }
1641 
1648  public function getPrefixedDBkey() {
1649  $s = $this->prefix( $this->mDbkeyform );
1650  $s = strtr( $s, ' ', '_' );
1651  return $s;
1652  }
1653 
1660  public function getPrefixedText() {
1661  if ( $this->prefixedText === null ) {
1662  $s = $this->prefix( $this->mTextform );
1663  $s = strtr( $s, '_', ' ' );
1664  $this->prefixedText = $s;
1665  }
1666  return $this->prefixedText;
1667  }
1668 
1674  public function __toString() {
1675  return $this->getPrefixedText();
1676  }
1677 
1684  public function getFullText() {
1685  $text = $this->getPrefixedText();
1686  if ( $this->hasFragment() ) {
1687  $text .= '#' . $this->mFragment;
1688  }
1689  return $text;
1690  }
1691 
1704  public function getRootText() {
1705  if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
1706  return $this->getText();
1707  }
1708 
1709  return strtok( $this->getText(), '/' );
1710  }
1711 
1724  public function getRootTitle() {
1725  return self::makeTitle( $this->mNamespace, $this->getRootText() );
1726  }
1727 
1739  public function getBaseText() {
1740  $text = $this->getText();
1741  if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
1742  return $text;
1743  }
1744 
1745  $lastSlashPos = strrpos( $text, '/' );
1746  // Don't discard the real title if there's no subpage involved
1747  if ( $lastSlashPos === false ) {
1748  return $text;
1749  }
1750 
1751  return substr( $text, 0, $lastSlashPos );
1752  }
1753 
1766  public function getBaseTitle() {
1767  return self::makeTitle( $this->mNamespace, $this->getBaseText() );
1768  }
1769 
1781  public function getSubpageText() {
1782  if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
1783  return $this->mTextform;
1784  }
1785  $parts = explode( '/', $this->mTextform );
1786  return $parts[count( $parts ) - 1];
1787  }
1788 
1802  public function getSubpage( $text ) {
1803  return self::makeTitleSafe( $this->mNamespace, $this->getText() . '/' . $text );
1804  }
1805 
1811  public function getSubpageUrlForm() {
1812  $text = $this->getSubpageText();
1813  $text = wfUrlencode( strtr( $text, ' ', '_' ) );
1814  return $text;
1815  }
1816 
1822  public function getPrefixedURL() {
1823  $s = $this->prefix( $this->mDbkeyform );
1824  $s = wfUrlencode( strtr( $s, ' ', '_' ) );
1825  return $s;
1826  }
1827 
1841  private static function fixUrlQueryArgs( $query, $query2 = false ) {
1842  if ( $query2 !== false ) {
1843  wfDeprecated( "Title::get{Canonical,Full,Link,Local,Internal}URL " .
1844  "method called with a second parameter is deprecated. Add your " .
1845  "parameter to an array passed as the first parameter.", "1.19" );
1846  }
1847  if ( is_array( $query ) ) {
1848  $query = wfArrayToCgi( $query );
1849  }
1850  if ( $query2 ) {
1851  if ( is_string( $query2 ) ) {
1852  // $query2 is a string, we will consider this to be
1853  // a deprecated $variant argument and add it to the query
1854  $query2 = wfArrayToCgi( [ 'variant' => $query2 ] );
1855  } else {
1856  $query2 = wfArrayToCgi( $query2 );
1857  }
1858  // If we have $query content add a & to it first
1859  if ( $query ) {
1860  $query .= '&';
1861  }
1862  // Now append the queries together
1863  $query .= $query2;
1864  }
1865  return $query;
1866  }
1867 
1879  public function getFullURL( $query = '', $query2 = false, $proto = PROTO_RELATIVE ) {
1880  $query = self::fixUrlQueryArgs( $query, $query2 );
1881 
1882  # Hand off all the decisions on urls to getLocalURL
1883  $url = $this->getLocalURL( $query );
1884 
1885  # Expand the url to make it a full url. Note that getLocalURL has the
1886  # potential to output full urls for a variety of reasons, so we use
1887  # wfExpandUrl instead of simply prepending $wgServer
1888  $url = wfExpandUrl( $url, $proto );
1889 
1890  # Finally, add the fragment.
1891  $url .= $this->getFragmentForURL();
1892  // Avoid PHP 7.1 warning from passing $this by reference
1893  $titleRef = $this;
1894  Hooks::run( 'GetFullURL', [ &$titleRef, &$url, $query ] );
1895  return $url;
1896  }
1897 
1914  public function getFullUrlForRedirect( $query = '', $proto = PROTO_CURRENT ) {
1915  $target = $this;
1916  if ( $this->isExternal() ) {
1917  $target = SpecialPage::getTitleFor(
1918  'GoToInterwiki',
1919  $this->getPrefixedDBkey()
1920  );
1921  }
1922  return $target->getFullURL( $query, false, $proto );
1923  }
1924 
1948  public function getLocalURL( $query = '', $query2 = false ) {
1950 
1951  $query = self::fixUrlQueryArgs( $query, $query2 );
1952 
1953  $interwiki = self::getInterwikiLookup()->fetch( $this->mInterwiki );
1954  if ( $interwiki ) {
1955  $namespace = $this->getNsText();
1956  if ( $namespace != '' ) {
1957  # Can this actually happen? Interwikis shouldn't be parsed.
1958  # Yes! It can in interwiki transclusion. But... it probably shouldn't.
1959  $namespace .= ':';
1960  }
1961  $url = $interwiki->getURL( $namespace . $this->mDbkeyform );
1962  $url = wfAppendQuery( $url, $query );
1963  } else {
1964  $dbkey = wfUrlencode( $this->getPrefixedDBkey() );
1965  if ( $query == '' ) {
1966  $url = str_replace( '$1', $dbkey, $wgArticlePath );
1967  // Avoid PHP 7.1 warning from passing $this by reference
1968  $titleRef = $this;
1969  Hooks::run( 'GetLocalURL::Article', [ &$titleRef, &$url ] );
1970  } else {
1972  $url = false;
1973  $matches = [];
1974 
1975  if ( !empty( $wgActionPaths )
1976  && preg_match( '/^(.*&|)action=([^&]*)(&(.*)|)$/', $query, $matches )
1977  ) {
1978  $action = urldecode( $matches[2] );
1979  if ( isset( $wgActionPaths[$action] ) ) {
1980  $query = $matches[1];
1981  if ( isset( $matches[4] ) ) {
1982  $query .= $matches[4];
1983  }
1984  $url = str_replace( '$1', $dbkey, $wgActionPaths[$action] );
1985  if ( $query != '' ) {
1986  $url = wfAppendQuery( $url, $query );
1987  }
1988  }
1989  }
1990 
1991  if ( $url === false
1993  && preg_match( '/^variant=([^&]*)$/', $query, $matches )
1994  && $this->getPageLanguage()->equals(
1995  MediaWikiServices::getInstance()->getContentLanguage() )
1996  && $this->getPageLanguage()->hasVariants()
1997  ) {
1998  $variant = urldecode( $matches[1] );
1999  if ( $this->getPageLanguage()->hasVariant( $variant ) ) {
2000  // Only do the variant replacement if the given variant is a valid
2001  // variant for the page's language.
2002  $url = str_replace( '$2', urlencode( $variant ), $wgVariantArticlePath );
2003  $url = str_replace( '$1', $dbkey, $url );
2004  }
2005  }
2006 
2007  if ( $url === false ) {
2008  if ( $query == '-' ) {
2009  $query = '';
2010  }
2011  $url = "{$wgScript}?title={$dbkey}&{$query}";
2012  }
2013  }
2014  // Avoid PHP 7.1 warning from passing $this by reference
2015  $titleRef = $this;
2016  Hooks::run( 'GetLocalURL::Internal', [ &$titleRef, &$url, $query ] );
2017 
2018  // @todo FIXME: This causes breakage in various places when we
2019  // actually expected a local URL and end up with dupe prefixes.
2020  if ( $wgRequest->getVal( 'action' ) == 'render' ) {
2021  $url = $wgServer . $url;
2022  }
2023  }
2024  // Avoid PHP 7.1 warning from passing $this by reference
2025  $titleRef = $this;
2026  Hooks::run( 'GetLocalURL', [ &$titleRef, &$url, $query ] );
2027  return $url;
2028  }
2029 
2047  public function getLinkURL( $query = '', $query2 = false, $proto = false ) {
2048  if ( $this->isExternal() || $proto !== false ) {
2049  $ret = $this->getFullURL( $query, $query2, $proto );
2050  } elseif ( $this->getPrefixedText() === '' && $this->hasFragment() ) {
2051  $ret = $this->getFragmentForURL();
2052  } else {
2053  $ret = $this->getLocalURL( $query, $query2 ) . $this->getFragmentForURL();
2054  }
2055  return $ret;
2056  }
2057 
2072  public function getInternalURL( $query = '', $query2 = false ) {
2073  global $wgInternalServer, $wgServer;
2074  $query = self::fixUrlQueryArgs( $query, $query2 );
2075  $server = $wgInternalServer !== false ? $wgInternalServer : $wgServer;
2076  $url = wfExpandUrl( $server . $this->getLocalURL( $query ), PROTO_HTTP );
2077  // Avoid PHP 7.1 warning from passing $this by reference
2078  $titleRef = $this;
2079  Hooks::run( 'GetInternalURL', [ &$titleRef, &$url, $query ] );
2080  return $url;
2081  }
2082 
2096  public function getCanonicalURL( $query = '', $query2 = false ) {
2097  $query = self::fixUrlQueryArgs( $query, $query2 );
2098  $url = wfExpandUrl( $this->getLocalURL( $query ) . $this->getFragmentForURL(), PROTO_CANONICAL );
2099  // Avoid PHP 7.1 warning from passing $this by reference
2100  $titleRef = $this;
2101  Hooks::run( 'GetCanonicalURL', [ &$titleRef, &$url, $query ] );
2102  return $url;
2103  }
2104 
2110  public function getEditURL() {
2111  if ( $this->isExternal() ) {
2112  return '';
2113  }
2114  $s = $this->getLocalURL( 'action=edit' );
2115 
2116  return $s;
2117  }
2118 
2139  public function quickUserCan( $action, $user = null ) {
2140  return $this->userCan( $action, $user, false );
2141  }
2142 
2158  public function userCan( $action, $user = null, $rigor = PermissionManager::RIGOR_SECURE ) {
2159  if ( !$user instanceof User ) {
2160  global $wgUser;
2161  $user = $wgUser;
2162  }
2163 
2164  // TODO: this is for b/c, eventually will be removed
2165  if ( $rigor === true ) {
2166  $rigor = PermissionManager::RIGOR_SECURE; // b/c
2167  } elseif ( $rigor === false ) {
2168  $rigor = PermissionManager::RIGOR_QUICK; // b/c
2169  }
2170 
2171  return MediaWikiServices::getInstance()->getPermissionManager()
2172  ->userCan( $action, $user, $this, $rigor );
2173  }
2174 
2196  public function getUserPermissionsErrors(
2197  $action, $user, $rigor = PermissionManager::RIGOR_SECURE, $ignoreErrors = []
2198  ) {
2199  // TODO: this is for b/c, eventually will be removed
2200  if ( $rigor === true ) {
2201  $rigor = PermissionManager::RIGOR_SECURE; // b/c
2202  } elseif ( $rigor === false ) {
2203  $rigor = PermissionManager::RIGOR_QUICK; // b/c
2204  }
2205 
2206  return MediaWikiServices::getInstance()->getPermissionManager()
2207  ->getPermissionErrors( $action, $user, $this, $rigor, $ignoreErrors );
2208  }
2209 
2218  private function resultToError( $errors, $result ) {
2219  if ( is_array( $result ) && count( $result ) && !is_array( $result[0] ) ) {
2220  // A single array representing an error
2221  $errors[] = $result;
2222  } elseif ( is_array( $result ) && is_array( $result[0] ) ) {
2223  // A nested array representing multiple errors
2224  $errors = array_merge( $errors, $result );
2225  } elseif ( $result !== '' && is_string( $result ) ) {
2226  // A string representing a message-id
2227  $errors[] = [ $result ];
2228  } elseif ( $result instanceof MessageSpecifier ) {
2229  // A message specifier representing an error
2230  $errors[] = [ $result ];
2231  } elseif ( $result === false ) {
2232  // a generic "We don't want them to do that"
2233  $errors[] = [ 'badaccess-group0' ];
2234  }
2235  return $errors;
2236  }
2237 
2245  public static function getFilteredRestrictionTypes( $exists = true ) {
2246  global $wgRestrictionTypes;
2247  $types = $wgRestrictionTypes;
2248  if ( $exists ) {
2249  # Remove the create restriction for existing titles
2250  $types = array_diff( $types, [ 'create' ] );
2251  } else {
2252  # Only the create and upload restrictions apply to non-existing titles
2253  $types = array_intersect( $types, [ 'create', 'upload' ] );
2254  }
2255  return $types;
2256  }
2257 
2263  public function getRestrictionTypes() {
2264  if ( $this->isSpecialPage() ) {
2265  return [];
2266  }
2267 
2268  $types = self::getFilteredRestrictionTypes( $this->exists() );
2269 
2270  if ( $this->mNamespace != NS_FILE ) {
2271  # Remove the upload restriction for non-file titles
2272  $types = array_diff( $types, [ 'upload' ] );
2273  }
2274 
2275  Hooks::run( 'TitleGetRestrictionTypes', [ $this, &$types ] );
2276 
2277  wfDebug( __METHOD__ . ': applicable restrictions to [[' .
2278  $this->getPrefixedText() . ']] are {' . implode( ',', $types ) . "}\n" );
2279 
2280  return $types;
2281  }
2282 
2290  public function getTitleProtection() {
2291  $protection = $this->getTitleProtectionInternal();
2292  if ( $protection ) {
2293  if ( $protection['permission'] == 'sysop' ) {
2294  $protection['permission'] = 'editprotected'; // B/C
2295  }
2296  if ( $protection['permission'] == 'autoconfirmed' ) {
2297  $protection['permission'] = 'editsemiprotected'; // B/C
2298  }
2299  }
2300  return $protection;
2301  }
2302 
2313  protected function getTitleProtectionInternal() {
2314  // Can't protect pages in special namespaces
2315  if ( $this->mNamespace < 0 ) {
2316  return false;
2317  }
2318 
2319  // Can't protect pages that exist.
2320  if ( $this->exists() ) {
2321  return false;
2322  }
2323 
2324  if ( $this->mTitleProtection === null ) {
2325  $dbr = wfGetDB( DB_REPLICA );
2326  $commentStore = CommentStore::getStore();
2327  $commentQuery = $commentStore->getJoin( 'pt_reason' );
2328  $res = $dbr->select(
2329  [ 'protected_titles' ] + $commentQuery['tables'],
2330  [
2331  'user' => 'pt_user',
2332  'expiry' => 'pt_expiry',
2333  'permission' => 'pt_create_perm'
2334  ] + $commentQuery['fields'],
2335  [ 'pt_namespace' => $this->mNamespace, 'pt_title' => $this->mDbkeyform ],
2336  __METHOD__,
2337  [],
2338  $commentQuery['joins']
2339  );
2340 
2341  // fetchRow returns false if there are no rows.
2342  $row = $dbr->fetchRow( $res );
2343  if ( $row ) {
2344  $this->mTitleProtection = [
2345  'user' => $row['user'],
2346  'expiry' => $dbr->decodeExpiry( $row['expiry'] ),
2347  'permission' => $row['permission'],
2348  'reason' => $commentStore->getComment( 'pt_reason', $row )->text,
2349  ];
2350  } else {
2351  $this->mTitleProtection = false;
2352  }
2353  }
2354  return $this->mTitleProtection;
2355  }
2356 
2360  public function deleteTitleProtection() {
2361  $dbw = wfGetDB( DB_MASTER );
2362 
2363  $dbw->delete(
2364  'protected_titles',
2365  [ 'pt_namespace' => $this->mNamespace, 'pt_title' => $this->mDbkeyform ],
2366  __METHOD__
2367  );
2368  $this->mTitleProtection = false;
2369  }
2370 
2378  public function isSemiProtected( $action = 'edit' ) {
2380 
2381  $restrictions = $this->getRestrictions( $action );
2383  if ( !$restrictions || !$semi ) {
2384  // Not protected, or all protection is full protection
2385  return false;
2386  }
2387 
2388  // Remap autoconfirmed to editsemiprotected for BC
2389  foreach ( array_keys( $semi, 'autoconfirmed' ) as $key ) {
2390  $semi[$key] = 'editsemiprotected';
2391  }
2392  foreach ( array_keys( $restrictions, 'autoconfirmed' ) as $key ) {
2393  $restrictions[$key] = 'editsemiprotected';
2394  }
2395 
2396  return !array_diff( $restrictions, $semi );
2397  }
2398 
2406  public function isProtected( $action = '' ) {
2407  global $wgRestrictionLevels;
2408 
2409  $restrictionTypes = $this->getRestrictionTypes();
2410 
2411  # Special pages have inherent protection
2412  if ( $this->isSpecialPage() ) {
2413  return true;
2414  }
2415 
2416  # Check regular protection levels
2417  foreach ( $restrictionTypes as $type ) {
2418  if ( $action == $type || $action == '' ) {
2419  $r = $this->getRestrictions( $type );
2420  foreach ( $wgRestrictionLevels as $level ) {
2421  if ( in_array( $level, $r ) && $level != '' ) {
2422  return true;
2423  }
2424  }
2425  }
2426  }
2427 
2428  return false;
2429  }
2430 
2438  public function isNamespaceProtected( User $user ) {
2439  global $wgNamespaceProtection;
2440 
2441  if ( isset( $wgNamespaceProtection[$this->mNamespace] ) ) {
2442  foreach ( (array)$wgNamespaceProtection[$this->mNamespace] as $right ) {
2443  if ( $right != '' && !$user->isAllowed( $right ) ) {
2444  return true;
2445  }
2446  }
2447  }
2448  return false;
2449  }
2450 
2456  public function isCascadeProtected() {
2457  list( $sources, /* $restrictions */ ) = $this->getCascadeProtectionSources( false );
2458  return ( $sources > 0 );
2459  }
2460 
2470  public function areCascadeProtectionSourcesLoaded( $getPages = true ) {
2471  return $getPages ? $this->mCascadeSources !== null : $this->mHasCascadingRestrictions !== null;
2472  }
2473 
2487  public function getCascadeProtectionSources( $getPages = true ) {
2488  $pagerestrictions = [];
2489 
2490  if ( $this->mCascadeSources !== null && $getPages ) {
2492  } elseif ( $this->mHasCascadingRestrictions !== null && !$getPages ) {
2493  return [ $this->mHasCascadingRestrictions, $pagerestrictions ];
2494  }
2495 
2496  $dbr = wfGetDB( DB_REPLICA );
2497 
2498  if ( $this->mNamespace == NS_FILE ) {
2499  $tables = [ 'imagelinks', 'page_restrictions' ];
2500  $where_clauses = [
2501  'il_to' => $this->mDbkeyform,
2502  'il_from=pr_page',
2503  'pr_cascade' => 1
2504  ];
2505  } else {
2506  $tables = [ 'templatelinks', 'page_restrictions' ];
2507  $where_clauses = [
2508  'tl_namespace' => $this->mNamespace,
2509  'tl_title' => $this->mDbkeyform,
2510  'tl_from=pr_page',
2511  'pr_cascade' => 1
2512  ];
2513  }
2514 
2515  if ( $getPages ) {
2516  $cols = [ 'pr_page', 'page_namespace', 'page_title',
2517  'pr_expiry', 'pr_type', 'pr_level' ];
2518  $where_clauses[] = 'page_id=pr_page';
2519  $tables[] = 'page';
2520  } else {
2521  $cols = [ 'pr_expiry' ];
2522  }
2523 
2524  $res = $dbr->select( $tables, $cols, $where_clauses, __METHOD__ );
2525 
2526  $sources = $getPages ? [] : false;
2527  $now = wfTimestampNow();
2528 
2529  foreach ( $res as $row ) {
2530  $expiry = $dbr->decodeExpiry( $row->pr_expiry );
2531  if ( $expiry > $now ) {
2532  if ( $getPages ) {
2533  $page_id = $row->pr_page;
2534  $page_ns = $row->page_namespace;
2535  $page_title = $row->page_title;
2536  $sources[$page_id] = self::makeTitle( $page_ns, $page_title );
2537  # Add groups needed for each restriction type if its not already there
2538  # Make sure this restriction type still exists
2539 
2540  if ( !isset( $pagerestrictions[$row->pr_type] ) ) {
2541  $pagerestrictions[$row->pr_type] = [];
2542  }
2543 
2544  if (
2545  isset( $pagerestrictions[$row->pr_type] )
2546  && !in_array( $row->pr_level, $pagerestrictions[$row->pr_type] )
2547  ) {
2548  $pagerestrictions[$row->pr_type][] = $row->pr_level;
2549  }
2550  } else {
2551  $sources = true;
2552  }
2553  }
2554  }
2555 
2556  if ( $getPages ) {
2557  $this->mCascadeSources = $sources;
2558  $this->mCascadingRestrictions = $pagerestrictions;
2559  } else {
2560  $this->mHasCascadingRestrictions = $sources;
2561  }
2562 
2563  return [ $sources, $pagerestrictions ];
2564  }
2565 
2573  public function areRestrictionsLoaded() {
2575  }
2576 
2586  public function getRestrictions( $action ) {
2587  if ( !$this->mRestrictionsLoaded ) {
2588  $this->loadRestrictions();
2589  }
2590  return $this->mRestrictions[$action] ?? [];
2591  }
2592 
2600  public function getAllRestrictions() {
2601  if ( !$this->mRestrictionsLoaded ) {
2602  $this->loadRestrictions();
2603  }
2604  return $this->mRestrictions;
2605  }
2606 
2614  public function getRestrictionExpiry( $action ) {
2615  if ( !$this->mRestrictionsLoaded ) {
2616  $this->loadRestrictions();
2617  }
2618  return $this->mRestrictionsExpiry[$action] ?? false;
2619  }
2620 
2627  if ( !$this->mRestrictionsLoaded ) {
2628  $this->loadRestrictions();
2629  }
2630 
2632  }
2633 
2645  public function loadRestrictionsFromRows( $rows, $oldFashionedRestrictions = null ) {
2646  // This function will only read rows from a table that we migrated away
2647  // from before adding READ_LATEST support to loadRestrictions, so we
2648  // don't need to support reading from DB_MASTER here.
2649  $dbr = wfGetDB( DB_REPLICA );
2650 
2651  $restrictionTypes = $this->getRestrictionTypes();
2652 
2653  foreach ( $restrictionTypes as $type ) {
2654  $this->mRestrictions[$type] = [];
2655  $this->mRestrictionsExpiry[$type] = 'infinity';
2656  }
2657 
2658  $this->mCascadeRestriction = false;
2659 
2660  # Backwards-compatibility: also load the restrictions from the page record (old format).
2661  if ( $oldFashionedRestrictions !== null ) {
2662  $this->mOldRestrictions = $oldFashionedRestrictions;
2663  }
2664 
2665  if ( $this->mOldRestrictions === false ) {
2666  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
2667  $linkCache->addLinkObj( $this ); # in case we already had an article ID
2668  $this->mOldRestrictions = $linkCache->getGoodLinkFieldObj( $this, 'restrictions' );
2669  }
2670 
2671  if ( $this->mOldRestrictions != '' ) {
2672  foreach ( explode( ':', trim( $this->mOldRestrictions ) ) as $restrict ) {
2673  $temp = explode( '=', trim( $restrict ) );
2674  if ( count( $temp ) == 1 ) {
2675  // old old format should be treated as edit/move restriction
2676  $this->mRestrictions['edit'] = explode( ',', trim( $temp[0] ) );
2677  $this->mRestrictions['move'] = explode( ',', trim( $temp[0] ) );
2678  } else {
2679  $restriction = trim( $temp[1] );
2680  if ( $restriction != '' ) { // some old entries are empty
2681  $this->mRestrictions[$temp[0]] = explode( ',', $restriction );
2682  }
2683  }
2684  }
2685  }
2686 
2687  if ( count( $rows ) ) {
2688  # Current system - load second to make them override.
2689  $now = wfTimestampNow();
2690 
2691  # Cycle through all the restrictions.
2692  foreach ( $rows as $row ) {
2693  // Don't take care of restrictions types that aren't allowed
2694  if ( !in_array( $row->pr_type, $restrictionTypes ) ) {
2695  continue;
2696  }
2697 
2698  $expiry = $dbr->decodeExpiry( $row->pr_expiry );
2699 
2700  // Only apply the restrictions if they haven't expired!
2701  if ( !$expiry || $expiry > $now ) {
2702  $this->mRestrictionsExpiry[$row->pr_type] = $expiry;
2703  $this->mRestrictions[$row->pr_type] = explode( ',', trim( $row->pr_level ) );
2704 
2705  $this->mCascadeRestriction |= $row->pr_cascade;
2706  }
2707  }
2708  }
2709 
2710  $this->mRestrictionsLoaded = true;
2711  }
2712 
2723  public function loadRestrictions( $oldFashionedRestrictions = null, $flags = 0 ) {
2724  $readLatest = DBAccessObjectUtils::hasFlags( $flags, self::READ_LATEST );
2725  if ( $this->mRestrictionsLoaded && !$readLatest ) {
2726  return;
2727  }
2728 
2729  // TODO: should probably pass $flags into getArticleID, but it seems hacky
2730  // to mix READ_LATEST and GAID_FOR_UPDATE, even if they have the same value.
2731  // Maybe deprecate GAID_FOR_UPDATE now that we implement IDBAccessObject?
2732  $id = $this->getArticleID();
2733  if ( $id ) {
2734  $fname = __METHOD__;
2735  $loadRestrictionsFromDb = function ( IDatabase $dbr ) use ( $fname, $id ) {
2736  return iterator_to_array(
2737  $dbr->select(
2738  'page_restrictions',
2739  [ 'pr_type', 'pr_expiry', 'pr_level', 'pr_cascade' ],
2740  [ 'pr_page' => $id ],
2741  $fname
2742  )
2743  );
2744  };
2745 
2746  if ( $readLatest ) {
2747  $dbr = wfGetDB( DB_MASTER );
2748  $rows = $loadRestrictionsFromDb( $dbr );
2749  } else {
2750  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
2751  $rows = $cache->getWithSetCallback(
2752  // Page protections always leave a new null revision
2753  $cache->makeKey( 'page-restrictions', 'v1', $id, $this->getLatestRevID() ),
2754  $cache::TTL_DAY,
2755  function ( $curValue, &$ttl, array &$setOpts ) use ( $loadRestrictionsFromDb ) {
2756  $dbr = wfGetDB( DB_REPLICA );
2757 
2758  $setOpts += Database::getCacheSetOptions( $dbr );
2759  $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
2760  if ( $lb->hasOrMadeRecentMasterChanges() ) {
2761  // @TODO: cleanup Title cache and caller assumption mess in general
2763  }
2764 
2765  return $loadRestrictionsFromDb( $dbr );
2766  }
2767  );
2768  }
2769 
2770  $this->loadRestrictionsFromRows( $rows, $oldFashionedRestrictions );
2771  } else {
2772  $title_protection = $this->getTitleProtectionInternal();
2773 
2774  if ( $title_protection ) {
2775  $now = wfTimestampNow();
2776  $expiry = wfGetDB( DB_REPLICA )->decodeExpiry( $title_protection['expiry'] );
2777 
2778  if ( !$expiry || $expiry > $now ) {
2779  // Apply the restrictions
2780  $this->mRestrictionsExpiry['create'] = $expiry;
2781  $this->mRestrictions['create'] =
2782  explode( ',', trim( $title_protection['permission'] ) );
2783  } else { // Get rid of the old restrictions
2784  $this->mTitleProtection = false;
2785  }
2786  } else {
2787  $this->mRestrictionsExpiry['create'] = 'infinity';
2788  }
2789  $this->mRestrictionsLoaded = true;
2790  }
2791  }
2792 
2797  public function flushRestrictions() {
2798  $this->mRestrictionsLoaded = false;
2799  $this->mTitleProtection = null;
2800  }
2801 
2807  static function purgeExpiredRestrictions() {
2808  if ( wfReadOnly() ) {
2809  return;
2810  }
2811 
2813  wfGetDB( DB_MASTER ),
2814  __METHOD__,
2815  function ( IDatabase $dbw, $fname ) {
2816  $config = MediaWikiServices::getInstance()->getMainConfig();
2817  $ids = $dbw->selectFieldValues(
2818  'page_restrictions',
2819  'pr_id',
2820  [ 'pr_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ],
2821  $fname,
2822  [ 'LIMIT' => $config->get( 'UpdateRowsPerQuery' ) ] // T135470
2823  );
2824  if ( $ids ) {
2825  $dbw->delete( 'page_restrictions', [ 'pr_id' => $ids ], $fname );
2826  }
2827  }
2828  ) );
2829 
2831  wfGetDB( DB_MASTER ),
2832  __METHOD__,
2833  function ( IDatabase $dbw, $fname ) {
2834  $dbw->delete(
2835  'protected_titles',
2836  [ 'pt_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ],
2837  $fname
2838  );
2839  }
2840  ) );
2841  }
2842 
2848  public function hasSubpages() {
2849  if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
2850  # Duh
2851  return false;
2852  }
2853 
2854  # We dynamically add a member variable for the purpose of this method
2855  # alone to cache the result. There's no point in having it hanging
2856  # around uninitialized in every Title object; therefore we only add it
2857  # if needed and don't declare it statically.
2858  if ( $this->mHasSubpages === null ) {
2859  $this->mHasSubpages = false;
2860  $subpages = $this->getSubpages( 1 );
2861  if ( $subpages instanceof TitleArray ) {
2862  $this->mHasSubpages = (bool)$subpages->count();
2863  }
2864  }
2865 
2866  return $this->mHasSubpages;
2867  }
2868 
2876  public function getSubpages( $limit = -1 ) {
2877  if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
2878  return [];
2879  }
2880 
2881  $dbr = wfGetDB( DB_REPLICA );
2882  $conds['page_namespace'] = $this->mNamespace;
2883  $conds[] = 'page_title ' . $dbr->buildLike( $this->mDbkeyform . '/', $dbr->anyString() );
2884  $options = [];
2885  if ( $limit > -1 ) {
2886  $options['LIMIT'] = $limit;
2887  }
2889  $dbr->select( 'page',
2890  [ 'page_id', 'page_namespace', 'page_title', 'page_is_redirect' ],
2891  $conds,
2892  __METHOD__,
2893  $options
2894  )
2895  );
2896  }
2897 
2903  public function isDeleted() {
2904  if ( $this->mNamespace < 0 ) {
2905  $n = 0;
2906  } else {
2907  $dbr = wfGetDB( DB_REPLICA );
2908 
2909  $n = $dbr->selectField( 'archive', 'COUNT(*)',
2910  [ 'ar_namespace' => $this->mNamespace, 'ar_title' => $this->mDbkeyform ],
2911  __METHOD__
2912  );
2913  if ( $this->mNamespace == NS_FILE ) {
2914  $n += $dbr->selectField( 'filearchive', 'COUNT(*)',
2915  [ 'fa_name' => $this->mDbkeyform ],
2916  __METHOD__
2917  );
2918  }
2919  }
2920  return (int)$n;
2921  }
2922 
2928  public function isDeletedQuick() {
2929  if ( $this->mNamespace < 0 ) {
2930  return false;
2931  }
2932  $dbr = wfGetDB( DB_REPLICA );
2933  $deleted = (bool)$dbr->selectField( 'archive', '1',
2934  [ 'ar_namespace' => $this->mNamespace, 'ar_title' => $this->mDbkeyform ],
2935  __METHOD__
2936  );
2937  if ( !$deleted && $this->mNamespace == NS_FILE ) {
2938  $deleted = (bool)$dbr->selectField( 'filearchive', '1',
2939  [ 'fa_name' => $this->mDbkeyform ],
2940  __METHOD__
2941  );
2942  }
2943  return $deleted;
2944  }
2945 
2954  public function getArticleID( $flags = 0 ) {
2955  if ( $this->mNamespace < 0 ) {
2956  $this->mArticleID = 0;
2957  return $this->mArticleID;
2958  }
2959  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
2960  if ( $flags & self::GAID_FOR_UPDATE ) {
2961  $oldUpdate = $linkCache->forUpdate( true );
2962  $linkCache->clearLink( $this );
2963  $this->mArticleID = $linkCache->addLinkObj( $this );
2964  $linkCache->forUpdate( $oldUpdate );
2965  } elseif ( $this->mArticleID == -1 ) {
2966  $this->mArticleID = $linkCache->addLinkObj( $this );
2967  }
2968  return $this->mArticleID;
2969  }
2970 
2978  public function isRedirect( $flags = 0 ) {
2979  if ( !is_null( $this->mRedirect ) ) {
2980  return $this->mRedirect;
2981  }
2982  if ( !$this->getArticleID( $flags ) ) {
2983  $this->mRedirect = false;
2984  return $this->mRedirect;
2985  }
2986 
2987  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
2988  $linkCache->addLinkObj( $this ); # in case we already had an article ID
2989  $cached = $linkCache->getGoodLinkFieldObj( $this, 'redirect' );
2990  if ( $cached === null ) {
2991  # Trust LinkCache's state over our own
2992  # LinkCache is telling us that the page doesn't exist, despite there being cached
2993  # data relating to an existing page in $this->mArticleID. Updaters should clear
2994  # LinkCache as appropriate, or use $flags = Title::GAID_FOR_UPDATE. If that flag is
2995  # set, then LinkCache will definitely be up to date here, since getArticleID() forces
2996  # LinkCache to refresh its data from the master.
2997  $this->mRedirect = false;
2998  return $this->mRedirect;
2999  }
3000 
3001  $this->mRedirect = (bool)$cached;
3002 
3003  return $this->mRedirect;
3004  }
3005 
3013  public function getLength( $flags = 0 ) {
3014  if ( $this->mLength != -1 ) {
3015  return $this->mLength;
3016  }
3017  if ( !$this->getArticleID( $flags ) ) {
3018  $this->mLength = 0;
3019  return $this->mLength;
3020  }
3021  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3022  $linkCache->addLinkObj( $this ); # in case we already had an article ID
3023  $cached = $linkCache->getGoodLinkFieldObj( $this, 'length' );
3024  if ( $cached === null ) {
3025  # Trust LinkCache's state over our own, as for isRedirect()
3026  $this->mLength = 0;
3027  return $this->mLength;
3028  }
3029 
3030  $this->mLength = intval( $cached );
3031 
3032  return $this->mLength;
3033  }
3034 
3041  public function getLatestRevID( $flags = 0 ) {
3042  if ( !( $flags & self::GAID_FOR_UPDATE ) && $this->mLatestID !== false ) {
3043  return intval( $this->mLatestID );
3044  }
3045  if ( !$this->getArticleID( $flags ) ) {
3046  $this->mLatestID = 0;
3047  return $this->mLatestID;
3048  }
3049  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3050  $linkCache->addLinkObj( $this ); # in case we already had an article ID
3051  $cached = $linkCache->getGoodLinkFieldObj( $this, 'revision' );
3052  if ( $cached === null ) {
3053  # Trust LinkCache's state over our own, as for isRedirect()
3054  $this->mLatestID = 0;
3055  return $this->mLatestID;
3056  }
3057 
3058  $this->mLatestID = intval( $cached );
3059 
3060  return $this->mLatestID;
3061  }
3062 
3073  public function resetArticleID( $newid ) {
3074  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3075  $linkCache->clearLink( $this );
3076 
3077  if ( $newid === false ) {
3078  $this->mArticleID = -1;
3079  } else {
3080  $this->mArticleID = intval( $newid );
3081  }
3082  $this->mRestrictionsLoaded = false;
3083  $this->mRestrictions = [];
3084  $this->mOldRestrictions = false;
3085  $this->mRedirect = null;
3086  $this->mLength = -1;
3087  $this->mLatestID = false;
3088  $this->mContentModel = false;
3089  $this->mEstimateRevisions = null;
3090  $this->mPageLanguage = false;
3091  $this->mDbPageLanguage = false;
3092  $this->mIsBigDeletion = null;
3093  }
3094 
3095  public static function clearCaches() {
3096  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3097  $linkCache->clear();
3098 
3100  $titleCache->clear();
3101  }
3102 
3110  public static function capitalize( $text, $ns = NS_MAIN ) {
3111  if ( MWNamespace::isCapitalized( $ns ) ) {
3112  return MediaWikiServices::getInstance()->getContentLanguage()->ucfirst( $text );
3113  } else {
3114  return $text;
3115  }
3116  }
3117 
3130  private function secureAndSplit() {
3131  // @note: splitTitleString() is a temporary hack to allow MediaWikiTitleCodec to share
3132  // the parsing code with Title, while avoiding massive refactoring.
3133  // @todo: get rid of secureAndSplit, refactor parsing code.
3134  // @note: getTitleParser() returns a TitleParser implementation which does not have a
3135  // splitTitleString method, but the only implementation (MediaWikiTitleCodec) does
3137  $titleCodec = MediaWikiServices::getInstance()->getTitleParser();
3138  // MalformedTitleException can be thrown here
3139  $parts = $titleCodec->splitTitleString( $this->mDbkeyform, $this->mDefaultNamespace );
3140 
3141  # Fill fields
3142  $this->setFragment( '#' . $parts['fragment'] );
3143  $this->mInterwiki = $parts['interwiki'];
3144  $this->mLocalInterwiki = $parts['local_interwiki'];
3145  $this->mNamespace = $parts['namespace'];
3146  $this->mUserCaseDBKey = $parts['user_case_dbkey'];
3147 
3148  $this->mDbkeyform = $parts['dbkey'];
3149  $this->mUrlform = wfUrlencode( $this->mDbkeyform );
3150  $this->mTextform = strtr( $this->mDbkeyform, '_', ' ' );
3151 
3152  # We already know that some pages won't be in the database!
3153  if ( $this->isExternal() || $this->isSpecialPage() ) {
3154  $this->mArticleID = 0;
3155  }
3156 
3157  return true;
3158  }
3159 
3172  public function getLinksTo( $options = [], $table = 'pagelinks', $prefix = 'pl' ) {
3173  if ( count( $options ) > 0 ) {
3174  $db = wfGetDB( DB_MASTER );
3175  } else {
3176  $db = wfGetDB( DB_REPLICA );
3177  }
3178 
3179  $res = $db->select(
3180  [ 'page', $table ],
3181  self::getSelectFields(),
3182  [
3183  "{$prefix}_from=page_id",
3184  "{$prefix}_namespace" => $this->mNamespace,
3185  "{$prefix}_title" => $this->mDbkeyform ],
3186  __METHOD__,
3187  $options
3188  );
3189 
3190  $retVal = [];
3191  if ( $res->numRows() ) {
3192  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3193  foreach ( $res as $row ) {
3194  $titleObj = self::makeTitle( $row->page_namespace, $row->page_title );
3195  if ( $titleObj ) {
3196  $linkCache->addGoodLinkObjFromRow( $titleObj, $row );
3197  $retVal[] = $titleObj;
3198  }
3199  }
3200  }
3201  return $retVal;
3202  }
3203 
3214  public function getTemplateLinksTo( $options = [] ) {
3215  return $this->getLinksTo( $options, 'templatelinks', 'tl' );
3216  }
3217 
3230  public function getLinksFrom( $options = [], $table = 'pagelinks', $prefix = 'pl' ) {
3231  $id = $this->getArticleID();
3232 
3233  # If the page doesn't exist; there can't be any link from this page
3234  if ( !$id ) {
3235  return [];
3236  }
3237 
3238  $db = wfGetDB( DB_REPLICA );
3239 
3240  $blNamespace = "{$prefix}_namespace";
3241  $blTitle = "{$prefix}_title";
3242 
3243  $pageQuery = WikiPage::getQueryInfo();
3244  $res = $db->select(
3245  [ $table, 'nestpage' => $pageQuery['tables'] ],
3246  array_merge(
3247  [ $blNamespace, $blTitle ],
3248  $pageQuery['fields']
3249  ),
3250  [ "{$prefix}_from" => $id ],
3251  __METHOD__,
3252  $options,
3253  [ 'nestpage' => [
3254  'LEFT JOIN',
3255  [ "page_namespace=$blNamespace", "page_title=$blTitle" ]
3256  ] ] + $pageQuery['joins']
3257  );
3258 
3259  $retVal = [];
3260  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3261  foreach ( $res as $row ) {
3262  if ( $row->page_id ) {
3263  $titleObj = self::newFromRow( $row );
3264  } else {
3265  $titleObj = self::makeTitle( $row->$blNamespace, $row->$blTitle );
3266  $linkCache->addBadLinkObj( $titleObj );
3267  }
3268  $retVal[] = $titleObj;
3269  }
3270 
3271  return $retVal;
3272  }
3273 
3284  public function getTemplateLinksFrom( $options = [] ) {
3285  return $this->getLinksFrom( $options, 'templatelinks', 'tl' );
3286  }
3287 
3296  public function getBrokenLinksFrom() {
3297  if ( $this->getArticleID() == 0 ) {
3298  # All links from article ID 0 are false positives
3299  return [];
3300  }
3301 
3302  $dbr = wfGetDB( DB_REPLICA );
3303  $res = $dbr->select(
3304  [ 'page', 'pagelinks' ],
3305  [ 'pl_namespace', 'pl_title' ],
3306  [
3307  'pl_from' => $this->getArticleID(),
3308  'page_namespace IS NULL'
3309  ],
3310  __METHOD__, [],
3311  [
3312  'page' => [
3313  'LEFT JOIN',
3314  [ 'pl_namespace=page_namespace', 'pl_title=page_title' ]
3315  ]
3316  ]
3317  );
3318 
3319  $retVal = [];
3320  foreach ( $res as $row ) {
3321  $retVal[] = self::makeTitle( $row->pl_namespace, $row->pl_title );
3322  }
3323  return $retVal;
3324  }
3325 
3332  public function getCdnUrls() {
3333  $urls = [
3334  $this->getInternalURL(),
3335  $this->getInternalURL( 'action=history' )
3336  ];
3337 
3338  $pageLang = $this->getPageLanguage();
3339  if ( $pageLang->hasVariants() ) {
3340  $variants = $pageLang->getVariants();
3341  foreach ( $variants as $vCode ) {
3342  $urls[] = $this->getInternalURL( $vCode );
3343  }
3344  }
3345 
3346  // If we are looking at a css/js user subpage, purge the action=raw.
3347  if ( $this->isUserJsConfigPage() ) {
3348  $urls[] = $this->getInternalURL( 'action=raw&ctype=text/javascript' );
3349  } elseif ( $this->isUserJsonConfigPage() ) {
3350  $urls[] = $this->getInternalURL( 'action=raw&ctype=application/json' );
3351  } elseif ( $this->isUserCssConfigPage() ) {
3352  $urls[] = $this->getInternalURL( 'action=raw&ctype=text/css' );
3353  }
3354 
3355  Hooks::run( 'TitleSquidURLs', [ $this, &$urls ] );
3356  return $urls;
3357  }
3358 
3362  public function purgeSquid() {
3364  new CdnCacheUpdate( $this->getCdnUrls() ),
3366  );
3367  }
3368 
3379  public function isValidMoveOperation( &$nt, $auth = true, $reason = '' ) {
3380  global $wgUser;
3381 
3382  if ( !( $nt instanceof Title ) ) {
3383  // Normally we'd add this to $errors, but we'll get
3384  // lots of syntax errors if $nt is not an object
3385  return [ [ 'badtitletext' ] ];
3386  }
3387 
3388  $mp = new MovePage( $this, $nt );
3389  $errors = $mp->isValidMove()->getErrorsArray();
3390  if ( $auth ) {
3391  $errors = wfMergeErrorArrays(
3392  $errors,
3393  $mp->checkPermissions( $wgUser, $reason )->getErrorsArray()
3394  );
3395  }
3396 
3397  return $errors ?: true;
3398  }
3399 
3413  public function moveTo( &$nt, $auth = true, $reason = '', $createRedirect = true,
3414  array $changeTags = []
3415  ) {
3416  global $wgUser;
3417  $err = $this->isValidMoveOperation( $nt, $auth, $reason );
3418  if ( is_array( $err ) ) {
3419  // Auto-block user's IP if the account was "hard" blocked
3420  $wgUser->spreadAnyEditBlock();
3421  return $err;
3422  }
3423  // Check suppressredirect permission
3424  if ( $auth && !$wgUser->isAllowed( 'suppressredirect' ) ) {
3425  $createRedirect = true;
3426  }
3427 
3428  $mp = new MovePage( $this, $nt );
3429  $status = $mp->move( $wgUser, $reason, $createRedirect, $changeTags );
3430  if ( $status->isOK() ) {
3431  return true;
3432  } else {
3433  return $status->getErrorsArray();
3434  }
3435  }
3436 
3451  public function moveSubpages( $nt, $auth = true, $reason = '', $createRedirect = true,
3452  array $changeTags = []
3453  ) {
3454  global $wgMaximumMovedPages;
3455  // Check permissions
3456  if ( !$this->userCan( 'move-subpages' ) ) {
3457  return [
3458  [ 'cant-move-subpages' ],
3459  ];
3460  }
3461  // Do the source and target namespaces support subpages?
3462  if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
3463  return [
3464  [ 'namespace-nosubpages', MWNamespace::getCanonicalName( $this->mNamespace ) ],
3465  ];
3466  }
3467  if ( !MWNamespace::hasSubpages( $nt->getNamespace() ) ) {
3468  return [
3469  [ 'namespace-nosubpages', MWNamespace::getCanonicalName( $nt->getNamespace() ) ],
3470  ];
3471  }
3472 
3473  $subpages = $this->getSubpages( $wgMaximumMovedPages + 1 );
3474  $retval = [];
3475  $count = 0;
3476  foreach ( $subpages as $oldSubpage ) {
3477  $count++;
3478  if ( $count > $wgMaximumMovedPages ) {
3479  $retval[$oldSubpage->getPrefixedText()] = [
3480  [ 'movepage-max-pages', $wgMaximumMovedPages ],
3481  ];
3482  break;
3483  }
3484 
3485  // We don't know whether this function was called before
3486  // or after moving the root page, so check both
3487  // $this and $nt
3488  if ( $oldSubpage->getArticleID() == $this->getArticleID()
3489  || $oldSubpage->getArticleID() == $nt->getArticleID()
3490  ) {
3491  // When moving a page to a subpage of itself,
3492  // don't move it twice
3493  continue;
3494  }
3495  $newPageName = preg_replace(
3496  '#^' . preg_quote( $this->mDbkeyform, '#' ) . '#',
3497  StringUtils::escapeRegexReplacement( $nt->getDBkey() ), # T23234
3498  $oldSubpage->getDBkey() );
3499  if ( $oldSubpage->isTalkPage() ) {
3500  $newNs = $nt->getTalkPage()->getNamespace();
3501  } else {
3502  $newNs = $nt->getSubjectPage()->getNamespace();
3503  }
3504  # T16385: we need makeTitleSafe because the new page names may
3505  # be longer than 255 characters.
3506  $newSubpage = self::makeTitleSafe( $newNs, $newPageName );
3507 
3508  $success = $oldSubpage->moveTo( $newSubpage, $auth, $reason, $createRedirect, $changeTags );
3509  if ( $success === true ) {
3510  $retval[$oldSubpage->getPrefixedText()] = $newSubpage->getPrefixedText();
3511  } else {
3512  $retval[$oldSubpage->getPrefixedText()] = $success;
3513  }
3514  }
3515  return $retval;
3516  }
3517 
3524  public function isSingleRevRedirect() {
3525  global $wgContentHandlerUseDB;
3526 
3527  $dbw = wfGetDB( DB_MASTER );
3528 
3529  # Is it a redirect?
3530  $fields = [ 'page_is_redirect', 'page_latest', 'page_id' ];
3531  if ( $wgContentHandlerUseDB ) {
3532  $fields[] = 'page_content_model';
3533  }
3534 
3535  $row = $dbw->selectRow( 'page',
3536  $fields,
3537  $this->pageCond(),
3538  __METHOD__,
3539  [ 'FOR UPDATE' ]
3540  );
3541  # Cache some fields we may want
3542  $this->mArticleID = $row ? intval( $row->page_id ) : 0;
3543  $this->mRedirect = $row ? (bool)$row->page_is_redirect : false;
3544  $this->mLatestID = $row ? intval( $row->page_latest ) : false;
3545  $this->mContentModel = $row && isset( $row->page_content_model )
3546  ? strval( $row->page_content_model )
3547  : false;
3548 
3549  if ( !$this->mRedirect ) {
3550  return false;
3551  }
3552  # Does the article have a history?
3553  $row = $dbw->selectField( [ 'page', 'revision' ],
3554  'rev_id',
3555  [ 'page_namespace' => $this->mNamespace,
3556  'page_title' => $this->mDbkeyform,
3557  'page_id=rev_page',
3558  'page_latest != rev_id'
3559  ],
3560  __METHOD__,
3561  [ 'FOR UPDATE' ]
3562  );
3563  # Return true if there was no history
3564  return ( $row === false );
3565  }
3566 
3575  public function isValidMoveTarget( $nt ) {
3576  # Is it an existing file?
3577  if ( $nt->getNamespace() == NS_FILE ) {
3578  $file = wfLocalFile( $nt );
3579  $file->load( File::READ_LATEST );
3580  if ( $file->exists() ) {
3581  wfDebug( __METHOD__ . ": file exists\n" );
3582  return false;
3583  }
3584  }
3585  # Is it a redirect with no history?
3586  if ( !$nt->isSingleRevRedirect() ) {
3587  wfDebug( __METHOD__ . ": not a one-rev redirect\n" );
3588  return false;
3589  }
3590  # Get the article text
3591  $rev = Revision::newFromTitle( $nt, false, Revision::READ_LATEST );
3592  if ( !is_object( $rev ) ) {
3593  return false;
3594  }
3595  $content = $rev->getContent();
3596  # Does the redirect point to the source?
3597  # Or is it a broken self-redirect, usually caused by namespace collisions?
3598  $redirTitle = $content ? $content->getRedirectTarget() : null;
3599 
3600  if ( $redirTitle ) {
3601  if ( $redirTitle->getPrefixedDBkey() != $this->getPrefixedDBkey() &&
3602  $redirTitle->getPrefixedDBkey() != $nt->getPrefixedDBkey() ) {
3603  wfDebug( __METHOD__ . ": redirect points to other page\n" );
3604  return false;
3605  } else {
3606  return true;
3607  }
3608  } else {
3609  # Fail safe (not a redirect after all. strange.)
3610  wfDebug( __METHOD__ . ": failsafe: database sais " . $nt->getPrefixedDBkey() .
3611  " is a redirect, but it doesn't contain a valid redirect.\n" );
3612  return false;
3613  }
3614  }
3615 
3623  public function getParentCategories() {
3624  $data = [];
3625 
3626  $titleKey = $this->getArticleID();
3627 
3628  if ( $titleKey === 0 ) {
3629  return $data;
3630  }
3631 
3632  $dbr = wfGetDB( DB_REPLICA );
3633 
3634  $res = $dbr->select(
3635  'categorylinks',
3636  'cl_to',
3637  [ 'cl_from' => $titleKey ],
3638  __METHOD__
3639  );
3640 
3641  if ( $res->numRows() > 0 ) {
3642  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
3643  foreach ( $res as $row ) {
3644  // $data[] = Title::newFromText( $contLang->getNsText ( NS_CATEGORY ).':'.$row->cl_to);
3645  $data[$contLang->getNsText( NS_CATEGORY ) . ':' . $row->cl_to] =
3646  $this->getFullText();
3647  }
3648  }
3649  return $data;
3650  }
3651 
3658  public function getParentCategoryTree( $children = [] ) {
3659  $stack = [];
3660  $parents = $this->getParentCategories();
3661 
3662  if ( $parents ) {
3663  foreach ( $parents as $parent => $current ) {
3664  if ( array_key_exists( $parent, $children ) ) {
3665  # Circular reference
3666  $stack[$parent] = [];
3667  } else {
3668  $nt = self::newFromText( $parent );
3669  if ( $nt ) {
3670  $stack[$parent] = $nt->getParentCategoryTree( $children + [ $parent => 1 ] );
3671  }
3672  }
3673  }
3674  }
3675 
3676  return $stack;
3677  }
3678 
3685  public function pageCond() {
3686  if ( $this->mArticleID > 0 ) {
3687  // PK avoids secondary lookups in InnoDB, shouldn't hurt other DBs
3688  return [ 'page_id' => $this->mArticleID ];
3689  } else {
3690  return [ 'page_namespace' => $this->mNamespace, 'page_title' => $this->mDbkeyform ];
3691  }
3692  }
3693 
3701  private function getRelativeRevisionID( $revId, $flags, $dir ) {
3702  $revId = (int)$revId;
3703  if ( $dir === 'next' ) {
3704  $op = '>';
3705  $sort = 'ASC';
3706  } elseif ( $dir === 'prev' ) {
3707  $op = '<';
3708  $sort = 'DESC';
3709  } else {
3710  throw new InvalidArgumentException( '$dir must be "next" or "prev"' );
3711  }
3712 
3713  if ( $flags & self::GAID_FOR_UPDATE ) {
3714  $db = wfGetDB( DB_MASTER );
3715  } else {
3716  $db = wfGetDB( DB_REPLICA, 'contributions' );
3717  }
3718 
3719  // Intentionally not caring if the specified revision belongs to this
3720  // page. We only care about the timestamp.
3721  $ts = $db->selectField( 'revision', 'rev_timestamp', [ 'rev_id' => $revId ], __METHOD__ );
3722  if ( $ts === false ) {
3723  $ts = $db->selectField( 'archive', 'ar_timestamp', [ 'ar_rev_id' => $revId ], __METHOD__ );
3724  if ( $ts === false ) {
3725  // Or should this throw an InvalidArgumentException or something?
3726  return false;
3727  }
3728  }
3729  $ts = $db->addQuotes( $ts );
3730 
3731  $revId = $db->selectField( 'revision', 'rev_id',
3732  [
3733  'rev_page' => $this->getArticleID( $flags ),
3734  "rev_timestamp $op $ts OR (rev_timestamp = $ts AND rev_id $op $revId)"
3735  ],
3736  __METHOD__,
3737  [
3738  'ORDER BY' => "rev_timestamp $sort, rev_id $sort",
3739  'IGNORE INDEX' => 'rev_timestamp', // Probably needed for T159319
3740  ]
3741  );
3742 
3743  if ( $revId === false ) {
3744  return false;
3745  } else {
3746  return intval( $revId );
3747  }
3748  }
3749 
3757  public function getPreviousRevisionID( $revId, $flags = 0 ) {
3758  return $this->getRelativeRevisionID( $revId, $flags, 'prev' );
3759  }
3760 
3768  public function getNextRevisionID( $revId, $flags = 0 ) {
3769  return $this->getRelativeRevisionID( $revId, $flags, 'next' );
3770  }
3771 
3778  public function getFirstRevision( $flags = 0 ) {
3779  $pageId = $this->getArticleID( $flags );
3780  if ( $pageId ) {
3781  $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
3783  $row = $db->selectRow( $revQuery['tables'], $revQuery['fields'],
3784  [ 'rev_page' => $pageId ],
3785  __METHOD__,
3786  [
3787  'ORDER BY' => 'rev_timestamp ASC, rev_id ASC',
3788  'IGNORE INDEX' => [ 'revision' => 'rev_timestamp' ], // See T159319
3789  ],
3790  $revQuery['joins']
3791  );
3792  if ( $row ) {
3793  return new Revision( $row, 0, $this );
3794  }
3795  }
3796  return null;
3797  }
3798 
3805  public function getEarliestRevTime( $flags = 0 ) {
3806  $rev = $this->getFirstRevision( $flags );
3807  return $rev ? $rev->getTimestamp() : null;
3808  }
3809 
3815  public function isNewPage() {
3816  $dbr = wfGetDB( DB_REPLICA );
3817  return (bool)$dbr->selectField( 'page', 'page_is_new', $this->pageCond(), __METHOD__ );
3818  }
3819 
3825  public function isBigDeletion() {
3826  global $wgDeleteRevisionsLimit;
3827 
3828  if ( !$wgDeleteRevisionsLimit ) {
3829  return false;
3830  }
3831 
3832  if ( $this->mIsBigDeletion === null ) {
3833  $dbr = wfGetDB( DB_REPLICA );
3834 
3835  $revCount = $dbr->selectRowCount(
3836  'revision',
3837  '1',
3838  [ 'rev_page' => $this->getArticleID() ],
3839  __METHOD__,
3840  [ 'LIMIT' => $wgDeleteRevisionsLimit + 1 ]
3841  );
3842 
3843  $this->mIsBigDeletion = $revCount > $wgDeleteRevisionsLimit;
3844  }
3845 
3846  return $this->mIsBigDeletion;
3847  }
3848 
3854  public function estimateRevisionCount() {
3855  if ( !$this->exists() ) {
3856  return 0;
3857  }
3858 
3859  if ( $this->mEstimateRevisions === null ) {
3860  $dbr = wfGetDB( DB_REPLICA );
3861  $this->mEstimateRevisions = $dbr->estimateRowCount( 'revision', '*',
3862  [ 'rev_page' => $this->getArticleID() ], __METHOD__ );
3863  }
3864 
3866  }
3867 
3877  public function countRevisionsBetween( $old, $new, $max = null ) {
3878  if ( !( $old instanceof Revision ) ) {
3879  $old = Revision::newFromTitle( $this, (int)$old );
3880  }
3881  if ( !( $new instanceof Revision ) ) {
3882  $new = Revision::newFromTitle( $this, (int)$new );
3883  }
3884  if ( !$old || !$new ) {
3885  return 0; // nothing to compare
3886  }
3887  $dbr = wfGetDB( DB_REPLICA );
3888  $conds = [
3889  'rev_page' => $this->getArticleID(),
3890  'rev_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( $old->getTimestamp() ) ),
3891  'rev_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $new->getTimestamp() ) )
3892  ];
3893  if ( $max !== null ) {
3894  return $dbr->selectRowCount( 'revision', '1',
3895  $conds,
3896  __METHOD__,
3897  [ 'LIMIT' => $max + 1 ] // extra to detect truncation
3898  );
3899  } else {
3900  return (int)$dbr->selectField( 'revision', 'count(*)', $conds, __METHOD__ );
3901  }
3902  }
3903 
3920  public function getAuthorsBetween( $old, $new, $limit, $options = [] ) {
3921  if ( !( $old instanceof Revision ) ) {
3922  $old = Revision::newFromTitle( $this, (int)$old );
3923  }
3924  if ( !( $new instanceof Revision ) ) {
3925  $new = Revision::newFromTitle( $this, (int)$new );
3926  }
3927  // XXX: what if Revision objects are passed in, but they don't refer to this title?
3928  // Add $old->getPage() != $new->getPage() || $old->getPage() != $this->getArticleID()
3929  // in the sanity check below?
3930  if ( !$old || !$new ) {
3931  return null; // nothing to compare
3932  }
3933  $authors = [];
3934  $old_cmp = '>';
3935  $new_cmp = '<';
3936  $options = (array)$options;
3937  if ( in_array( 'include_old', $options ) ) {
3938  $old_cmp = '>=';
3939  }
3940  if ( in_array( 'include_new', $options ) ) {
3941  $new_cmp = '<=';
3942  }
3943  if ( in_array( 'include_both', $options ) ) {
3944  $old_cmp = '>=';
3945  $new_cmp = '<=';
3946  }
3947  // No DB query needed if $old and $new are the same or successive revisions:
3948  if ( $old->getId() === $new->getId() ) {
3949  return ( $old_cmp === '>' && $new_cmp === '<' ) ?
3950  [] :
3951  [ $old->getUserText( Revision::RAW ) ];
3952  } elseif ( $old->getId() === $new->getParentId() ) {
3953  if ( $old_cmp === '>=' && $new_cmp === '<=' ) {
3954  $authors[] = $old->getUserText( Revision::RAW );
3955  if ( $old->getUserText( Revision::RAW ) != $new->getUserText( Revision::RAW ) ) {
3956  $authors[] = $new->getUserText( Revision::RAW );
3957  }
3958  } elseif ( $old_cmp === '>=' ) {
3959  $authors[] = $old->getUserText( Revision::RAW );
3960  } elseif ( $new_cmp === '<=' ) {
3961  $authors[] = $new->getUserText( Revision::RAW );
3962  }
3963  return $authors;
3964  }
3965  $dbr = wfGetDB( DB_REPLICA );
3967  $authors = $dbr->selectFieldValues(
3968  $revQuery['tables'],
3969  $revQuery['fields']['rev_user_text'],
3970  [
3971  'rev_page' => $this->getArticleID(),
3972  "rev_timestamp $old_cmp " . $dbr->addQuotes( $dbr->timestamp( $old->getTimestamp() ) ),
3973  "rev_timestamp $new_cmp " . $dbr->addQuotes( $dbr->timestamp( $new->getTimestamp() ) )
3974  ], __METHOD__,
3975  [ 'DISTINCT', 'LIMIT' => $limit + 1 ], // add one so caller knows it was truncated
3976  $revQuery['joins']
3977  );
3978  return $authors;
3979  }
3980 
3995  public function countAuthorsBetween( $old, $new, $limit, $options = [] ) {
3996  $authors = $this->getAuthorsBetween( $old, $new, $limit, $options );
3997  return $authors ? count( $authors ) : 0;
3998  }
3999 
4006  public function equals( Title $title ) {
4007  // Note: === is necessary for proper matching of number-like titles.
4008  return $this->mInterwiki === $title->mInterwiki
4009  && $this->mNamespace == $title->mNamespace
4010  && $this->mDbkeyform === $title->mDbkeyform;
4011  }
4012 
4019  public function isSubpageOf( Title $title ) {
4020  return $this->mInterwiki === $title->mInterwiki
4021  && $this->mNamespace == $title->mNamespace
4022  && strpos( $this->mDbkeyform, $title->mDbkeyform . '/' ) === 0;
4023  }
4024 
4036  public function exists( $flags = 0 ) {
4037  $exists = $this->getArticleID( $flags ) != 0;
4038  Hooks::run( 'TitleExists', [ $this, &$exists ] );
4039  return $exists;
4040  }
4041 
4058  public function isAlwaysKnown() {
4059  $isKnown = null;
4060 
4071  Hooks::run( 'TitleIsAlwaysKnown', [ $this, &$isKnown ] );
4072 
4073  if ( !is_null( $isKnown ) ) {
4074  return $isKnown;
4075  }
4076 
4077  if ( $this->isExternal() ) {
4078  return true; // any interwiki link might be viewable, for all we know
4079  }
4080 
4081  switch ( $this->mNamespace ) {
4082  case NS_MEDIA:
4083  case NS_FILE:
4084  // file exists, possibly in a foreign repo
4085  return (bool)wfFindFile( $this );
4086  case NS_SPECIAL:
4087  // valid special page
4088  return MediaWikiServices::getInstance()->getSpecialPageFactory()->
4089  exists( $this->mDbkeyform );
4090  case NS_MAIN:
4091  // selflink, possibly with fragment
4092  return $this->mDbkeyform == '';
4093  case NS_MEDIAWIKI:
4094  // known system message
4095  return $this->hasSourceText() !== false;
4096  default:
4097  return false;
4098  }
4099  }
4100 
4112  public function isKnown() {
4113  return $this->isAlwaysKnown() || $this->exists();
4114  }
4115 
4121  public function hasSourceText() {
4122  if ( $this->exists() ) {
4123  return true;
4124  }
4125 
4126  if ( $this->mNamespace == NS_MEDIAWIKI ) {
4127  // If the page doesn't exist but is a known system message, default
4128  // message content will be displayed, same for language subpages-
4129  // Use always content language to avoid loading hundreds of languages
4130  // to get the link color.
4131  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
4132  list( $name, ) = MessageCache::singleton()->figureMessage(
4133  $contLang->lcfirst( $this->getText() )
4134  );
4135  $message = wfMessage( $name )->inLanguage( $contLang )->useDatabase( false );
4136  return $message->exists();
4137  }
4138 
4139  return false;
4140  }
4141 
4179  public function getDefaultMessageText() {
4180  if ( $this->mNamespace != NS_MEDIAWIKI ) { // Just in case
4181  return false;
4182  }
4183 
4184  list( $name, $lang ) = MessageCache::singleton()->figureMessage(
4185  MediaWikiServices::getInstance()->getContentLanguage()->lcfirst( $this->getText() )
4186  );
4187  $message = wfMessage( $name )->inLanguage( $lang )->useDatabase( false );
4188 
4189  if ( $message->exists() ) {
4190  return $message->plain();
4191  } else {
4192  return false;
4193  }
4194  }
4195 
4202  public function invalidateCache( $purgeTime = null ) {
4203  if ( wfReadOnly() ) {
4204  return false;
4205  } elseif ( $this->mArticleID === 0 ) {
4206  return true; // avoid gap locking if we know it's not there
4207  }
4208 
4209  $dbw = wfGetDB( DB_MASTER );
4210  $dbw->onTransactionPreCommitOrIdle(
4211  function () use ( $dbw ) {
4213  $this, null, null, $dbw->getDomainID() );
4214  },
4215  __METHOD__
4216  );
4217 
4218  $conds = $this->pageCond();
4220  new AutoCommitUpdate(
4221  $dbw,
4222  __METHOD__,
4223  function ( IDatabase $dbw, $fname ) use ( $conds, $purgeTime ) {
4224  $dbTimestamp = $dbw->timestamp( $purgeTime ?: time() );
4225  $dbw->update(
4226  'page',
4227  [ 'page_touched' => $dbTimestamp ],
4228  $conds + [ 'page_touched < ' . $dbw->addQuotes( $dbTimestamp ) ],
4229  $fname
4230  );
4231  MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $this );
4232  }
4233  ),
4235  );
4236 
4237  return true;
4238  }
4239 
4245  public function touchLinks() {
4246  DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this, 'pagelinks', 'page-touch' ) );
4247  if ( $this->mNamespace == NS_CATEGORY ) {
4249  new HTMLCacheUpdate( $this, 'categorylinks', 'category-touch' )
4250  );
4251  }
4252  }
4253 
4260  public function getTouched( $db = null ) {
4261  if ( $db === null ) {
4262  $db = wfGetDB( DB_REPLICA );
4263  }
4264  $touched = $db->selectField( 'page', 'page_touched', $this->pageCond(), __METHOD__ );
4265  return $touched;
4266  }
4267 
4274  public function getNotificationTimestamp( $user = null ) {
4275  global $wgUser;
4276 
4277  // Assume current user if none given
4278  if ( !$user ) {
4279  $user = $wgUser;
4280  }
4281  // Check cache first
4282  $uid = $user->getId();
4283  if ( !$uid ) {
4284  return false;
4285  }
4286  // avoid isset here, as it'll return false for null entries
4287  if ( array_key_exists( $uid, $this->mNotificationTimestamp ) ) {
4288  return $this->mNotificationTimestamp[$uid];
4289  }
4290  // Don't cache too much!
4291  if ( count( $this->mNotificationTimestamp ) >= self::CACHE_MAX ) {
4292  $this->mNotificationTimestamp = [];
4293  }
4294 
4295  $store = MediaWikiServices::getInstance()->getWatchedItemStore();
4296  $watchedItem = $store->getWatchedItem( $user, $this );
4297  if ( $watchedItem ) {
4298  $this->mNotificationTimestamp[$uid] = $watchedItem->getNotificationTimestamp();
4299  } else {
4300  $this->mNotificationTimestamp[$uid] = false;
4301  }
4302 
4303  return $this->mNotificationTimestamp[$uid];
4304  }
4305 
4312  public function getNamespaceKey( $prepend = 'nstab-' ) {
4313  // Gets the subject namespace of this title
4314  $subjectNS = MWNamespace::getSubject( $this->mNamespace );
4315  // Prefer canonical namespace name for HTML IDs
4316  $namespaceKey = MWNamespace::getCanonicalName( $subjectNS );
4317  if ( $namespaceKey === false ) {
4318  // Fallback to localised text
4319  $namespaceKey = $this->getSubjectNsText();
4320  }
4321  // Makes namespace key lowercase
4322  $namespaceKey = MediaWikiServices::getInstance()->getContentLanguage()->lc( $namespaceKey );
4323  // Uses main
4324  if ( $namespaceKey == '' ) {
4325  $namespaceKey = 'main';
4326  }
4327  // Changes file to image for backwards compatibility
4328  if ( $namespaceKey == 'file' ) {
4329  $namespaceKey = 'image';
4330  }
4331  return $prepend . $namespaceKey;
4332  }
4333 
4340  public function getRedirectsHere( $ns = null ) {
4341  $redirs = [];
4342 
4343  $dbr = wfGetDB( DB_REPLICA );
4344  $where = [
4345  'rd_namespace' => $this->mNamespace,
4346  'rd_title' => $this->mDbkeyform,
4347  'rd_from = page_id'
4348  ];
4349  if ( $this->isExternal() ) {
4350  $where['rd_interwiki'] = $this->mInterwiki;
4351  } else {
4352  $where[] = 'rd_interwiki = ' . $dbr->addQuotes( '' ) . ' OR rd_interwiki IS NULL';
4353  }
4354  if ( !is_null( $ns ) ) {
4355  $where['page_namespace'] = $ns;
4356  }
4357 
4358  $res = $dbr->select(
4359  [ 'redirect', 'page' ],
4360  [ 'page_namespace', 'page_title' ],
4361  $where,
4362  __METHOD__
4363  );
4364 
4365  foreach ( $res as $row ) {
4366  $redirs[] = self::newFromRow( $row );
4367  }
4368  return $redirs;
4369  }
4370 
4376  public function isValidRedirectTarget() {
4378 
4379  if ( $this->isSpecialPage() ) {
4380  // invalid redirect targets are stored in a global array, but explicitly disallow Userlogout here
4381  if ( $this->isSpecial( 'Userlogout' ) ) {
4382  return false;
4383  }
4384 
4385  foreach ( $wgInvalidRedirectTargets as $target ) {
4386  if ( $this->isSpecial( $target ) ) {
4387  return false;
4388  }
4389  }
4390  }
4391 
4392  return true;
4393  }
4394 
4400  public function getBacklinkCache() {
4401  return BacklinkCache::get( $this );
4402  }
4403 
4409  public function canUseNoindex() {
4411 
4413 
4414  return !in_array( $this->mNamespace, $bannedNamespaces );
4415  }
4416 
4427  public function getCategorySortkey( $prefix = '' ) {
4428  $unprefixed = $this->getText();
4429 
4430  // Anything that uses this hook should only depend
4431  // on the Title object passed in, and should probably
4432  // tell the users to run updateCollations.php --force
4433  // in order to re-sort existing category relations.
4434  Hooks::run( 'GetDefaultSortkey', [ $this, &$unprefixed ] );
4435  if ( $prefix !== '' ) {
4436  # Separate with a line feed, so the unprefixed part is only used as
4437  # a tiebreaker when two pages have the exact same prefix.
4438  # In UCA, tab is the only character that can sort above LF
4439  # so we strip both of them from the original prefix.
4440  $prefix = strtr( $prefix, "\n\t", ' ' );
4441  return "$prefix\n$unprefixed";
4442  }
4443  return $unprefixed;
4444  }
4445 
4453  private function getDbPageLanguageCode() {
4454  global $wgPageLanguageUseDB;
4455 
4456  // check, if the page language could be saved in the database, and if so and
4457  // the value is not requested already, lookup the page language using LinkCache
4458  if ( $wgPageLanguageUseDB && $this->mDbPageLanguage === false ) {
4459  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
4460  $linkCache->addLinkObj( $this );
4461  $this->mDbPageLanguage = $linkCache->getGoodLinkFieldObj( $this, 'lang' );
4462  }
4463 
4464  return $this->mDbPageLanguage;
4465  }
4466 
4475  public function getPageLanguage() {
4476  global $wgLang, $wgLanguageCode;
4477  if ( $this->isSpecialPage() ) {
4478  // special pages are in the user language
4479  return $wgLang;
4480  }
4481 
4482  // Checking if DB language is set
4483  $dbPageLanguage = $this->getDbPageLanguageCode();
4484  if ( $dbPageLanguage ) {
4485  return wfGetLangObj( $dbPageLanguage );
4486  }
4487 
4488  if ( !$this->mPageLanguage || $this->mPageLanguage[1] !== $wgLanguageCode ) {
4489  // Note that this may depend on user settings, so the cache should
4490  // be only per-request.
4491  // NOTE: ContentHandler::getPageLanguage() may need to load the
4492  // content to determine the page language!
4493  // Checking $wgLanguageCode hasn't changed for the benefit of unit
4494  // tests.
4495  $contentHandler = ContentHandler::getForTitle( $this );
4496  $langObj = $contentHandler->getPageLanguage( $this );
4497  $this->mPageLanguage = [ $langObj->getCode(), $wgLanguageCode ];
4498  } else {
4499  $langObj = Language::factory( $this->mPageLanguage[0] );
4500  }
4501 
4502  return $langObj;
4503  }
4504 
4513  public function getPageViewLanguage() {
4514  global $wgLang;
4515 
4516  if ( $this->isSpecialPage() ) {
4517  // If the user chooses a variant, the content is actually
4518  // in a language whose code is the variant code.
4519  $variant = $wgLang->getPreferredVariant();
4520  if ( $wgLang->getCode() !== $variant ) {
4521  return Language::factory( $variant );
4522  }
4523 
4524  return $wgLang;
4525  }
4526 
4527  // Checking if DB language is set
4528  $dbPageLanguage = $this->getDbPageLanguageCode();
4529  if ( $dbPageLanguage ) {
4530  $pageLang = wfGetLangObj( $dbPageLanguage );
4531  $variant = $pageLang->getPreferredVariant();
4532  if ( $pageLang->getCode() !== $variant ) {
4533  $pageLang = Language::factory( $variant );
4534  }
4535 
4536  return $pageLang;
4537  }
4538 
4539  // @note Can't be cached persistently, depends on user settings.
4540  // @note ContentHandler::getPageViewLanguage() may need to load the
4541  // content to determine the page language!
4542  $contentHandler = ContentHandler::getForTitle( $this );
4543  $pageLang = $contentHandler->getPageViewLanguage( $this );
4544  return $pageLang;
4545  }
4546 
4557  public function getEditNotices( $oldid = 0 ) {
4558  $notices = [];
4559 
4560  // Optional notice for the entire namespace
4561  $editnotice_ns = 'editnotice-' . $this->mNamespace;
4562  $msg = wfMessage( $editnotice_ns );
4563  if ( $msg->exists() ) {
4564  $html = $msg->parseAsBlock();
4565  // Edit notices may have complex logic, but output nothing (T91715)
4566  if ( trim( $html ) !== '' ) {
4567  $notices[$editnotice_ns] = Html::rawElement(
4568  'div',
4569  [ 'class' => [
4570  'mw-editnotice',
4571  'mw-editnotice-namespace',
4572  Sanitizer::escapeClass( "mw-$editnotice_ns" )
4573  ] ],
4574  $html
4575  );
4576  }
4577  }
4578 
4579  if ( MWNamespace::hasSubpages( $this->mNamespace ) ) {
4580  // Optional notice for page itself and any parent page
4581  $editnotice_base = $editnotice_ns;
4582  foreach ( explode( '/', $this->mDbkeyform ) as $part ) {
4583  $editnotice_base .= '-' . $part;
4584  $msg = wfMessage( $editnotice_base );
4585  if ( $msg->exists() ) {
4586  $html = $msg->parseAsBlock();
4587  if ( trim( $html ) !== '' ) {
4588  $notices[$editnotice_base] = Html::rawElement(
4589  'div',
4590  [ 'class' => [
4591  'mw-editnotice',
4592  'mw-editnotice-base',
4593  Sanitizer::escapeClass( "mw-$editnotice_base" )
4594  ] ],
4595  $html
4596  );
4597  }
4598  }
4599  }
4600  } else {
4601  // Even if there are no subpages in namespace, we still don't want "/" in MediaWiki message keys
4602  $editnoticeText = $editnotice_ns . '-' . strtr( $this->mDbkeyform, '/', '-' );
4603  $msg = wfMessage( $editnoticeText );
4604  if ( $msg->exists() ) {
4605  $html = $msg->parseAsBlock();
4606  if ( trim( $html ) !== '' ) {
4607  $notices[$editnoticeText] = Html::rawElement(
4608  'div',
4609  [ 'class' => [
4610  'mw-editnotice',
4611  'mw-editnotice-page',
4612  Sanitizer::escapeClass( "mw-$editnoticeText" )
4613  ] ],
4614  $html
4615  );
4616  }
4617  }
4618  }
4619 
4620  Hooks::run( 'TitleGetEditNotices', [ $this, $oldid, &$notices ] );
4621  return $notices;
4622  }
4623 
4627  public function __sleep() {
4628  return [
4629  'mNamespace',
4630  'mDbkeyform',
4631  'mFragment',
4632  'mInterwiki',
4633  'mLocalInterwiki',
4634  'mUserCaseDBKey',
4635  'mDefaultNamespace',
4636  ];
4637  }
4638 
4639  public function __wakeup() {
4640  $this->mArticleID = ( $this->mNamespace >= 0 ) ? -1 : 0;
4641  $this->mUrlform = wfUrlencode( $this->mDbkeyform );
4642  $this->mTextform = strtr( $this->mDbkeyform, '_', ' ' );
4643  }
4644 
4645 }
Title\$mLocalInterwiki
bool $mLocalInterwiki
Was this Title created from a string with a local interwiki prefix?
Definition: Title.php:92
Title\$mRestrictions
array $mRestrictions
Array of groups allowed to edit this article.
Definition: Title.php:119
Title\canHaveTalkPage
canHaveTalkPage()
Can this title have a corresponding talk page?
Definition: Title.php:1101
Title\getTitleProtection
getTitleProtection()
Is this title subject to title protection? Title protection is the one applied against creation of su...
Definition: Title.php:2290
Title\canUseNoindex
canUseNoindex()
Whether the magic words INDEX and NOINDEX function for this page.
Definition: Title.php:4409
$status
Status::newGood()` to allow deletion, and then `return false` from the hook function. Ensure you consume the 'ChangeTagAfterDelete' hook to carry out custom deletion actions. $tag:name of the tag $user:user initiating the action & $status:Status object. See above. 'ChangeTagsListActive':Allows you to nominate which of the tags your extension uses are in active use. & $tags:list of all active tags. Append to this array. 'ChangeTagsAfterUpdateTags':Called after tags have been updated with the ChangeTags::updateTags function. Params:$addedTags:tags effectively added in the update $removedTags:tags effectively removed in the update $prevTags:tags that were present prior to the update $rc_id:recentchanges table id $rev_id:revision table id $log_id:logging table id $params:tag params $rc:RecentChange being tagged when the tagging accompanies the action, or null $user:User who performed the tagging when the tagging is subsequent to the action, or null 'ChangeTagsAllowedAdd':Called when checking if a user can add tags to a change. & $allowedTags:List of all the tags the user is allowed to add. Any tags the user wants to add( $addTags) that are not in this array will cause it to fail. You may add or remove tags to this array as required. $addTags:List of tags user intends to add. $user:User who is adding the tags. 'ChangeUserGroups':Called before user groups are changed. $performer:The User who will perform the change $user:The User whose groups will be changed & $add:The groups that will be added & $remove:The groups that will be removed 'Collation::factory':Called if $wgCategoryCollation is an unknown collation. $collationName:Name of the collation in question & $collationObject:Null. Replace with a subclass of the Collation class that implements the collation given in $collationName. 'ConfirmEmailComplete':Called after a user 's email has been confirmed successfully. $user:user(object) whose email is being confirmed 'ContentAlterParserOutput':Modify parser output for a given content object. Called by Content::getParserOutput after parsing has finished. Can be used for changes that depend on the result of the parsing but have to be done before LinksUpdate is called(such as adding tracking categories based on the rendered HTML). $content:The Content to render $title:Title of the page, as context $parserOutput:ParserOutput to manipulate 'ContentGetParserOutput':Customize parser output for a given content object, called by AbstractContent::getParserOutput. May be used to override the normal model-specific rendering of page content. $content:The Content to render $title:Title of the page, as context $revId:The revision ID, as context $options:ParserOptions for rendering. To avoid confusing the parser cache, the output can only depend on parameters provided to this hook function, not on global state. $generateHtml:boolean, indicating whether full HTML should be generated. If false, generation of HTML may be skipped, but other information should still be present in the ParserOutput object. & $output:ParserOutput, to manipulate or replace 'ContentHandlerDefaultModelFor':Called when the default content model is determined for a given title. May be used to assign a different model for that title. $title:the Title in question & $model:the model name. Use with CONTENT_MODEL_XXX constants. 'ContentHandlerForModelID':Called when a ContentHandler is requested for a given content model name, but no entry for that model exists in $wgContentHandlers. Note:if your extension implements additional models via this hook, please use GetContentModels hook to make them known to core. $modeName:the requested content model name & $handler:set this to a ContentHandler object, if desired. 'ContentModelCanBeUsedOn':Called to determine whether that content model can be used on a given page. This is especially useful to prevent some content models to be used in some special location. $contentModel:ID of the content model in question $title:the Title in question. & $ok:Output parameter, whether it is OK to use $contentModel on $title. Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok. 'ContribsPager::getQueryInfo':Before the contributions query is about to run & $pager:Pager object for contributions & $queryInfo:The query for the contribs Pager 'ContribsPager::reallyDoQuery':Called before really executing the query for My Contributions & $data:an array of results of all contribs queries $pager:The ContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'ContributionsLineEnding':Called before a contributions HTML line is finished $page:SpecialPage object for contributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'ContributionsToolLinks':Change tool links above Special:Contributions $id:User identifier $title:User page title & $tools:Array of tool links $specialPage:SpecialPage instance for context and services. Can be either SpecialContributions or DeletedContributionsPage. Extensions should type hint against a generic SpecialPage though. 'ConvertContent':Called by AbstractContent::convert when a conversion to another content model is requested. Handler functions that modify $result should generally return false to disable further attempts at conversion. $content:The Content object to be converted. $toModel:The ID of the content model to convert to. $lossy:boolean indicating whether lossy conversion is allowed. & $result:Output parameter, in case the handler function wants to provide a converted Content object. Note that $result->getContentModel() must return $toModel. 'ContentSecurityPolicyDefaultSource':Modify the allowed CSP load sources. This affects all directives except for the script directive. If you want to add a script source, see ContentSecurityPolicyScriptSource hook. & $defaultSrc:Array of Content-Security-Policy allowed sources $policyConfig:Current configuration for the Content-Security-Policy header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyDirectives':Modify the content security policy directives. Use this only if ContentSecurityPolicyDefaultSource and ContentSecurityPolicyScriptSource do not meet your needs. & $directives:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyScriptSource':Modify the allowed CSP script sources. Note that you also have to use ContentSecurityPolicyDefaultSource if you want non-script sources to be loaded from whatever you add. & $scriptSrc:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'CustomEditor':When invoking the page editor Return true to allow the normal editor to be used, or false if implementing a custom editor, e.g. for a special namespace, etc. $article:Article being edited $user:User performing the edit 'DatabaseOraclePostInit':Called after initialising an Oracle database $db:the DatabaseOracle object 'DeletedContribsPager::reallyDoQuery':Called before really executing the query for Special:DeletedContributions Similar to ContribsPager::reallyDoQuery & $data:an array of results of all contribs queries $pager:The DeletedContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'DeletedContributionsLineEnding':Called before a DeletedContributions HTML line is finished. Similar to ContributionsLineEnding $page:SpecialPage object for DeletedContributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'DeleteUnknownPreferences':Called by the cleanupPreferences.php maintenance script to build a WHERE clause with which to delete preferences that are not known about. This hook is used by extensions that have dynamically-named preferences that should not be deleted in the usual cleanup process. For example, the Gadgets extension creates preferences prefixed with 'gadget-', and so anything with that prefix is excluded from the deletion. &where:An array that will be passed as the $cond parameter to IDatabase::select() to determine what will be deleted from the user_properties table. $db:The IDatabase object, useful for accessing $db->buildLike() etc. 'DifferenceEngineAfterLoadNewText':called in DifferenceEngine::loadNewText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before returning true from this function. $differenceEngine:DifferenceEngine object 'DifferenceEngineLoadTextAfterNewContentIsLoaded':called in DifferenceEngine::loadText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before checking if the variable 's value is null. This hook can be used to inject content into said class member variable. $differenceEngine:DifferenceEngine object 'DifferenceEngineMarkPatrolledLink':Allows extensions to change the "mark as patrolled" link which is shown both on the diff header as well as on the bottom of a page, usually wrapped in a span element which has class="patrollink". $differenceEngine:DifferenceEngine object & $markAsPatrolledLink:The "mark as patrolled" link HTML(string) $rcid:Recent change ID(rc_id) for this change(int) 'DifferenceEngineMarkPatrolledRCID':Allows extensions to possibly change the rcid parameter. For example the rcid might be set to zero due to the user being the same as the performer of the change but an extension might still want to show it under certain conditions. & $rcid:rc_id(int) of the change or 0 $differenceEngine:DifferenceEngine object $change:RecentChange object $user:User object representing the current user 'DifferenceEngineNewHeader':Allows extensions to change the $newHeader variable, which contains information about the new revision, such as the revision 's author, whether the revision was marked as a minor edit or not, etc. $differenceEngine:DifferenceEngine object & $newHeader:The string containing the various #mw-diff-otitle[1-5] divs, which include things like revision author info, revision comment, RevisionDelete link and more $formattedRevisionTools:Array containing revision tools, some of which may have been injected with the DiffRevisionTools hook $nextlink:String containing the link to the next revision(if any) $status
Definition: hooks.txt:1266
Title\inNamespaces
inNamespaces()
Returns true if the title is inside one of the specified namespaces.
Definition: Title.php:1191
Title\getLocalURL
getLocalURL( $query='', $query2=false)
Get a URL with no fragment or server name (relative URL) from a Title object.
Definition: Title.php:1948
CONTENT_MODEL_JSON
const CONTENT_MODEL_JSON
Definition: Defines.php:239
Title\isSemiProtected
isSemiProtected( $action='edit')
Is this page "semi-protected" - the only protection levels are listed in $wgSemiprotectedRestrictionL...
Definition: Title.php:2378
Title\$mHasCascadingRestrictions
bool $mHasCascadingRestrictions
Are cascading restrictions in effect on this page?
Definition: Title.php:139
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:48
Title\isNamespaceProtected
isNamespaceProtected(User $user)
Determines if $user is unable to edit this page because it has been protected by $wgNamespaceProtecti...
Definition: Title.php:2438
Title\getTalkNsText
getTalkNsText()
Get the namespace text of the talk page.
Definition: Title.php:1088
$user
return true to allow those checks to and false if checking is done & $user
Definition: hooks.txt:1476
wfMergeErrorArrays
wfMergeErrorArrays(... $args)
Merge arrays in the style of getUserPermissionsErrors, with duplicate removal e.g.
Definition: GlobalFunctions.php:205
Title\getSubpageText
getSubpageText()
Get the lowest-level subpage name, i.e.
Definition: Title.php:1781
MediaWiki\Linker\LinkTarget\getInterwiki
getInterwiki()
The interwiki component of this LinkTarget.
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:306
MWNamespace\subjectEquals
static subjectEquals( $ns1, $ns2)
Returns whether the specified namespaces share the same subject.
Definition: MWNamespace.php:217
Title\isBigDeletion
isBigDeletion()
Check whether the number of revisions of this page surpasses $wgDeleteRevisionsLimit.
Definition: Title.php:3825
Title\getNextRevisionID
getNextRevisionID( $revId, $flags=0)
Get the revision ID of the next revision.
Definition: Title.php:3768
PROTO_CANONICAL
const PROTO_CANONICAL
Definition: Defines.php:223
Title\areCascadeProtectionSourcesLoaded
areCascadeProtectionSourcesLoaded( $getPages=true)
Determines whether cascading protection sources have already been loaded from the database.
Definition: Title.php:2470
MediaWiki\Linker\LinkTarget\getText
getText()
Returns the link in text form, without namespace prefix or fragment.
$file
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Definition: router.php:42
WANObjectCache\TTL_UNCACHEABLE
const TTL_UNCACHEABLE
Idiom for getWithSetCallback() callbacks to avoid calling set()
Definition: WANObjectCache.php:177
Title\getFilteredRestrictionTypes
static getFilteredRestrictionTypes( $exists=true)
Get a filtered list of all restriction types supported by this wiki.
Definition: Title.php:2245
Title\makeName
static makeName( $ns, $title, $fragment='', $interwiki='', $canonicalNamespace=false)
Make a prefixed DB key from a DB key and a namespace index.
Definition: Title.php:788
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
Title\getInternalURL
getInternalURL( $query='', $query2=false)
Get the URL form for an internal link.
Definition: Title.php:2072
$wgActionPaths
$wgActionPaths
Definition: img_auth.php:47
Title\getFragment
getFragment()
Get the Title fragment (i.e.
Definition: Title.php:1549
MWNamespace\isTalk
static isTalk( $index)
Is the given namespace a talk namespace?
Definition: MWNamespace.php:119
$wgExemptFromUserRobotsControl
$wgExemptFromUserRobotsControl
An array of namespace keys in which the INDEX/__NOINDEX__ magic words will not function,...
Definition: DefaultSettings.php:8047
Title\getTalkPageIfDefined
getTalkPageIfDefined()
Get a Title object associated with the talk page of this article, if such a talk page can exist.
Definition: Title.php:1488
Title\inNamespace
inNamespace( $ns)
Returns true if the title is inside the specified namespace.
Definition: Title.php:1180
Title\$mForcedContentModel
bool $mForcedContentModel
If a content model was forced via setContentModel() this will be true to avoid having other code path...
Definition: Title.php:113
TitleArray\newFromResult
static newFromResult( $res)
Definition: TitleArray.php:40
Title\isMovable
isMovable()
Would anybody with sufficient privileges be able to move this page? Some pages just aren't movable.
Definition: Title.php:1240
$wgMaximumMovedPages
$wgMaximumMovedPages
Maximum number of pages to move at once when moving subpages with a page.
Definition: DefaultSettings.php:8503
Title\wasLocalInterwiki
wasLocalInterwiki()
Was this a local interwiki link?
Definition: Title.php:889
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:33
Title\isWikitextPage
isWikitextPage()
Does that page contain wikitext, or it is JS, CSS or whatever?
Definition: Title.php:1293
Title\isUserCssConfigPage
isUserCssConfigPage()
Is this a CSS "config" sub-page of a user page?
Definition: Title.php:1355
Title\getBacklinkCache
getBacklinkCache()
Get a backlink cache object.
Definition: Title.php:4400
Title\getPartialURL
getPartialURL()
Get the URL-encoded form of the main part.
Definition: Title.php:961
$wgLegalTitleChars
$wgLegalTitleChars
Allowed title characters – regex character class Don't change this unless you know what you're doing.
Definition: DefaultSettings.php:3904
Title\clearCaches
static clearCaches()
Text form (spaces not underscores) of the main part.
Definition: Title.php:3095
AutoCommitUpdate
Deferrable Update for closure/callback updates that should use auto-commit mode.
Definition: AutoCommitUpdate.php:9
Title\moveSubpages
moveSubpages( $nt, $auth=true, $reason='', $createRedirect=true, array $changeTags=[])
Move this page's subpages to be subpages of $nt.
Definition: Title.php:3451
Title\getTitleValue
getTitleValue()
Get a TitleValue object representing this Title.
Definition: Title.php:929
Title\estimateRevisionCount
estimateRevisionCount()
Get the approximate revision count of this page.
Definition: Title.php:3854
Title\countRevisionsBetween
countRevisionsBetween( $old, $new, $max=null)
Get the number of revisions between the given revision.
Definition: Title.php:3877
captcha-old.count
count
Definition: captcha-old.py:249
Title\getPrefixedDBkey
getPrefixedDBkey()
Get the prefixed database key form.
Definition: Title.php:1648
Title\getDbPageLanguageCode
getDbPageLanguageCode()
Returns the page language code saved in the database, if $wgPageLanguageUseDB is set to true in Local...
Definition: Title.php:4453
Title\getSkinFromConfigSubpage
getSkinFromConfigSubpage()
Trim down a .css, .json, or .js subpage title to get the corresponding skin name.
Definition: Title.php:1339
$wgScript
$wgScript
The URL path to index.php.
Definition: DefaultSettings.php:186
Title\$mUserCaseDBKey
string $mUserCaseDBKey
Database key with the initial letter in the case specified by the user.
Definition: Title.php:83
Title\$mHasSubpages
bool $mHasSubpages
Whether a page has any subpages.
Definition: Title.php:177
Title\getTalkPage
getTalkPage()
Get a Title object associated with the talk page of this article.
Definition: Title.php:1475
Title\newMainPage
static newMainPage()
Create a new Title for the Main Page.
Definition: Title.php:632
Title\NEW_CLONE
const NEW_CLONE
Flag for use with factory methods like newFromLinkTarget() that have a $forceClone parameter.
Definition: Title.php:64
Title\getNotificationTimestamp
getNotificationTimestamp( $user=null)
Get the timestamp when this page was updated since the user last saw it.
Definition: Title.php:4274
Title\getParentCategoryTree
getParentCategoryTree( $children=[])
Get a tree of parent categories.
Definition: Title.php:3658
CONTENT_MODEL_CSS
const CONTENT_MODEL_CSS
Definition: Defines.php:237
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUnknownUser':When a user doesn 't exist locally, this hook is called to give extensions an opportunity to auto-create it. If the auto-creation is successful, return false. $name:User name 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED since 1.28! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1983
Title\fixUrlQueryArgs
static fixUrlQueryArgs( $query, $query2=false)
Helper to fix up the get{Canonical,Full,Link,Local,Internal}URL args get{Canonical,...
Definition: Title.php:1841
$namespaces
namespace and then decline to actually register it & $namespaces
Definition: hooks.txt:925
Title\fixSpecialName
fixSpecialName()
If the Title refers to a special page alias which is not the local default, resolve the alias,...
Definition: Title.php:1156
$out
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not it can be in the form of< username >< more info > e g for bot passwords intended to be added to log contexts Fields it might only if the login was with a bot password it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:780
Title\getInterwikiLookup
static getInterwikiLookup()
B/C kludge: provide an InterwikiLookup for use by Title.
Definition: Title.php:213
Title\isUserJsConfigPage
isUserJsConfigPage()
Is this a JS "config" sub-page of a user page?
Definition: Title.php:1383
MessageSpecifier
Definition: MessageSpecifier.php:21
Title\touchLinks
touchLinks()
Update page_touched timestamps and send CDN purge messages for pages linking to this title.
Definition: Title.php:4245
wfUrlencode
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
Definition: GlobalFunctions.php:333
$tables
this hook is for auditing only RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist & $tables
Definition: hooks.txt:979
Title\getPrefixedText
getPrefixedText()
Get the prefixed title with spaces.
Definition: Title.php:1660
Title\getTransWikiID
getTransWikiID()
Returns the DB name of the distant wiki which owns the object.
Definition: Title.php:912
Title\resultToError
resultToError( $errors, $result)
Add the resulting error code to the errors array.
Definition: Title.php:2218
DeferredUpdates\addUpdate
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the deferred list to be run later by execute()
Definition: DeferredUpdates.php:79
Title\getArticleID
getArticleID( $flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
Definition: Title.php:2954
StringUtils\escapeRegexReplacement
static escapeRegexReplacement( $string)
Escape a string to make it suitable for inclusion in a preg_replace() replacement parameter.
Definition: StringUtils.php:323
Title\getLinkURL
getLinkURL( $query='', $query2=false, $proto=false)
Get a URL that's the simplest URL that will be valid to link, locally, to the current Title.
Definition: Title.php:2047
Title\$mTitleValue
TitleValue null $mTitleValue
A corresponding TitleValue object.
Definition: Title.php:187
Title\secureAndSplit
secureAndSplit()
Secure and split - main initialisation function for this object.
Definition: Title.php:3130
Title\quickUserCan
quickUserCan( $action, $user=null)
Can $user perform $action on this page? This skips potentially expensive cascading permission checks ...
Definition: Title.php:2139
NS_FILE
const NS_FILE
Definition: Defines.php:70
Title\isTalkPage
isTalkPage()
Is this a talk page of some sort?
Definition: Title.php:1466
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1197
$s
$s
Definition: mergeMessageFileList.php:186
SpecialPage\getTitleFor
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Definition: SpecialPage.php:82
ContentHandler\getForTitle
static getForTitle(Title $title)
Returns the appropriate ContentHandler singleton for the given title.
Definition: ContentHandler.php:199
$res
$res
Definition: database.txt:21
Title\isExternal
isExternal()
Is this Title interwiki?
Definition: Title.php:869
Title\loadRestrictionsFromRows
loadRestrictionsFromRows( $rows, $oldFashionedRestrictions=null)
Compiles list of active page restrictions from both page table (pre 1.10) and page_restrictions table...
Definition: Title.php:2645
$success
$success
Definition: NoLocalSettings.php:42
Title\getDefaultMessageText
getDefaultMessageText()
Get the default (plain) message contents for an page that overrides an interface message key.
Definition: Title.php:4179
CONTENT_MODEL_WIKITEXT
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:235
Title\hasSourceText
hasSourceText()
Does this page have source text?
Definition: Title.php:4121
Title\loadFromRow
loadFromRow( $row)
Load Title object fields from a DB row.
Definition: Title.php:518
Title\resetArticleID
resetArticleID( $newid)
This clears some fields in this object, and clears any associated keys in the "bad links" section of ...
Definition: Title.php:3073
Title\setFragment
setFragment( $fragment)
Set the fragment for this title.
Definition: Title.php:1595
IDBAccessObject
Interface for database access objects.
Definition: IDBAccessObject.php:55
MWNamespace\getContentNamespaces
static getContentNamespaces()
Get a list of all namespace indices which are considered to contain content.
Definition: MWNamespace.php:375
$wgContentHandlerUseDB
$wgContentHandlerUseDB
Set to false to disable use of the database fields introduced by the ContentHandler facility.
Definition: DefaultSettings.php:8594
Title\$mIsBigDeletion
bool null $mIsBigDeletion
Would deleting this page be a big deletion?
Definition: Title.php:190
Title\convertByteClassToUnicodeClass
static convertByteClassToUnicodeClass( $byteClass)
Utility method for converting a character sequence from bytes to Unicode.
Definition: Title.php:683
Title\__wakeup
__wakeup()
Text form (spaces not underscores) of the main part.
Definition: Title.php:4639
$revQuery
$revQuery
Definition: testCompression.php:51
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
Title\getParentCategories
getParentCategories()
Get categories to which this Title belongs and return an array of categories' names.
Definition: Title.php:3623
Title\getLinksTo
getLinksTo( $options=[], $table='pagelinks', $prefix='pl')
Get an array of Title objects linking to this Title Also stores the IDs in the link cache.
Definition: Title.php:3172
Title\$mContentModel
bool string $mContentModel
ID of the page's content model, i.e.
Definition: Title.php:107
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
Title\isSiteCssConfigPage
isSiteCssConfigPage()
Is this a sitewide CSS "config" page?
Definition: Title.php:1397
Title\getNsText
getNsText()
Get the namespace text.
Definition: Title.php:1054
Title\$mDbkeyform
string $mDbkeyform
Main part with underscores.
Definition: Title.php:80
Title\$mUrlform
string $mUrlform
URL-encoded form of the main part.
Definition: Title.php:77
$dbr
$dbr
Definition: testCompression.php:50
Title\getLinksFrom
getLinksFrom( $options=[], $table='pagelinks', $prefix='pl')
Get an array of Title objects linked from this Title Also stores the IDs in the link cache.
Definition: Title.php:3230
Title\$mOldRestrictions
string bool $mOldRestrictions
Comma-separated set of permission keys indicating who can move or edit the page from the page table,...
Definition: Title.php:127
wfAppendQuery
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
Definition: GlobalFunctions.php:463
Revision
Definition: Revision.php:40
NS_MAIN
const NS_MAIN
Definition: Defines.php:64
Title\isCascadeProtected
isCascadeProtected()
Cascading protection: Return true if cascading restrictions apply to this page, false if not.
Definition: Title.php:2456
Revision\newFromTitle
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target.
Definition: Revision.php:137
Title\isValidMoveTarget
isValidMoveTarget( $nt)
Checks if $this can be moved to a given Title.
Definition: Title.php:3575
$query
null for the wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1588
Title\getCdnUrls
getCdnUrls()
Get a list of URLs to purge from the CDN cache when this page changes.
Definition: Title.php:3332
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:53
Title\getOtherPage
getOtherPage()
Get the other title for this page, if this is a subject page get the talk page, if it is a subject pa...
Definition: Title.php:1519
MediaWiki\Linker\LinkTarget\getNamespace
getNamespace()
Get the namespace index.
Title\isSiteConfigPage
isSiteConfigPage()
Could this MediaWiki namespace page contain custom CSS, JSON, or JavaScript for the global UI.
Definition: Title.php:1311
$data
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
Definition: generatePhpCharToUpperMappings.php:13
Title\isUserJsonConfigPage
isUserJsonConfigPage()
Is this a JSON "config" sub-page of a user page?
Definition: Title.php:1369
Wikimedia\Rdbms\IDatabase\timestamp
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
ContentHandler\getDefaultModelFor
static getDefaultModelFor(Title $title)
Returns the name of the default content model to be used for the page with the given title.
Definition: ContentHandler.php:184
$wgRawHtmlMessages
string[] $wgRawHtmlMessages
List of messages which might contain raw HTML.
Definition: DefaultSettings.php:8814
Title\getDBkey
getDBkey()
Get the main part with underscores.
Definition: Title.php:970
Revision\getQueryInfo
static getQueryInfo( $options=[])
Return the tables, fields, and join conditions to be selected to create a new revision object.
Definition: Revision.php:511
Title\nameOf
static nameOf( $id)
Get the prefixed DB key associated with an ID.
Definition: Title.php:647
Title\$mDbPageLanguage
string bool null $mDbPageLanguage
The page language code from the database, null if not saved in the database or false if not loaded,...
Definition: Title.php:184
$html
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:1985
Title\isSpecial
isSpecial( $name)
Returns true if this title resolves to the named special page.
Definition: Title.php:1138
MWException
MediaWiki exception.
Definition: MWException.php:26
Title\getTitleFormatter
static getTitleFormatter()
B/C kludge: provide a TitleParser for use by Title.
Definition: Title.php:201
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
MapCacheLRU\get
get( $key, $maxAge=0.0)
Get the value for a key.
Definition: MapCacheLRU.php:163
Title\isMainPage
isMainPage()
Is this the mainpage?
Definition: Title.php:1261
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1078
$titles
linkcache txt The LinkCache class maintains a list of article titles and the information about whether or not the article exists in the database This is used to mark up links when displaying a page If the same link appears more than once on any page then it only has to be looked up once In most cases link lookups are done in batches with the LinkBatch class or the equivalent in so the link cache is mostly useful for short snippets of parsed and for links in the navigation areas of the skin The link cache was formerly used to track links used in a document for the purposes of updating the link tables This application is now deprecated To create a you can use the following $titles
Definition: linkcache.txt:17
Title\moveTo
moveTo(&$nt, $auth=true, $reason='', $createRedirect=true, array $changeTags=[])
Move a title to a new location.
Definition: Title.php:3413
Title\getSubpage
getSubpage( $text)
Get the title for a subpage of the current page.
Definition: Title.php:1802
Title\getBaseTitle
getBaseTitle()
Get the base page name title, i.e.
Definition: Title.php:1766
Title\getNamespace
getNamespace()
Get the namespace index, i.e.
Definition: Title.php:994
BacklinkCache\get
static get(Title $title)
Create a new BacklinkCache or reuse any existing one.
Definition: BacklinkCache.php:113
Title\newFromRow
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:506
Title\isConversionTable
isConversionTable()
Is this a conversion table for the LanguageConverter?
Definition: Title.php:1281
MovePage
Handles the backend logic of moving a page from one title to another.
Definition: MovePage.php:32
Title\isProtected
isProtected( $action='')
Does the title correspond to a protected article?
Definition: Title.php:2406
Title\flushRestrictions
flushRestrictions()
Flush the protection cache in this object and force reload from the database.
Definition: Title.php:2797
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2636
Title\getCategorySortkey
getCategorySortkey( $prefix='')
Returns the raw sort key to be used for categories, with the specified prefix.
Definition: Title.php:4427
Title\getInterwiki
getInterwiki()
Get the interwiki prefix.
Definition: Title.php:880
Title\isSiteJsonConfigPage
isSiteJsonConfigPage()
Is this a sitewide JSON "config" page?
Definition: Title.php:1415
$matches
$matches
Definition: NoLocalSettings.php:24
in
null for the wiki Added in
Definition: hooks.txt:1588
Title\isValidRedirectTarget
isValidRedirectTarget()
Check if this Title is a valid redirect target.
Definition: Title.php:4376
Title\deleteTitleProtection
deleteTitleProtection()
Remove any title protection due to page existing.
Definition: Title.php:2360
Title\__construct
__construct()
Definition: Title.php:220
$wgLang
$wgLang
Definition: Setup.php:875
MediaWiki\Interwiki\InterwikiLookup
Service interface for looking up Interwiki records.
Definition: InterwikiLookup.php:31
Title\userCan
userCan( $action, $user=null, $rigor=PermissionManager::RIGOR_SECURE)
Can $user perform $action on this page?
Definition: Title.php:2158
MWNamespace\isContent
static isContent( $index)
Does this namespace contain content, for the purposes of calculating statistics, etc?
Definition: MWNamespace.php:333
Title\getBrokenLinksFrom
getBrokenLinksFrom()
Get an array of Title objects referring to non-existent articles linked from this page.
Definition: Title.php:3296
Title\isUserConfigPage
isUserConfigPage()
Is this a "config" (.css, .json, or .js) sub-page of a user page?
Definition: Title.php:1325
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:222
Title\$mCascadeSources
array $mCascadeSources
Where are the cascading restrictions coming from on this page?
Definition: Title.php:142
Title\getSubjectPage
getSubjectPage()
Get a title object associated with the subject page of this talk page.
Definition: Title.php:1502
MapCacheLRU
Handles a simple LRU key/value map with a maximum number of entries.
Definition: MapCacheLRU.php:37
wfGetLangObj
wfGetLangObj( $langcode=false)
Return a Language object from $langcode.
Definition: GlobalFunctions.php:1241
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
Title\loadRestrictions
loadRestrictions( $oldFashionedRestrictions=null, $flags=0)
Load restrictions from the page_restrictions table.
Definition: Title.php:2723
$wgInvalidRedirectTargets
$wgInvalidRedirectTargets
Array of invalid page redirect targets.
Definition: DefaultSettings.php:4089
Title\getFullText
getFullText()
Get the prefixed title with spaces, plus any fragment (part beginning with '#')
Definition: Title.php:1684
MWNamespace\hasTalkNamespace
static hasTalkNamespace( $index)
Does this namespace ever have a talk namespace?
Definition: MWNamespace.php:322
MWNamespace\hasSubpages
static hasSubpages( $index)
Does the namespace allow subpages?
Definition: MWNamespace.php:366
Title\getTitleCache
static getTitleCache()
Definition: Title.php:417
Title\hasFragment
hasFragment()
Check if a Title fragment is set.
Definition: Title.php:1559
$parser
see documentation in includes Linker php for Linker::makeImageLink or false for current used if you return false $parser
Definition: hooks.txt:1802
Title\getRedirectsHere
getRedirectsHere( $ns=null)
Get all extant redirects to this Title.
Definition: Title.php:4340
MWNamespace\isMovable
static isMovable( $index)
Can pages in the given namespace be moved?
Definition: MWNamespace.php:89
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:576
Title\$mInterwiki
string $mInterwiki
Interwiki prefix.
Definition: Title.php:89
Title\$mCascadeRestriction
bool $mCascadeRestriction
Cascade restrictions on this page to included templates and images?
Definition: Title.php:130
Title\equals
equals(Title $title)
Compare with another title.
Definition: Title.php:4006
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:1941
Title\getRootText
getRootText()
Get the root page name text without a namespace, i.e.
Definition: Title.php:1704
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:78
$wgNamespaceProtection
$wgNamespaceProtection
Set the minimum permissions required to edit pages in each namespace.
Definition: DefaultSettings.php:5334
Title\canExist
canExist()
Is this in a namespace that allows actual pages?
Definition: Title.php:1110
$wgDeleteRevisionsLimit
$wgDeleteRevisionsLimit
Optional to restrict deletion of pages with higher revision counts to users with the 'bigdelete' perm...
Definition: DefaultSettings.php:5511
DB_MASTER
const DB_MASTER
Definition: defines.php:26
Title\$prefixedText
string null $prefixedText
Text form including namespace/interwiki, initialised on demand.
Definition: Title.php:155
array
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:949
string
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:175
Title\__sleep
__sleep()
Definition: Title.php:4627
Title\getCanonicalURL
getCanonicalURL( $query='', $query2=false)
Get the URL for a canonical link, for use in things like IRC and e-mail notifications.
Definition: Title.php:2096
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
MessageCache\singleton
static singleton()
Get the signleton instance of this class.
Definition: MessageCache.php:114
$sort
$sort
Definition: profileinfo.php:328
Title\$mRedirect
null $mRedirect
Is the article at this title a redirect?
Definition: Title.php:171
Title\createFragmentTarget
createFragmentTarget( $fragment)
Creates a new Title for a different fragment of the same page.
Definition: Title.php:1606
Title\$mNamespace
int $mNamespace
Namespace index, i.e.
Definition: Title.php:86
Title\getDefaultNamespace
getDefaultNamespace()
Get the default namespace index, for when there is no namespace.
Definition: Title.php:1538
null
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
$fname
if(defined( 'MW_SETUP_CALLBACK')) $fname
Customization point after all loading (constants, functions, classes, DefaultSettings,...
Definition: Setup.php:123
Title\newFromTextThrow
static newFromTextThrow( $text, $defaultNamespace=NS_MAIN)
Like Title::newFromText(), but throws MalformedTitleException when the title is invalid,...
Definition: Title.php:343
$wgPageLanguageUseDB
bool $wgPageLanguageUseDB
Enable page language feature Allows setting page language in database.
Definition: DefaultSettings.php:8682
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
Title\isValid
isValid()
Returns true if the title is valid, false if it is invalid.
Definition: Title.php:833
Title\$mPageLanguage
bool $mPageLanguage
The (string) language code of the page's language and content code.
Definition: Title.php:180
AtomicSectionUpdate
Deferrable Update for closure/callback updates via IDatabase::doAtomicSection()
Definition: AtomicSectionUpdate.php:9
HTMLCacheUpdate
Class to invalidate the HTML cache of all the pages linking to a given title.
Definition: HTMLCacheUpdate.php:29
Title\getPrefixedURL
getPrefixedURL()
Get a URL-encoded title (not an actual URL) including interwiki.
Definition: Title.php:1822
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:604
Title\__toString
__toString()
Return a string representation of this title.
Definition: Title.php:1674
MediaWiki\Permissions\PermissionManager
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
Definition: PermissionManager.php:43
DBAccessObjectUtils\hasFlags
static hasFlags( $bitfield, $flags)
Definition: DBAccessObjectUtils.php:35
Title\getTemplateLinksTo
getTemplateLinksTo( $options=[])
Get an array of Title objects using this Title as a template Also stores the IDs in the link cache.
Definition: Title.php:3214
Title\areRestrictionsCascading
areRestrictionsCascading()
Returns cascading restrictions for the current article.
Definition: Title.php:2626
NS_MEDIA
const NS_MEDIA
Definition: Defines.php:52
CdnCacheUpdate
Handles purging appropriate CDN URLs given a title (or titles)
Definition: CdnCacheUpdate.php:30
Title\getLatestRevID
getLatestRevID( $flags=0)
What is the page_latest field for this page?
Definition: Title.php:3041
Title\areRestrictionsLoaded
areRestrictionsLoaded()
Accessor for mRestrictionsLoaded.
Definition: Title.php:2573
Title\getSubpages
getSubpages( $limit=-1)
Get all subpages of this page.
Definition: Title.php:2876
Title\isSingleRevRedirect
isSingleRevRedirect()
Checks if this page is just a one-rev redirect.
Definition: Title.php:3524
$wgServer
$wgServer
URL of the server.
Definition: DefaultSettings.php:106
Title\GAID_FOR_UPDATE
const GAID_FOR_UPDATE
Used to be GAID_FOR_UPDATE define.
Definition: Title.php:55
Title\getPageViewLanguage
getPageViewLanguage()
Get the language in which the content of this page is written when viewed by user.
Definition: Title.php:4513
Title\newFromDBkey
static newFromDBkey( $key)
Create a new Title from a prefixed DB key.
Definition: Title.php:231
$wgLanguageCode
$wgLanguageCode
Site language code.
Definition: DefaultSettings.php:2912
Title\isSubpage
isSubpage()
Is this a subpage?
Definition: Title.php:1270
Title\hasContentModel
hasContentModel( $id)
Convenience method for checking a title's content model name.
Definition: Title.php:1029
Title\getRestrictionExpiry
getRestrictionExpiry( $action)
Get the expiry time for the restriction against a given action.
Definition: Title.php:2614
Title\newFromURL
static newFromURL( $url)
THIS IS NOT THE FUNCTION YOU WANT.
Definition: Title.php:394
ResourceLoaderWikiModule\invalidateModuleCache
static invalidateModuleCache(Title $title, Revision $old=null, Revision $new=null, $domain)
Clear the preloadTitleInfo() cache for all wiki modules on this wiki on page change if it was a JS or...
Definition: ResourceLoaderWikiModule.php:535
Title\isValidMoveOperation
isValidMoveOperation(&$nt, $auth=true, $reason='')
Check whether a given move operation would be valid.
Definition: Title.php:3379
MediaWiki\Linker\LinkTarget\getFragment
getFragment()
Get the link fragment (i.e.
PROTO_HTTP
const PROTO_HTTP
Definition: Defines.php:219
Title\$mRestrictionsExpiry
array $mRestrictionsExpiry
When do the restrictions on this page expire?
Definition: Title.php:136
MapCacheLRU\set
set( $key, $value, $rank=self::RANK_TOP)
Set a key/value pair.
Definition: MapCacheLRU.php:109
PROTO_RELATIVE
const PROTO_RELATIVE
Definition: Defines.php:221
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1985
Title\isSubpageOf
isSubpageOf(Title $title)
Check if this title is a subpage of another title.
Definition: Title.php:4019
Revision\RAW
const RAW
Definition: Revision.php:56
Title\isLocal
isLocal()
Determine whether the object refers to a page within this project (either this wiki or a wiki with a ...
Definition: Title.php:854
Title\$mFragment
string $mFragment
Title fragment (i.e.
Definition: Title.php:95
Title\getContentModel
getContentModel( $flags=0)
Get the page's content model id, see the CONTENT_MODEL_XXX constants.
Definition: Title.php:1006
Title\$mNotificationTimestamp
array $mNotificationTimestamp
Associative array of user ID -> timestamp/false.
Definition: Title.php:174
MWNamespace\exists
static exists( $index)
Returns whether the specified namespace exists.
Definition: MWNamespace.php:183
Title\newFromIDs
static newFromIDs( $ids)
Make an array of titles from an array of IDs.
Definition: Title.php:480
Wikimedia\Rdbms\IDatabase\update
update( $table, $values, $conds, $fname=__METHOD__, $options=[])
UPDATE wrapper.
WikiPage\getQueryInfo
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new page object.
Definition: WikiPage.php:383
Title\newFromLinkTarget
static newFromLinkTarget(LinkTarget $linkTarget, $forceClone='')
Returns a Title given a LinkTarget.
Definition: Title.php:269
Title\prefix
prefix( $name)
Prefix some arbitrary text with the namespace or interwiki prefix of this object.
Definition: Title.php:1622
Title\getNamespaceKey
getNamespaceKey( $prepend='nstab-')
Generate strings used for xml 'id' names in monobook tabs.
Definition: Title.php:4312
Title\getEditURL
getEditURL()
Get the edit URL for this Title.
Definition: Title.php:2110
Title\getFullURL
getFullURL( $query='', $query2=false, $proto=PROTO_RELATIVE)
Get a real URL referring to this title, with interwiki link and fragment.
Definition: Title.php:1879
wfFindFile
wfFindFile( $title, $options=[])
Find a file.
Definition: GlobalFunctions.php:2677
Title\isKnown
isKnown()
Does this title refer to a page that can (or might) be meaningfully viewed? In particular,...
Definition: Title.php:4112
$wgArticlePath
$wgArticlePath
Definition: img_auth.php:46
text
This list may contain false positives That usually means there is additional text with links below the first Each row contains links to the first and second as well as the first line of the second redirect text
Definition: All_system_messages.txt:1267
article
and how to run hooks for an and one after Each event has a preferably in CamelCase For ArticleDelete hook A clump of code and data that should be run when an event happens This can be either a function and a chunk of or an object and a method hook function The function part of a third party developers and administrators to define code that will be run at certain points in the mainline and to modify the data run by that mainline code Hooks can keep mainline code and make it easier to write extensions Hooks are a principled alternative to patches for two options in MediaWiki One reverses the order of a title before displaying the article
Definition: hooks.txt:23
Title\getFirstRevision
getFirstRevision( $flags=0)
Get the first revision of the page.
Definition: Title.php:3778
Title\getAllRestrictions
getAllRestrictions()
Accessor/initialisation for mRestrictions.
Definition: Title.php:2600
Title\getEarliestRevTime
getEarliestRevTime( $flags=0)
Get the oldest revision timestamp of this page.
Definition: Title.php:3805
$parent
$parent
Definition: pageupdater.txt:71
Title
Represents a title within MediaWiki.
Definition: Title.php:40
Title\$mCascadingRestrictions
$mCascadingRestrictions
Caching the results of getCascadeProtectionSources.
Definition: Title.php:133
Title\getCascadeProtectionSources
getCascadeProtectionSources( $getPages=true)
Cascading protection: Get the source of any cascading restrictions on this page.
Definition: Title.php:2487
$cache
$cache
Definition: mcc.php:33
$rows
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction $rows
Definition: hooks.txt:2636
$wgSemiprotectedRestrictionLevels
$wgSemiprotectedRestrictionLevels
Restriction levels that should be considered "semiprotected".
Definition: DefaultSettings.php:5325
Title\getRestrictionTypes
getRestrictionTypes()
Returns restriction types for the current Title.
Definition: Title.php:2263
MalformedTitleException
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Definition: MalformedTitleException.php:25
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1985
Title\getTitleProtectionInternal
getTitleProtectionInternal()
Fetch title protection settings.
Definition: Title.php:2313
Wikimedia\Rdbms\IDatabase\addQuotes
addQuotes( $s)
Adds quotes and backslashes.
Title\getTemplateLinksFrom
getTemplateLinksFrom( $options=[])
Get an array of Title objects used on this Title as a template Also stores the IDs in the link cache.
Definition: Title.php:3284
Title\isRedirect
isRedirect( $flags=0)
Is this an article that is a redirect page? Uses link cache, adding it if necessary.
Definition: Title.php:2978
DeferredUpdates\PRESEND
const PRESEND
Definition: DeferredUpdates.php:63
MWNamespace\equals
static equals( $ns1, $ns2)
Returns whether the specified namespaces are the same namespace.
Definition: MWNamespace.php:202
Title\$mArticleID
int $mArticleID
Article ID, fetched from the link cache on demand.
Definition: Title.php:98
Title\isDeleted
isDeleted()
Is there a version of this page in the deletion archive?
Definition: Title.php:2903
Title\capitalize
static capitalize( $text, $ns=NS_MAIN)
Capitalize a text string for a title if it belongs to a namespace that capitalizes.
Definition: Title.php:3110
Title\$mDefaultNamespace
int $mDefaultNamespace
Namespace index when there is no namespace.
Definition: Title.php:165
Title\$mLength
int $mLength
The page length, 0 for special pages.
Definition: Title.php:168
Title\$mEstimateRevisions
int $mEstimateRevisions
Estimated number of revisions; null of not loaded.
Definition: Title.php:116
Title\hasSubjectNamespace
hasSubjectNamespace( $ns)
Returns true if the title has the same subject namespace as the namespace specified.
Definition: Title.php:1219
Title\isSpecialPage
isSpecialPage()
Returns true if this is a special page.
Definition: Title.php:1128
Title\purgeSquid
purgeSquid()
Purge all applicable CDN URLs.
Definition: Title.php:3362
Title\getPreviousRevisionID
getPreviousRevisionID( $revId, $flags=0)
Get the revision ID of the previous revision.
Definition: Title.php:3757
TitleArray
The TitleArray class only exists to provide the newFromResult method at pre- sent.
Definition: TitleArray.php:33
$rev
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1769
Title\getPageLanguage
getPageLanguage()
Get the language in which the content of this page is written in wikitext.
Definition: Title.php:4475
Title\CACHE_MAX
const CACHE_MAX
Title::newFromText maintains a cache to avoid expensive re-normalization of commonly used titles.
Definition: Title.php:49
Title\getEditNotices
getEditNotices( $oldid=0)
Get a list of rendered edit notices for this page.
Definition: Title.php:4557
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
Title\getTouched
getTouched( $db=null)
Get the last touched timestamp.
Definition: Title.php:4260
MWNamespace\isCapitalized
static isCapitalized( $index)
Is the namespace first-letter capitalized?
Definition: MWNamespace.php:419
Wikimedia\Rdbms\IDatabase\selectFieldValues
selectFieldValues( $table, $var, $cond='', $fname=__METHOD__, $options=[], $join_conds=[])
A SELECT wrapper which returns a list of single field values from result rows.
$wgRestrictionLevels
$wgRestrictionLevels
Rights which can be required for each protection level (via action=protect)
Definition: DefaultSettings.php:5300
Title\getFragmentForURL
getFragmentForURL()
Get the fragment in URL form, including the "#" character if there is one.
Definition: Title.php:1568
Title\exists
exists( $flags=0)
Check if page exists.
Definition: Title.php:4036
NS_USER
const NS_USER
Definition: Defines.php:66
$content
$content
Definition: pageupdater.txt:72
Title\isAlwaysKnown
isAlwaysKnown()
Should links to this title be shown as potentially viewable (i.e.
Definition: Title.php:4058
Title\isDeletedQuick
isDeletedQuick()
Is there a version of this page in the deletion archive?
Definition: Title.php:2928
Title\getSubpageUrlForm
getSubpageUrlForm()
Get a URL-encoded form of the subpage text.
Definition: Title.php:1811
MapCacheLRU\clear
clear( $keys=null)
Clear one or several cache entries, or all cache entries.
Definition: MapCacheLRU.php:277
Language\factory
static factory( $code)
Get a cached or new language object for a given language code.
Definition: Language.php:215
Title\isNewPage
isNewPage()
Check if this is a new page.
Definition: Title.php:3815
$wgRestrictionTypes
$wgRestrictionTypes
Set of available actions that can be restricted via action=protect You probably shouldn't change this...
Definition: DefaultSettings.php:5287
Title\setContentModel
setContentModel( $model)
Set a proposed content model for the page for permissions checking.
Definition: Title.php:1044
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:72
CONTENT_MODEL_JAVASCRIPT
const CONTENT_MODEL_JAVASCRIPT
Definition: Defines.php:236
Title\compare
static compare(LinkTarget $a, LinkTarget $b)
Callback for usort() to do title sorts by (namespace, title)
Definition: Title.php:814
Title\countAuthorsBetween
countAuthorsBetween( $old, $new, $limit, $options=[])
Get the number of authors between the given revisions or revision IDs.
Definition: Title.php:3995
$t
$t
Definition: testCompression.php:69
Title\legalChars
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition: Title.php:669
Title\isSiteJsConfigPage
isSiteJsConfigPage()
Is this a sitewide JS "config" page?
Definition: Title.php:1433
MWNamespace\isWatchable
static isWatchable( $index)
Can pages in a namespace be watched?
Definition: MWNamespace.php:356
Title\invalidateCache
invalidateCache( $purgeTime=null)
Updates page_touched for this page; called from LinksUpdate.php.
Definition: Title.php:4202
$wgRequest
if(! $wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:728
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
Title\isTrans
isTrans()
Determine whether the object refers to a page within this project and is transcludable.
Definition: Title.php:899
Title\getRestrictions
getRestrictions( $action)
Accessor/initialisation for mRestrictions.
Definition: Title.php:2586
MWNamespace\getTalk
static getTalk( $index)
Get the talk namespace index for a given namespace.
Definition: MWNamespace.php:130
wfMessage
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
MWNamespace\getSubject
static getSubject( $index)
Get the subject namespace index for a given namespace Special namespaces (NS_MEDIA,...
Definition: MWNamespace.php:144
CommentStore\getStore
static getStore()
Definition: CommentStore.php:130
Title\isContentPage
isContentPage()
Is this Title in a namespace which contains content? In other words, is this a content page,...
Definition: Title.php:1230
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:48
wfLocalFile
wfLocalFile( $title)
Get an object referring to a locally registered file.
Definition: GlobalFunctions.php:2688
Title\$titleCache
static MapCacheLRU null $titleCache
Definition: Title.php:42
Title\newFromID
static newFromID( $id, $flags=0)
Create a new Title from an article ID.
Definition: Title.php:457
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
$wgVariantArticlePath
$wgVariantArticlePath
Like $wgArticlePath, but on multi-variant wikis, this provides a path format that describes which par...
Definition: DefaultSettings.php:3131
Title\getUserCaseDBKey
getUserCaseDBKey()
Get the DB key with the initial letter case as specified by the user.
Definition: Title.php:980
Title\isRawHtmlMessage
isRawHtmlMessage()
Is this a message which can contain raw HTML?
Definition: Title.php:1451
Title\getSelectFields
static getSelectFields()
Returns a list of fields that are to be selected for initializing Title objects or LinkCache entries.
Definition: Title.php:431
Title\hasSubpages
hasSubpages()
Does this have subpages? (Warning, usually requires an extra DB query.)
Definition: Title.php:2848
Title\getBaseText
getBaseText()
Get the base page name without a namespace, i.e.
Definition: Title.php:1739
Title\pageCond
pageCond()
Get an associative array for selecting this title from the "page" table.
Definition: Title.php:3685
Title\getText
getText()
Get the text form (spaces not underscores) of the main part.
Definition: Title.php:952
MWNamespace\getCanonicalName
static getCanonicalName( $index)
Returns the canonical (English) name for a given index.
Definition: MWNamespace.php:256
Title\$mTextform
string $mTextform
Text form (spaces not underscores) of the main part.
Definition: Title.php:74
Wikimedia\Rdbms\IDatabase\delete
delete( $table, $conds, $fname=__METHOD__)
DELETE query wrapper.
Title\purgeExpiredRestrictions
static purgeExpiredRestrictions()
Purge expired restrictions from the page_restrictions table.
Definition: Title.php:2807
$wgInternalServer
$wgInternalServer
Internal server name as known to CDN, if different.
Definition: DefaultSettings.php:2742
Title\$mLatestID
bool int $mLatestID
ID of most recent revision.
Definition: Title.php:101
Title\$mRestrictionsLoaded
bool $mRestrictionsLoaded
Boolean for initialisation on demand.
Definition: Title.php:145
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:515
Title\getSubjectNsText
getSubjectNsText()
Get the namespace text of the subject (rather than talk) page.
Definition: Title.php:1078
Title\getUserPermissionsErrors
getUserPermissionsErrors( $action, $user, $rigor=PermissionManager::RIGOR_SECURE, $ignoreErrors=[])
Can $user perform $action on this page?
Definition: Title.php:2196
Title\$mTitleProtection
mixed $mTitleProtection
Cached value for getTitleProtection (create protection)
Definition: Title.php:158
TitleValue
Represents a page (or page fragment) title within MediaWiki.
Definition: TitleValue.php:36
Title\newFromTitleValue
static newFromTitleValue(TitleValue $titleValue, $forceClone='')
Returns a Title given a TitleValue.
Definition: Title.php:254
Title\getRelativeRevisionID
getRelativeRevisionID( $revId, $flags, $dir)
Get next/previous revision ID relative to another revision ID.
Definition: Title.php:3701
names
alter the names
Definition: COPYING.txt:329
wfArrayToCgi
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
Definition: GlobalFunctions.php:371
Title\getFullUrlForRedirect
getFullUrlForRedirect( $query='', $proto=PROTO_CURRENT)
Get a url appropriate for making redirects based on an untrusted url arg.
Definition: Title.php:1914
Title\getRootTitle
getRootTitle()
Get the root page name title, i.e.
Definition: Title.php:1724
$type
$type
Definition: testCompression.php:48
Title\getLength
getLength( $flags=0)
What is the length of this page? Uses link cache, adding it if necessary.
Definition: Title.php:3013
Title\getAuthorsBetween
getAuthorsBetween( $old, $new, $limit, $options=[])
Get the authors between the given revisions or revision IDs.
Definition: Title.php:3920
Title\isWatchable
isWatchable()
Can this title be added to a user's watchlist?
Definition: Title.php:1119