ILIAS  release_7 Revision v7.30-3-g800a261c036
Title.php
Go to the documentation of this file.
1<?php
8if (!class_exists('UtfNormal')) {
9 require_once('include/Unicode/UtfNormal.php');
10}
11
12
13// patched: alex, 30.4.2019: Added missing defines
14
15define('NS_MAIN', "nsmain");
16define('NS_SPECIAL', "nsspecial");
17
18define('GAID_FOR_UPDATE', 1);
19
20# Title::newFromTitle maintains a cache to avoid
21# expensive re-normalization of commonly used titles.
22# On a batch operation this can become a memory leak
23# if not bounded. After hitting this many titles,
24# reset the cache.
25define('MW_TITLECACHE_MAX', 1000);
26
27# Constants for pr_cascade bitfield
28define('CASCADE', 1);
29
36class Title
37{
41 private static $titleCache = array();
42 private static $interwikiCache = array();
43
44
54 public $mTextform; # Text form (spaces not underscores) of the main part
55 public $mUrlform; # URL-encoded form of the main part
56 public $mDbkeyform; # Main part with underscores
57 public $mNamespace; # Namespace index, i.e. one of the NS_xxxx constants
58 public $mInterwiki; # Interwiki prefix (or null string)
59 public $mFragment; # Title fragment (i.e. the bit after the #)
60 public $mArticleID; # Article ID, fetched from the link cache on demand
61 public $mLatestID; # ID of most recent revision
62 public $mRestrictions; # Array of groups allowed to edit this article
63 public $mCascadeRestriction; # Cascade restrictions on this page to included templates and images?
64 public $mRestrictionsExpiry; # When do the restrictions on this page expire?
65 public $mHasCascadingRestrictions; # Are cascading restrictions in effect on this page?
66 public $mCascadeRestrictionSources;# Where are the cascading restrictions coming from on this page?
67 public $mRestrictionsLoaded; # Boolean for initialisation on demand
68 public $mPrefixedText; # Text form including namespace/interwiki, initialised on demand
69 public $mDefaultNamespace; # Namespace index when there is no namespace
70 # Zero except in {{transclusion}} tags
71 public $mWatched; # Is $wgUser watching this page? NULL if unfilled, accessed through userIsWatching()
79 /* private */ public function __construct()
80 {
81 $this->mInterwiki = $this->mUrlform =
82 $this->mTextform = $this->mDbkeyform = '';
83 $this->mArticleID = -1;
84 $this->mNamespace = NS_MAIN;
85 $this->mRestrictionsLoaded = false;
86 $this->mRestrictions = array();
87 # Dont change the following, NS_MAIN is hardcoded in several place
88 # See bug #696
89 $this->mDefaultNamespace = NS_MAIN;
90 $this->mWatched = null;
91 $this->mLatestID = false;
92 $this->mOldRestrictions = false;
93 }
94
102 public static function newFromDBkey($key)
103 {
104 $t = new Title();
105 $t->mDbkeyform = $key;
106 if ($t->secureAndSplit()) {
107 return $t;
108 } else {
109 return null;
110 }
111 }
112
124 public static function newFromText($text, $defaultNamespace = NS_MAIN)
125 {
126 if (is_object($text)) {
127 throw new MWException('Title::newFromText given an object');
128 }
129
138 if ($defaultNamespace == NS_MAIN && isset(Title::$titleCache[$text])) {
139 return Title::$titleCache[$text];
140 }
141
145 $filteredText = Sanitizer::decodeCharReferences($text);
146
147 $t = new Title();
148 $t->mDbkeyform = str_replace(' ', '_', $filteredText);
149 $t->mDefaultNamespace = $defaultNamespace;
150
151 static $cachedcount = 0 ;
152 if ($t->secureAndSplit()) {
153 if ($defaultNamespace == NS_MAIN) {
154 if ($cachedcount >= MW_TITLECACHE_MAX) {
155 # Avoid memory leaks on mass operations...
156 Title::$titleCache = array();
157 $cachedcount = 0;
158 }
159 $cachedcount++;
160 Title::$titleCache[$text] = &$t;
161 }
162 return $t;
163 } else {
164 $ret = null;
165 return $ret;
166 }
167 }
168
175 public static function newFromURL($url)
176 {
177 global $wgLegalTitleChars;
178 $t = new Title();
179
180 # For compatibility with old buggy URLs. "+" is usually not valid in titles,
181 # but some URLs used it as a space replacement and they still come
182 # from some external search tools.
183 if (strpos($wgLegalTitleChars, '+') === false) {
184 $url = str_replace('+', ' ', $url);
185 }
186
187 $t->mDbkeyform = str_replace(' ', '_', $url);
188 if ($t->secureAndSplit()) {
189 return $t;
190 } else {
191 return null;
192 }
193 }
194
204 public static function newFromID($id)
205 {
206 $fname = 'Title::newFromID';
207 $dbr = wfGetDB(DB_SLAVE);
208 $row = $dbr->selectRow(
209 'page',
210 array( 'page_namespace', 'page_title' ),
211 array( 'page_id' => $id ),
212 $fname
213 );
214 if ($row !== false) {
215 $title = Title::makeTitle($row->page_namespace, $row->page_title);
216 } else {
217 $title = null;
218 }
219 return $title;
220 }
221
225 public static function newFromIDs($ids)
226 {
227 $dbr = wfGetDB(DB_SLAVE);
228 $res = $dbr->select(
229 'page',
230 array( 'page_namespace', 'page_title' ),
231 'page_id IN (' . $dbr->makeList($ids) . ')',
232 __METHOD__
233 );
234
235 $titles = array();
236 while ($row = $dbr->fetchObject($res)) {
237 $titles[] = Title::makeTitle($row->page_namespace, $row->page_title);
238 }
239 return $titles;
240 }
241
253 public static function &makeTitle($ns, $title)
254 {
255 $t = new Title();
256 $t->mInterwiki = '';
257 $t->mFragment = '';
258 $t->mNamespace = intval($ns);
259 $t->mDbkeyform = str_replace(' ', '_', $title);
260 $t->mArticleID = ($ns >= 0) ? -1 : 0;
261 $t->mUrlform = wfUrlencode($t->mDbkeyform);
262 $t->mTextform = str_replace('_', ' ', $title);
263 return $t;
264 }
265
275 public static function makeTitleSafe($ns, $title)
276 {
277 $t = new Title();
278 $t->mDbkeyform = Title::makeName($ns, $title);
279 if ($t->secureAndSplit()) {
280 return $t;
281 } else {
282 return null;
283 }
284 }
285
290 public static function newMainPage()
291 {
292 return Title::newFromText(wfMsgForContent('mainpage'));
293 }
294
301 public static function newFromRedirect($text)
302 {
303 $mwRedir = MagicWord::get('redirect');
304 $rt = null;
305 if ($mwRedir->matchStart($text)) {
306 $m = array();
307 if (preg_match('/\[{2}(.*?)(?:\||\]{2})/', $text, $m)) {
308 # categories are escaped using : for example one can enter:
309 # #REDIRECT [[:Category:Music]]. Need to remove it.
310 if (substr($m[1], 0, 1) == ':') {
311 # We don't want to keep the ':'
312 $m[1] = substr($m[1], 1);
313 }
314
315 $rt = Title::newFromText($m[1]);
316 # Disallow redirects to Special:Userlogout
317 if (!is_null($rt) && $rt->isSpecial('Userlogout')) {
318 $rt = null;
319 }
320 }
321 }
322 return $rt;
323 }
324
325 #----------------------------------------------------------------------------
326 # Static functions
327 #----------------------------------------------------------------------------
328
337 public function nameOf($id)
338 {
339 $fname = 'Title::nameOf';
340 $dbr = wfGetDB(DB_SLAVE);
341
342 $s = $dbr->selectRow('page', array( 'page_namespace','page_title' ), array( 'page_id' => $id ), $fname);
343 if ($s === false) {
344 return null;
345 }
346
347 $n = Title::makeName($s->page_namespace, $s->page_title);
348 return $n;
349 }
350
355 public static function legalChars()
356 {
357 global $wgLegalTitleChars;
358
359 $wgLegalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+";
360
361 return $wgLegalTitleChars;
362 }
363
373 public static function indexTitle($ns, $title)
374 {
375 global $wgContLang;
376
377 $lc = SearchEngine::legalSearchChars() . '&#;';
378 $t = $wgContLang->stripForSearch($title);
379 $t = preg_replace("/[^{$lc}]+/", ' ', $t);
380 $t = $wgContLang->lc($t);
381
382 # Handle 's, s'
383 $t = preg_replace("/([{$lc}]+)'s( |$)/", "\\1 \\1's ", $t);
384 $t = preg_replace("/([{$lc}]+)s'( |$)/", "\\1s ", $t);
385
386 $t = preg_replace("/\\s+/", ' ', $t);
387
388 if ($ns == NS_IMAGE) {
389 $t = preg_replace("/ (png|gif|jpg|jpeg|ogg)$/", "", $t);
390 }
391 return trim($t);
392 }
393
394 /*
395 * Make a prefixed DB key from a DB key and a namespace index
396 * @param int $ns numerical representation of the namespace
397 * @param string $title the DB key form the title
398 * @return string the prefixed form of the title
399 */
400 public static function makeName($ns, $title)
401 {
402 global $wgContLang;
403
404 $n = $wgContLang->getNsText($ns);
405 return $n == '' ? $title : "$n:$title";
406 }
407
415 public function getInterwikiLink($key)
416 {
417 global $wgMemc, $wgInterwikiExpiry;
418 global $wgInterwikiCache, $wgContLang;
419
420 return ""; // changed. alex
421
422 $fname = 'Title::getInterwikiLink';
423
424 $key = $wgContLang->lc($key);
425
426 $k = wfMemcKey('interwiki', $key);
427 if (array_key_exists($k, Title::$interwikiCache)) {
428 return Title::$interwikiCache[$k]->iw_url;
429 }
430
431 if ($wgInterwikiCache) {
432 return Title::getInterwikiCached($key);
433 }
434
435 $s = $wgMemc->get($k);
436 # Ignore old keys with no iw_local
437 if ($s && isset($s->iw_local) && isset($s->iw_trans)) {
438 Title::$interwikiCache[$k] = $s;
439 return $s->iw_url;
440 }
441
442 $dbr = wfGetDB(DB_SLAVE);
443 $res = $dbr->select(
444 'interwiki',
445 array( 'iw_url', 'iw_local', 'iw_trans' ),
446 array( 'iw_prefix' => $key ),
447 $fname
448 );
449 if (!$res) {
450 return '';
451 }
452
453 $s = $dbr->fetchObject($res);
454 if (!$s) {
455 # Cache non-existence: create a blank object and save it to memcached
456 $s = (object) false;
457 $s->iw_url = '';
458 $s->iw_local = 0;
459 $s->iw_trans = 0;
460 }
461 $wgMemc->set($k, $s, $wgInterwikiExpiry);
462 Title::$interwikiCache[$k] = $s;
463
464 return $s->iw_url;
465 }
466
474 public static function getInterwikiCached($key)
475 {
476 global $wgInterwikiCache, $wgInterwikiScopes, $wgInterwikiFallbackSite;
477 static $db, $site;
478
479 if (!$db) {
480 $db = dba_open($wgInterwikiCache, 'r', 'cdb');
481 }
482 /* Resolve site name */
483 if ($wgInterwikiScopes >= 3 and !$site) {
484 $site = dba_fetch('__sites:' . wfWikiID(), $db);
485 if ($site == "") {
486 $site = $wgInterwikiFallbackSite;
487 }
488 }
489 $value = dba_fetch(wfMemcKey($key), $db);
490 if ($value == '' and $wgInterwikiScopes >= 3) {
491 /* try site-level */
492 $value = dba_fetch("_{$site}:{$key}", $db);
493 }
494 if ($value == '' and $wgInterwikiScopes >= 2) {
495 /* try globals */
496 $value = dba_fetch("__global:{$key}", $db);
497 }
498 if ($value == 'undef') {
499 $value = '';
500 }
501 $s = (object) false;
502 $s->iw_url = '';
503 $s->iw_local = 0;
504 $s->iw_trans = 0;
505 if ($value != '') {
506 list($local, $url) = explode(' ', $value, 2);
507 $s->iw_url = $url;
508 $s->iw_local = (int) $local;
509 }
510 Title::$interwikiCache[wfMemcKey('interwiki', $key)] = $s;
511 return $s->iw_url;
512 }
520 public function isLocal()
521 {
522 if ($this->mInterwiki != '') {
523 # Make sure key is loaded into cache
524 $this->getInterwikiLink($this->mInterwiki);
525 $k = wfMemcKey('interwiki', $this->mInterwiki);
526 return (bool) (Title::$interwikiCache[$k]->iw_local);
527 } else {
528 return true;
529 }
530 }
531
538 public function isTrans()
539 {
540 if ($this->mInterwiki == '') {
541 return false;
542 }
543 # Make sure key is loaded into cache
544 $this->getInterwikiLink($this->mInterwiki);
545 $k = wfMemcKey('interwiki', $this->mInterwiki);
546 return (bool) (Title::$interwikiCache[$k]->iw_trans);
547 }
548
552 public static function escapeFragmentForURL($fragment)
553 {
554 $fragment = str_replace(' ', '_', $fragment);
555 $fragment = urlencode(Sanitizer::decodeCharReferences($fragment));
556 $replaceArray = array(
557 '%3A' => ':',
558 '%' => '.'
559 );
560 return strtr($fragment, $replaceArray);
561 }
562
563 #----------------------------------------------------------------------------
564 # Other stuff
565 #----------------------------------------------------------------------------
566
572 public function getText()
573 {
574 return $this->mTextform;
575 }
580 public function getPartialURL()
581 {
582 return $this->mUrlform;
583 }
588 public function getDBkey()
589 {
590 return $this->mDbkeyform;
591 }
596 public function getNamespace()
597 {
598 return $this->mNamespace;
599 }
604 public function getNsText()
605 {
606 global $wgContLang, $wgCanonicalNamespaceNames;
607
608 if ('' != $this->mInterwiki) {
609 // This probably shouldn't even happen. ohh man, oh yuck.
610 // But for interwiki transclusion it sometimes does.
611 // Shit. Shit shit shit.
612 //
613 // Use the canonical namespaces if possible to try to
614 // resolve a foreign namespace.
615 if (isset($wgCanonicalNamespaceNames[$this->mNamespace])) {
616 return $wgCanonicalNamespaceNames[$this->mNamespace];
617 }
618 }
619 return $wgContLang->getNsText($this->mNamespace);
620 }
625 /* public function getSubjectNsText() {
626 global $wgContLang;
627 return $wgContLang->getNsText( Namespace::getSubject( $this->mNamespace ) );
628 }*/
629
634 /* public function getTalkNsText() {
635 global $wgContLang;
636 return( $wgContLang->getNsText( Namespace::getTalk( $this->mNamespace ) ) );
637 }*/
638
643 /* public function canTalk() {
644 return( Namespace::canTalk( $this->mNamespace ) );
645 }*/
646
651 public function getInterwiki()
652 {
653 return $this->mInterwiki;
654 }
659 public function getFragment()
660 {
661 return $this->mFragment;
662 }
667 public function getFragmentForURL()
668 {
669 if ($this->mFragment == '') {
670 return '';
671 } else {
672 return '#' . Title::escapeFragmentForURL($this->mFragment);
673 }
674 }
679 public function getDefaultNamespace()
680 {
682 }
683
689 public function getIndexTitle()
690 {
691 return Title::indexTitle($this->mNamespace, $this->mTextform);
692 }
693
699 public function getPrefixedDBkey()
700 {
701 $s = $this->prefix($this->mDbkeyform);
702 $s = str_replace(' ', '_', $s);
703 return $s;
704 }
705
711 public function getPrefixedText()
712 {
713 if (empty($this->mPrefixedText)) { // FIXME: bad usage of empty() ?
714 $s = $this->prefix($this->mTextform);
715 $s = str_replace('_', ' ', $s);
716 $this->mPrefixedText = $s;
717 }
719 }
720
727 public function getFullText()
728 {
729 $text = $this->getPrefixedText();
730 if ('' != $this->mFragment) {
731 $text .= '#' . $this->mFragment;
732 }
733 return $text;
734 }
735
740 public function getBaseText()
741 {
742 global $wgNamespacesWithSubpages;
743 if (isset($wgNamespacesWithSubpages[ $this->mNamespace ]) && $wgNamespacesWithSubpages[ $this->mNamespace ]) {
744 $parts = explode('/', $this->getText());
745 # Don't discard the real title if there's no subpage involved
746 if (count($parts) > 1) {
747 unset($parts[ count($parts) - 1 ]);
748 }
749 return implode('/', $parts);
750 } else {
751 return $this->getText();
752 }
753 }
754
759 public function getSubpageText()
760 {
761 global $wgNamespacesWithSubpages;
762 if (isset($wgNamespacesWithSubpages[ $this->mNamespace ]) && $wgNamespacesWithSubpages[ $this->mNamespace ]) {
763 $parts = explode('/', $this->mTextform);
764 return($parts[ count($parts) - 1 ]);
765 } else {
766 return($this->mTextform);
767 }
768 }
769
774 public function getSubpageUrlForm()
775 {
776 $text = $this->getSubpageText();
777 $text = wfUrlencode(str_replace(' ', '_', $text));
778 $text = str_replace('%28', '(', str_replace('%29', ')', $text)); # Clean up the URL; per below, this might not be safe
779 return($text);
780 }
781
786 public function getPrefixedURL()
787 {
788 $s = $this->prefix($this->mDbkeyform);
789 $s = str_replace(' ', '_', $s);
790
791 $s = wfUrlencode($s) ;
792
793 # Cleaning up URL to make it look nice -- is this safe?
794 $s = str_replace('%28', '(', $s);
795 $s = str_replace('%29', ')', $s);
796
797 return $s;
798 }
799
809 public function getFullURL($query = '', $variant = false)
810 {
811 global $wgContLang, $wgServer, $wgRequest;
812
813 if ('' == $this->mInterwiki) {
814 $url = $this->getLocalUrl($query, $variant);
815
816 // Ugly quick hack to avoid duplicate prefixes (bug 4571 etc)
817 // Correct fix would be to move the prepending elsewhere.
818 if ($wgRequest->getVal('action') != 'render') {
819 $url = $wgServer . $url;
820 }
821 } else {
822 $baseUrl = $this->getInterwikiLink($this->mInterwiki);
823
824 $namespace = wfUrlencode($this->getNsText());
825 if ('' != $namespace) {
826 # Can this actually happen? Interwikis shouldn't be parsed.
827 # Yes! It can in interwiki transclusion. But... it probably shouldn't.
828 $namespace .= ':';
829 }
830 $url = str_replace('$1', $namespace . $this->mUrlform, $baseUrl);
831 $url = wfAppendQuery($url, $query);
832 }
833
834 # Finally, add the fragment.
835 $url .= $this->getFragmentForURL();
836
837 wfRunHooks('GetFullURL', array( &$this, &$url, $query ));
838 return $url;
839 }
840
849 public function getLocalURL($query = '', $variant = false)
850 {
851 global $wgArticlePath, $wgScript, $wgServer, $wgRequest;
852 global $wgVariantArticlePath, $wgContLang, $wgUser;
853
854 // internal links should point to same variant as current page (only anonymous users)
855 if ($variant == false && $wgContLang->hasVariants() && !$wgUser->isLoggedIn()) {
856 $pref = $wgContLang->getPreferredVariant(false);
857 if ($pref != $wgContLang->getCode()) {
858 $variant = $pref;
859 }
860 }
861
862 if ($this->isExternal()) {
863 $url = $this->getFullURL();
864 if ($query) {
865 // This is currently only used for edit section links in the
866 // context of interwiki transclusion. In theory we should
867 // append the query to the end of any existing query string,
868 // but interwiki transclusion is already broken in that case.
869 $url .= "?$query";
870 }
871 } else {
872 $dbkey = wfUrlencode($this->getPrefixedDBkey());
873 if ($query == '') {
874 if ($variant != false && $wgContLang->hasVariants()) {
875 if ($wgVariantArticlePath == false) {
876 $variantArticlePath = "$wgScript?title=$1&variant=$2"; // default
877 } else {
878 $variantArticlePath = $wgVariantArticlePath;
879 }
880 $url = str_replace('$2', urlencode($variant), $variantArticlePath);
881 $url = str_replace('$1', $dbkey, $url);
882 } else {
883 $url = str_replace('$1', $dbkey, $wgArticlePath);
884 }
885 } else {
886 global $wgActionPaths;
887 $url = false;
888 $matches = array();
889 if (!empty($wgActionPaths) &&
890 preg_match('/^(.*&|)action=([^&]*)(&(.*)|)$/', $query, $matches)) {
891 $action = urldecode($matches[2]);
892 if (isset($wgActionPaths[$action])) {
893 $query = $matches[1];
894 if (isset($matches[4])) {
895 $query .= $matches[4];
896 }
897 $url = str_replace('$1', $dbkey, $wgActionPaths[$action]);
898 if ($query != '') {
899 $url .= '?' . $query;
900 }
901 }
902 }
903 if ($url === false) {
904 if ($query == '-') {
905 $query = '';
906 }
907 $url = "{$wgScript}?title={$dbkey}&{$query}";
908 }
909 }
910
911 // FIXME: this causes breakage in various places when we
912 // actually expected a local URL and end up with dupe prefixes.
913 if ($wgRequest->getVal('action') == 'render') {
914 $url = $wgServer . $url;
915 }
916 }
917 wfRunHooks('GetLocalURL', array( &$this, &$url, $query ));
918 return $url;
919 }
920
927 public function escapeLocalURL($query = '')
928 {
929 return htmlspecialchars($this->getLocalURL($query));
930 }
931
939 public function escapeFullURL($query = '')
940 {
941 return htmlspecialchars($this->getFullURL($query));
942 }
943
953 public function getInternalURL($query = '', $variant = false)
954 {
955 global $wgInternalServer;
956 $url = $wgInternalServer . $this->getLocalURL($query, $variant);
957 wfRunHooks('GetInternalURL', array( &$this, &$url, $query ));
958 return $url;
959 }
960
966 public function getEditURL()
967 {
968 if ('' != $this->mInterwiki) {
969 return '';
970 }
971 $s = $this->getLocalURL('action=edit');
972
973 return $s;
974 }
975
981 public function getEscapedText()
982 {
983 return htmlspecialchars($this->getPrefixedText());
984 }
985
990 public function isExternal()
991 {
992 return ('' != $this->mInterwiki);
993 }
994
1001 public function isSemiProtected($action = 'edit')
1002 {
1003 if ($this->exists()) {
1004 $restrictions = $this->getRestrictions($action);
1005 if (count($restrictions) > 0) {
1006 foreach ($restrictions as $restriction) {
1007 if (strtolower($restriction) != 'autoconfirmed') {
1008 return false;
1009 }
1010 }
1011 } else {
1012 # Not protected
1013 return false;
1014 }
1015 return true;
1016 } else {
1017 # If it doesn't exist, it can't be protected
1018 return false;
1019 }
1020 }
1021
1028 public function isProtected($action = '')
1029 {
1030 global $wgRestrictionLevels;
1031
1032 # Special pages have inherent protection
1033 if ($this->getNamespace() == NS_SPECIAL) {
1034 return true;
1035 }
1036
1037 # Check regular protection levels
1038 if ($action == 'edit' || $action == '') {
1039 $r = $this->getRestrictions('edit');
1040 foreach ($wgRestrictionLevels as $level) {
1041 if (in_array($level, $r) && $level != '') {
1042 return(true);
1043 }
1044 }
1045 }
1046
1047 if ($action == 'move' || $action == '') {
1048 $r = $this->getRestrictions('move');
1049 foreach ($wgRestrictionLevels as $level) {
1050 if (in_array($level, $r) && $level != '') {
1051 return(true);
1052 }
1053 }
1054 }
1055
1056 return false;
1057 }
1058
1063 public function userIsWatching()
1064 {
1065 global $wgUser;
1066
1067 if (is_null($this->mWatched)) {
1068 if (NS_SPECIAL == $this->mNamespace || !$wgUser->isLoggedIn()) {
1069 $this->mWatched = false;
1070 } else {
1071 $this->mWatched = $wgUser->isWatched($this);
1072 }
1073 }
1074 return $this->mWatched;
1075 }
1076
1089 public function quickUserCan($action)
1090 {
1091 return $this->userCan($action, false);
1092 }
1093
1100 public function userCan($action, $doExpensiveQueries = true)
1101 {
1102 $fname = 'Title::userCan';
1103 wfProfileIn($fname);
1104
1105 global $wgUser, $wgNamespaceProtection;
1106
1107 $result = null;
1108 wfRunHooks('userCan', array( &$this, &$wgUser, $action, &$result ));
1109 if ($result !== null) {
1110 wfProfileOut($fname);
1111 return $result;
1112 }
1113
1114 if (NS_SPECIAL == $this->mNamespace) {
1115 wfProfileOut($fname);
1116 return false;
1117 }
1118
1119 if (array_key_exists($this->mNamespace, $wgNamespaceProtection)) {
1120 $nsProt = $wgNamespaceProtection[ $this->mNamespace ];
1121 if (!is_array($nsProt)) {
1122 $nsProt = array($nsProt);
1123 }
1124 foreach ($nsProt as $right) {
1125 if ('' != $right && !$wgUser->isAllowed($right)) {
1126 wfProfileOut($fname);
1127 return false;
1128 }
1129 }
1130 }
1131
1132 if ($this->mDbkeyform == '_') {
1133 # FIXME: Is this necessary? Shouldn't be allowed anyway...
1134 wfProfileOut($fname);
1135 return false;
1136 }
1137
1138 # protect css/js subpages of user pages
1139 # XXX: this might be better using restrictions
1140 # XXX: Find a way to work around the php bug that prevents using $this->userCanEditCssJsSubpage() from working
1141 if ($this->isCssJsSubpage()
1142 && !$wgUser->isAllowed('editinterface')
1143 && !preg_match('/^' . preg_quote($wgUser->getName(), '/') . '\//', $this->mTextform)) {
1144 wfProfileOut($fname);
1145 return false;
1146 }
1147
1148 if ($doExpensiveQueries && !$this->isCssJsSubpage()) {
1149 # We /could/ use the protection level on the source page, but it's fairly ugly
1150 # as we have to establish a precedence hierarchy for pages included by multiple
1151 # cascade-protected pages. So just restrict it to people with 'protect' permission,
1152 # as they could remove the protection anyway.
1153 list($cascadingSources, $restrictions) = $this->getCascadeProtectionSources();
1154 # Cascading protection depends on more than this page...
1155 # Several cascading protected pages may include this page...
1156 # Check each cascading level
1157 # This is only for protection restrictions, not for all actions
1158 if ($cascadingSources > 0 && isset($restrictions[$action])) {
1159 foreach ($restrictions[$action] as $right) {
1160 $right = ($right == 'sysop') ? 'protect' : $right;
1161 if ('' != $right && !$wgUser->isAllowed($right)) {
1162 wfProfileOut($fname);
1163 return false;
1164 }
1165 }
1166 }
1167 }
1168
1169 foreach ($this->getRestrictions($action) as $right) {
1170 // Backwards compatibility, rewrite sysop -> protect
1171 if ($right == 'sysop') {
1172 $right = 'protect';
1173 }
1174 if ('' != $right && !$wgUser->isAllowed($right)) {
1175 wfProfileOut($fname);
1176 return false;
1177 }
1178 }
1179
1180 if ($action == 'move' &&
1181 !($this->isMovable() && $wgUser->isAllowed('move'))) {
1182 wfProfileOut($fname);
1183 return false;
1184 }
1185
1186 if ($action == 'create') {
1187 if (($this->isTalkPage() && !$wgUser->isAllowed('createtalk')) ||
1188 (!$this->isTalkPage() && !$wgUser->isAllowed('createpage'))) {
1189 wfProfileOut($fname);
1190 return false;
1191 }
1192 }
1193
1194 wfProfileOut($fname);
1195 return true;
1196 }
1197
1203 public function userCanEdit($doExpensiveQueries = true)
1204 {
1205 return $this->userCan('edit', $doExpensiveQueries);
1206 }
1207
1213 public function userCanCreate($doExpensiveQueries = true)
1214 {
1215 return $this->userCan('create', $doExpensiveQueries);
1216 }
1217
1223 public function userCanMove($doExpensiveQueries = true)
1224 {
1225 return $this->userCan('move', $doExpensiveQueries);
1226 }
1227
1234 /* public function isMovable() {
1235 return Namespace::isMovable( $this->getNamespace() )
1236 && $this->getInterwiki() == '';
1237 }*/
1238
1244 public function userCanRead()
1245 {
1246 global $wgUser;
1247
1248 $result = null;
1249 wfRunHooks('userCan', array( &$this, &$wgUser, 'read', &$result ));
1250 if ($result !== null) {
1251 return $result;
1252 }
1253
1254 if ($wgUser->isAllowed('read')) {
1255 return true;
1256 } else {
1257 global $wgWhitelistRead;
1258
1263 if ($this->isSpecial('Userlogin') || $this->isSpecial('Resetpass')) {
1264 return true;
1265 }
1266
1268 $name = $this->getPrefixedText();
1269 if ($wgWhitelistRead && in_array($name, $wgWhitelistRead)) {
1270 return true;
1271 }
1272
1273 # Compatibility with old settings
1274 if ($wgWhitelistRead && $this->getNamespace() == NS_MAIN) {
1275 if (in_array(':' . $name, $wgWhitelistRead)) {
1276 return true;
1277 }
1278 }
1279 }
1280 return false;
1281 }
1282
1287 /* public function isTalkPage() {
1288 return Namespace::isTalk( $this->getNamespace() );
1289 }*/
1290
1295 public function isSubpage()
1296 {
1297 global $wgNamespacesWithSubpages;
1298
1299 if (isset($wgNamespacesWithSubpages[ $this->mNamespace ])) {
1300 return (strpos($this->getText(), '/') !== false && $wgNamespacesWithSubpages[ $this->mNamespace ] == true);
1301 } else {
1302 return false;
1303 }
1304 }
1305
1310 public function isCssJsSubpage()
1311 {
1312 return (NS_USER == $this->mNamespace and preg_match("/\\/.*\\.(?:css|js)$/", $this->mTextform));
1313 }
1318 public function isValidCssJsSubpage()
1319 {
1320 if ($this->isCssJsSubpage()) {
1321 $skinNames = Skin::getSkinNames();
1322 return array_key_exists($this->getSkinFromCssJsSubpage(), $skinNames);
1323 } else {
1324 return false;
1325 }
1326 }
1330 public function getSkinFromCssJsSubpage()
1331 {
1332 $subpage = explode('/', $this->mTextform);
1333 $subpage = $subpage[ count($subpage) - 1 ];
1334 return(str_replace(array( '.css', '.js' ), array( '', '' ), $subpage));
1335 }
1340 public function isCssSubpage()
1341 {
1342 return (NS_USER == $this->mNamespace and preg_match("/\\/.*\\.css$/", $this->mTextform));
1343 }
1348 public function isJsSubpage()
1349 {
1350 return (NS_USER == $this->mNamespace and preg_match("/\\/.*\\.js$/", $this->mTextform));
1351 }
1359 public function userCanEditCssJsSubpage()
1360 {
1361 global $wgUser;
1362 return ($wgUser->isAllowed('editinterface') or preg_match('/^' . preg_quote($wgUser->getName(), '/') . '\//', $this->mTextform));
1363 }
1364
1370 public function isCascadeProtected()
1371 {
1372 list($sources, $restrictions) = $this->getCascadeProtectionSources(false);
1373 return ($sources > 0);
1374 }
1375
1384 public function getCascadeProtectionSources($get_pages = true)
1385 {
1386 global $wgEnableCascadingProtection, $wgRestrictionTypes;
1387
1388 # Define our dimension of restrictions types
1389 $pagerestrictions = array();
1390 foreach ($wgRestrictionTypes as $action) {
1391 $pagerestrictions[$action] = array();
1392 }
1393
1394 if (!$wgEnableCascadingProtection) {
1395 return array( false, $pagerestrictions );
1396 }
1397
1398 if (isset($this->mCascadeSources) && $get_pages) {
1399 return array( $this->mCascadeSources, $this->mCascadingRestrictions );
1400 } elseif (isset($this->mHasCascadingRestrictions) && !$get_pages) {
1401 return array( $this->mHasCascadingRestrictions, $pagerestrictions );
1402 }
1403
1404 wfProfileIn(__METHOD__);
1405
1406 $dbr = wfGetDb(DB_SLAVE);
1407
1408 if ($this->getNamespace() == NS_IMAGE) {
1409 $tables = array('imagelinks', 'page_restrictions');
1410 $where_clauses = array(
1411 'il_to' => $this->getDBkey(),
1412 'il_from=pr_page',
1413 'pr_cascade' => 1 );
1414 } else {
1415 $tables = array('templatelinks', 'page_restrictions');
1416 $where_clauses = array(
1417 'tl_namespace' => $this->getNamespace(),
1418 'tl_title' => $this->getDBkey(),
1419 'tl_from=pr_page',
1420 'pr_cascade' => 1 );
1421 }
1422
1423 if ($get_pages) {
1424 $cols = array('pr_page', 'page_namespace', 'page_title', 'pr_expiry', 'pr_type', 'pr_level' );
1425 $where_clauses[] = 'page_id=pr_page';
1426 $tables[] = 'page';
1427 } else {
1428 $cols = array( 'pr_expiry' );
1429 }
1430
1431 $res = $dbr->select($tables, $cols, $where_clauses, __METHOD__);
1432
1433 $sources = $get_pages ? array() : false;
1434 $now = wfTimestampNow();
1435 $purgeExpired = false;
1436
1437 while ($row = $dbr->fetchObject($res)) {
1438 $expiry = Block::decodeExpiry($row->pr_expiry);
1439 if ($expiry > $now) {
1440 if ($get_pages) {
1441 $page_id = $row->pr_page;
1442 $page_ns = $row->page_namespace;
1443 $page_title = $row->page_title;
1444 $sources[$page_id] = Title::makeTitle($page_ns, $page_title);
1445 # Add groups needed for each restriction type if its not already there
1446 # Make sure this restriction type still exists
1447 if (isset($pagerestrictions[$row->pr_type]) && !in_array($row->pr_level, $pagerestrictions[$row->pr_type])) {
1448 $pagerestrictions[$row->pr_type][] = $row->pr_level;
1449 }
1450 } else {
1451 $sources = true;
1452 }
1453 } else {
1454 // Trigger lazy purge of expired restrictions from the db
1455 $purgeExpired = true;
1456 }
1457 }
1458 if ($purgeExpired) {
1460 }
1461
1462 wfProfileOut(__METHOD__);
1463
1464 if ($get_pages) {
1465 $this->mCascadeSources = $sources;
1466 $this->mCascadingRestrictions = $pagerestrictions;
1467 } else {
1468 $this->mHasCascadingRestrictions = $sources;
1469 }
1470
1471 return array( $sources, $pagerestrictions );
1472 }
1473
1475 {
1476 if (!$this->mRestrictionsLoaded) {
1477 $this->loadRestrictions();
1478 }
1479
1481 }
1482
1487 private function loadRestrictionsFromRow($res, $oldFashionedRestrictions = null)
1488 {
1489 $dbr = wfGetDb(DB_SLAVE);
1490
1491 $this->mRestrictions['edit'] = array();
1492 $this->mRestrictions['move'] = array();
1493
1494 # Backwards-compatibility: also load the restrictions from the page record (old format).
1495
1496 if ($oldFashionedRestrictions == null) {
1497 $oldFashionedRestrictions = $dbr->selectField('page', 'page_restrictions', array( 'page_id' => $this->getArticleId() ), __METHOD__);
1498 }
1499
1500 if ($oldFashionedRestrictions != '') {
1501 foreach (explode(':', trim($oldFashionedRestrictions)) as $restrict) {
1502 $temp = explode('=', trim($restrict));
1503 if (count($temp) == 1) {
1504 // old old format should be treated as edit/move restriction
1505 $this->mRestrictions["edit"] = explode(',', trim($temp[0]));
1506 $this->mRestrictions["move"] = explode(',', trim($temp[0]));
1507 } else {
1508 $this->mRestrictions[$temp[0]] = explode(',', trim($temp[1]));
1509 }
1510 }
1511
1512 $this->mOldRestrictions = true;
1513 $this->mCascadeRestriction = false;
1514 $this->mRestrictionsExpiry = Block::decodeExpiry('');
1515 }
1516
1517 if ($dbr->numRows($res)) {
1518 # Current system - load second to make them override.
1519 $now = wfTimestampNow();
1520 $purgeExpired = false;
1521
1522 while ($row = $dbr->fetchObject($res)) {
1523 # Cycle through all the restrictions.
1524
1525 // This code should be refactored, now that it's being used more generally,
1526 // But I don't really see any harm in leaving it in Block for now -werdna
1527 $expiry = Block::decodeExpiry($row->pr_expiry);
1528
1529 // Only apply the restrictions if they haven't expired!
1530 if (!$expiry || $expiry > $now) {
1531 $this->mRestrictionsExpiry = $expiry;
1532 $this->mRestrictions[$row->pr_type] = explode(',', trim($row->pr_level));
1533
1534 $this->mCascadeRestriction |= $row->pr_cascade;
1535 } else {
1536 // Trigger a lazy purge of expired restrictions
1537 $purgeExpired = true;
1538 }
1539 }
1540
1541 if ($purgeExpired) {
1543 }
1544 }
1545
1546 $this->mRestrictionsLoaded = true;
1547 }
1548
1549 public function loadRestrictions($oldFashionedRestrictions = null)
1550 {
1551 if (!$this->mRestrictionsLoaded) {
1552 $dbr = wfGetDB(DB_SLAVE);
1553
1554 $res = $dbr->select(
1555 'page_restrictions',
1556 '*',
1557 array( 'pr_page' => $this->getArticleId() ),
1558 __METHOD__
1559 );
1560
1561 $this->loadRestrictionsFromRow($res, $oldFashionedRestrictions);
1562 }
1563 }
1564
1568 public static function purgeExpiredRestrictions()
1569 {
1570 $dbw = wfGetDB(DB_MASTER);
1571 $dbw->delete(
1572 'page_restrictions',
1573 array( 'pr_expiry < ' . $dbw->addQuotes($dbw->timestamp()) ),
1574 __METHOD__
1575 );
1576 }
1577
1584 public function getRestrictions($action)
1585 {
1586 if ($this->exists()) {
1587 if (!$this->mRestrictionsLoaded) {
1588 $this->loadRestrictions();
1589 }
1590 return isset($this->mRestrictions[$action])
1591 ? $this->mRestrictions[$action]
1592 : array();
1593 } else {
1594 return array();
1595 }
1596 }
1597
1602 public function isDeleted()
1603 {
1604 $fname = 'Title::isDeleted';
1605 if ($this->getNamespace() < 0) {
1606 $n = 0;
1607 } else {
1608 $dbr = wfGetDB(DB_SLAVE);
1609 $n = $dbr->selectField('archive', 'COUNT(*)', array( 'ar_namespace' => $this->getNamespace(),
1610 'ar_title' => $this->getDBkey() ), $fname);
1611 if ($this->getNamespace() == NS_IMAGE) {
1612 $n += $dbr->selectField(
1613 'filearchive',
1614 'COUNT(*)',
1615 array( 'fa_name' => $this->getDBkey() ),
1616 $fname
1617 );
1618 }
1619 }
1620 return (int) $n;
1621 }
1622
1630 public function getArticleID($flags = 0)
1631 {
1632 $linkCache = &LinkCache::singleton();
1633 if ($flags & GAID_FOR_UPDATE) {
1634 $oldUpdate = $linkCache->forUpdate(true);
1635 $this->mArticleID = $linkCache->addLinkObj($this);
1636 $linkCache->forUpdate($oldUpdate);
1637 } else {
1638 if (-1 == $this->mArticleID) {
1639 $this->mArticleID = $linkCache->addLinkObj($this);
1640 }
1641 }
1642 return $this->mArticleID;
1643 }
1644
1645 public function getLatestRevID()
1646 {
1647 if ($this->mLatestID !== false) {
1648 return $this->mLatestID;
1649 }
1650
1651 $db = wfGetDB(DB_SLAVE);
1652 return $this->mLatestID = $db->selectField(
1653 'revision',
1654 "max(rev_id)",
1655 array('rev_page' => $this->getArticleID()),
1656 'Title::getLatestRevID'
1657 );
1658 }
1659
1670 public function resetArticleID($newid)
1671 {
1672 $linkCache = &LinkCache::singleton();
1673 $linkCache->clearBadLink($this->getPrefixedDBkey());
1674
1675 if (0 == $newid) {
1676 $this->mArticleID = -1;
1677 } else {
1678 $this->mArticleID = $newid;
1679 }
1680 $this->mRestrictionsLoaded = false;
1681 $this->mRestrictions = array();
1682 }
1683
1688 public function invalidateCache()
1689 {
1690 global $wgUseFileCache;
1691
1692 if (wfReadOnly()) {
1693 return;
1694 }
1695
1696 $dbw = wfGetDB(DB_MASTER);
1697 $success = $dbw->update(
1698 'page',
1699 array( /* SET */
1700 'page_touched' => $dbw->timestamp()
1701 ),
1702 array( /* WHERE */
1703 'page_namespace' => $this->getNamespace() ,
1704 'page_title' => $this->getDBkey()
1705 ),
1706 'Title::invalidateCache'
1707 );
1708
1709 if ($wgUseFileCache) {
1710 $cache = new HTMLFileCache($this);
1711 @unlink($cache->fileCacheName());
1712 }
1713
1714 return $success;
1715 }
1716
1725 /* private */ public function prefix($name)
1726 {
1727 $p = '';
1728 if ('' != $this->mInterwiki) {
1729 $p = $this->mInterwiki . ':';
1730 }
1731 if (0 != $this->mNamespace) {
1732 $p .= $this->getNsText() . ':';
1733 }
1734 return $p . $name;
1735 }
1736
1747 private function secureAndSplit()
1748 {
1749 global $wgContLang, $wgLocalInterwiki, $wgCapitalLinks;
1750
1751 # Initialisation
1752 static $rxTc = false;
1753 if (!$rxTc) {
1754 # % is needed as well
1755 $rxTc = '/[^' . Title::legalChars() . ']|%[0-9A-Fa-f]{2}/S';
1756 }
1757
1758 $this->mInterwiki = $this->mFragment = '';
1759 $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN
1760
1761 $dbkey = $this->mDbkeyform;
1762
1763 # Strip Unicode bidi override characters.
1764 # Sometimes they slip into cut-n-pasted page titles, where the
1765 # override chars get included in list displays.
1766 $dbkey = str_replace("\xE2\x80\x8E", '', $dbkey); // 200E LEFT-TO-RIGHT MARK
1767 $dbkey = str_replace("\xE2\x80\x8F", '', $dbkey); // 200F RIGHT-TO-LEFT MARK
1768
1769 # Clean up whitespace
1770 #
1771 $dbkey = preg_replace('/[ _]+/', '_', $dbkey);
1772 $dbkey = trim($dbkey, '_');
1773
1774 if ('' == $dbkey) {
1775 return false;
1776 }
1777
1778 if (false !== strpos($dbkey, UTF8_REPLACEMENT)) {
1779 # Contained illegal UTF-8 sequences or forbidden Unicode chars.
1780 return false;
1781 }
1782
1783 $this->mDbkeyform = $dbkey;
1784
1785 # Initial colon indicates main namespace rather than specified default
1786 # but should not create invalid {ns,title} pairs such as {0,Project:Foo}
1787 if (':' == $dbkey[0]) {
1788 $this->mNamespace = NS_MAIN;
1789 $dbkey = substr($dbkey, 1); # remove the colon but continue processing
1790 $dbkey = trim($dbkey, '_'); # remove any subsequent whitespace
1791 }
1792
1793 # Namespace or interwiki prefix
1794 $firstPass = true;
1795 do {
1796 $m = array();
1797 if (preg_match("/^(.+?)_*:_*(.*)$/S", $dbkey, $m)) {
1798 $p = $m[1];
1799 if ($ns = $wgContLang->getNsIndex($p)) {
1800 # Ordinary namespace
1801 $dbkey = $m[2];
1802 $this->mNamespace = $ns;
1803 } elseif ($this->getInterwikiLink($p)) {
1804 if (!$firstPass) {
1805 # Can't make a local interwiki link to an interwiki link.
1806 # That's just crazy!
1807 return false;
1808 }
1809
1810 # Interwiki link
1811 $dbkey = $m[2];
1812 $this->mInterwiki = $wgContLang->lc($p);
1813
1814 # Redundant interwiki prefix to the local wiki
1815 if (0 == strcasecmp($this->mInterwiki, $wgLocalInterwiki)) {
1816 if ($dbkey == '') {
1817 # Can't have an empty self-link
1818 return false;
1819 }
1820 $this->mInterwiki = '';
1821 $firstPass = false;
1822 # Do another namespace split...
1823 continue;
1824 }
1825
1826 # If there's an initial colon after the interwiki, that also
1827 # resets the default namespace
1828 if ($dbkey !== '' && $dbkey[0] == ':') {
1829 $this->mNamespace = NS_MAIN;
1830 $dbkey = substr($dbkey, 1);
1831 }
1832 }
1833 # If there's no recognized interwiki or namespace,
1834 # then let the colon expression be part of the title.
1835 }
1836 break;
1837 } while (true);
1838
1839 # We already know that some pages won't be in the database!
1840 #
1841 if ('' != $this->mInterwiki || NS_SPECIAL == $this->mNamespace) {
1842 $this->mArticleID = 0;
1843 }
1844 $fragment = strstr($dbkey, '#');
1845 if (false !== $fragment) {
1846 $this->setFragment($fragment);
1847 $dbkey = substr($dbkey, 0, strlen($dbkey) - strlen($fragment));
1848 # remove whitespace again: prevents "Foo_bar_#"
1849 # becoming "Foo_bar_"
1850 $dbkey = preg_replace('/_*$/', '', $dbkey);
1851 }
1852
1853 # Reject illegal characters.
1854 #
1855 if (preg_match($rxTc, $dbkey)) {
1856 return false;
1857 }
1858
1864 if (strpos($dbkey, '.') !== false &&
1865 ($dbkey === '.' || $dbkey === '..' ||
1866 strpos($dbkey, './') === 0 ||
1867 strpos($dbkey, '../') === 0 ||
1868 strpos($dbkey, '/./') !== false ||
1869 strpos($dbkey, '/../') !== false)) {
1870 return false;
1871 }
1872
1876 if (strpos($dbkey, '~~~') !== false) {
1877 return false;
1878 }
1879
1887 if (($this->mNamespace != NS_SPECIAL && strlen($dbkey) > 255) ||
1888 strlen($dbkey) > 512) {
1889 return false;
1890 }
1891
1900 if ($wgCapitalLinks && $this->mInterwiki == '') {
1901 $dbkey = $wgContLang->ucfirst($dbkey);
1902 }
1903
1909 if ($dbkey == '' &&
1910 $this->mInterwiki == '' &&
1911 $this->mNamespace != NS_MAIN) {
1912 return false;
1913 }
1914
1915 // Any remaining initial :s are illegal.
1916 if ($dbkey !== '' && ':' == $dbkey[0]) {
1917 return false;
1918 }
1919
1920 # Fill fields
1921 $this->mDbkeyform = $dbkey;
1922 $this->mUrlform = ilWikiUtil::wfUrlencode($dbkey);
1923
1924 $this->mTextform = str_replace('_', ' ', $dbkey);
1925
1926 return true;
1927 }
1928
1938 public function setFragment($fragment)
1939 {
1940 $this->mFragment = str_replace('_', ' ', substr($fragment, 1));
1941 }
1942
1947 /* public function getTalkPage() {
1948 return Title::makeTitle( Namespace::getTalk( $this->getNamespace() ), $this->getDBkey() );
1949 }*/
1950
1957 /* public function getSubjectPage() {
1958 return Title::makeTitle( Namespace::getSubject( $this->getNamespace() ), $this->getDBkey() );
1959 }*/
1960
1971 public function getLinksTo($options = '', $table = 'pagelinks', $prefix = 'pl')
1972 {
1973 $linkCache = &LinkCache::singleton();
1974
1975 if ($options) {
1976 $db = wfGetDB(DB_MASTER);
1977 } else {
1978 $db = wfGetDB(DB_SLAVE);
1979 }
1980
1981 $res = $db->select(
1982 array( 'page', $table ),
1983 array( 'page_namespace', 'page_title', 'page_id' ),
1984 array(
1985 "{$prefix}_from=page_id",
1986 "{$prefix}_namespace" => $this->getNamespace(),
1987 "{$prefix}_title" => $this->getDbKey() ),
1988 'Title::getLinksTo',
1989 $options
1990 );
1991
1992 $retVal = array();
1993 if ($db->numRows($res)) {
1994 while ($row = $db->fetchObject($res)) {
1995 if ($titleObj = Title::makeTitle($row->page_namespace, $row->page_title)) {
1996 $linkCache->addGoodLinkObj($row->page_id, $titleObj);
1997 $retVal[] = $titleObj;
1998 }
1999 }
2000 }
2001 $db->freeResult($res);
2002 return $retVal;
2003 }
2004
2015 public function getTemplateLinksTo($options = '')
2016 {
2017 return $this->getLinksTo($options, 'templatelinks', 'tl');
2018 }
2019
2026 public function getBrokenLinksFrom($options = '')
2027 {
2028 if ($options) {
2029 $db = wfGetDB(DB_MASTER);
2030 } else {
2031 $db = wfGetDB(DB_SLAVE);
2032 }
2033
2034 $res = $db->safeQuery(
2035 "SELECT pl_namespace, pl_title
2036 FROM !
2037 LEFT JOIN !
2038 ON pl_namespace=page_namespace
2039 AND pl_title=page_title
2040 WHERE pl_from=?
2041 AND page_namespace IS NULL
2042 !",
2043 $db->tableName('pagelinks'),
2044 $db->tableName('page'),
2045 $this->getArticleId(),
2046 $options
2047 );
2048
2049 $retVal = array();
2050 if ($db->numRows($res)) {
2051 while ($row = $db->fetchObject($res)) {
2052 $retVal[] = Title::makeTitle($row->pl_namespace, $row->pl_title);
2053 }
2054 }
2055 $db->freeResult($res);
2056 return $retVal;
2057 }
2058
2059
2066 public function getSquidURLs()
2067 {
2068 global $wgContLang;
2069
2070 $urls = array(
2071 $this->getInternalURL(),
2072 $this->getInternalURL('action=history')
2073 );
2074
2075 // purge variant urls as well
2076 if ($wgContLang->hasVariants()) {
2077 $variants = $wgContLang->getVariants();
2078 foreach ($variants as $vCode) {
2079 if ($vCode == $wgContLang->getCode()) {
2080 continue;
2081 } // we don't want default variant
2082 $urls[] = $this->getInternalURL('', $vCode);
2083 }
2084 }
2085
2086 return $urls;
2087 }
2088
2089 public function purgeSquid()
2090 {
2091 global $wgUseSquid;
2092 if ($wgUseSquid) {
2093 $urls = $this->getSquidURLs();
2094 $u = new SquidUpdate($urls);
2095 $u->doUpdate();
2096 }
2097 }
2098
2103 public function moveNoAuth(&$nt)
2104 {
2105 return $this->moveTo($nt, false);
2106 }
2107
2117 public function isValidMoveOperation(&$nt, $auth = true)
2118 {
2119 if (!$this or !$nt) {
2120 return 'badtitletext';
2121 }
2122 if ($this->equals($nt)) {
2123 return 'selfmove';
2124 }
2125 if (!$this->isMovable() || !$nt->isMovable()) {
2126 return 'immobile_namespace';
2127 }
2128
2129 $oldid = $this->getArticleID();
2130 $newid = $nt->getArticleID();
2131
2132 if (strlen($nt->getDBkey()) < 1) {
2133 return 'articleexists';
2134 }
2135 if (('' == $this->getDBkey()) ||
2136 (!$oldid) ||
2137 ('' == $nt->getDBkey())) {
2138 return 'badarticleerror';
2139 }
2140
2141 if ($auth && (
2142 !$this->userCan('edit') || !$nt->userCan('edit') ||
2143 !$this->userCan('move') || !$nt->userCan('move')
2144 )) {
2145 return 'protectedpage';
2146 }
2147
2148 # The move is allowed only if (1) the target doesn't exist, or
2149 # (2) the target is a redirect to the source, and has no history
2150 # (so we can undo bad moves right after they're done).
2151
2152 if (0 != $newid) { # Target exists; check for validity
2153 if (!$this->isValidMoveTarget($nt)) {
2154 return 'articleexists';
2155 }
2156 }
2157 return true;
2158 }
2159
2167 public function moveTo(&$nt, $auth = true, $reason = '')
2168 {
2169 $err = $this->isValidMoveOperation($nt, $auth);
2170 if (is_string($err)) {
2171 return $err;
2172 }
2173
2174 $pageid = $this->getArticleID();
2175 if ($nt->exists()) {
2176 $this->moveOverExistingRedirect($nt, $reason);
2177 $pageCountChange = 0;
2178 } else { # Target didn't exist, do normal move.
2179 $this->moveToNewTitle($nt, $reason);
2180 $pageCountChange = 1;
2181 }
2182 $redirid = $this->getArticleID();
2183
2184 # Fixing category links (those without piped 'alternate' names) to be sorted under the new title
2185 $dbw = wfGetDB(DB_MASTER);
2186 $categorylinks = $dbw->tableName('categorylinks');
2187 $sql = "UPDATE $categorylinks SET cl_sortkey=" . $dbw->addQuotes($nt->getPrefixedText()) .
2188 " WHERE cl_from=" . $dbw->addQuotes($pageid) .
2189 " AND cl_sortkey=" . $dbw->addQuotes($this->getPrefixedText());
2190 $dbw->query($sql, 'SpecialMovepage::doSubmit');
2191
2192 # Update watchlists
2193
2194 $oldnamespace = $this->getNamespace() & ~1;
2195 $newnamespace = $nt->getNamespace() & ~1;
2196 $oldtitle = $this->getDBkey();
2197 $newtitle = $nt->getDBkey();
2198
2199 if ($oldnamespace != $newnamespace || $oldtitle != $newtitle) {
2200 WatchedItem::duplicateEntries($this, $nt);
2201 }
2202
2203 # Update search engine
2204 $u = new SearchUpdate($pageid, $nt->getPrefixedDBkey());
2205 $u->doUpdate();
2206 $u = new SearchUpdate($redirid, $this->getPrefixedDBkey(), '');
2207 $u->doUpdate();
2208
2209 # Update site_stats
2210 if ($this->isContentPage() && !$nt->isContentPage()) {
2211 # No longer a content page
2212 # Not viewed, edited, removing
2213 $u = new SiteStatsUpdate(0, 1, -1, $pageCountChange);
2214 } elseif (!$this->isContentPage() && $nt->isContentPage()) {
2215 # Now a content page
2216 # Not viewed, edited, adding
2217 $u = new SiteStatsUpdate(0, 1, +1, $pageCountChange);
2218 } elseif ($pageCountChange) {
2219 # Redirect added
2220 $u = new SiteStatsUpdate(0, 0, 0, 1);
2221 } else {
2222 # Nothing special
2223 $u = false;
2224 }
2225 if ($u) {
2226 $u->doUpdate();
2227 }
2228
2229 global $wgUser;
2230 wfRunHooks('TitleMoveComplete', array( &$this, &$nt, &$wgUser, $pageid, $redirid ));
2231 return true;
2232 }
2233
2241 private function moveOverExistingRedirect(&$nt, $reason = '')
2242 {
2243 global $wgUseSquid;
2245 $comment = wfMsgForContent('1movedto2_redir', $this->getPrefixedText(), $nt->getPrefixedText());
2246
2247 if ($reason) {
2248 $comment .= ": $reason";
2249 }
2250
2251 $now = wfTimestampNow();
2252 $newid = $nt->getArticleID();
2253 $oldid = $this->getArticleID();
2254 $dbw = wfGetDB(DB_MASTER);
2255 $linkCache = &LinkCache::singleton();
2256
2257 # Delete the old redirect. We don't save it to history since
2258 # by definition if we've got here it's rather uninteresting.
2259 # We have to remove it so that the next step doesn't trigger
2260 # a conflict on the unique namespace+title index...
2261 $dbw->delete('page', array( 'page_id' => $newid ), $fname);
2262
2263 # Save a null revision in the page's history notifying of the move
2264 $nullRevision = Revision::newNullRevision($dbw, $oldid, $comment, true);
2265 $nullRevId = $nullRevision->insertOn($dbw);
2266
2267 # Change the name of the target page:
2268 $dbw->update(
2269 'page',
2270 /* SET */
2271 array(
2272 'page_touched' => $dbw->timestamp($now),
2273 'page_namespace' => $nt->getNamespace(),
2274 'page_title' => $nt->getDBkey(),
2275 'page_latest' => $nullRevId,
2276 ),
2277 /* WHERE */
2278 array( 'page_id' => $oldid ),
2279 $fname
2280 );
2281 $linkCache->clearLink($nt->getPrefixedDBkey());
2282
2283 # Recreate the redirect, this time in the other direction.
2284 $mwRedir = MagicWord::get('redirect');
2285 $redirectText = $mwRedir->getSynonym(0) . ' [[' . $nt->getPrefixedText() . "]]\n";
2286 $redirectArticle = new Article($this);
2287 $newid = $redirectArticle->insertOn($dbw);
2288 $redirectRevision = new Revision(array(
2289 'page' => $newid,
2290 'comment' => $comment,
2291 'text' => $redirectText ));
2292 $redirectRevision->insertOn($dbw);
2293 $redirectArticle->updateRevisionOn($dbw, $redirectRevision, 0);
2294 $linkCache->clearLink($this->getPrefixedDBkey());
2295
2296 # Log the move
2297 $log = new LogPage('move');
2298 $log->addEntry('move_redir', $this, $reason, array( 1 => $nt->getPrefixedText() ));
2299
2300 # Now, we record the link from the redirect to the new title.
2301 # It should have no other outgoing links...
2302 $dbw->delete('pagelinks', array( 'pl_from' => $newid ), $fname);
2303 $dbw->insert(
2304 'pagelinks',
2305 array(
2306 'pl_from' => $newid,
2307 'pl_namespace' => $nt->getNamespace(),
2308 'pl_title' => $nt->getDbKey() ),
2309 $fname
2310 );
2311
2312 # Purge squid
2313 if ($wgUseSquid) {
2314 $urls = array_merge($nt->getSquidURLs(), $this->getSquidURLs());
2315 $u = new SquidUpdate($urls);
2316 $u->doUpdate();
2317 }
2318 }
2319
2324 private function moveToNewTitle(&$nt, $reason = '')
2325 {
2326 global $wgUseSquid;
2327 $fname = 'MovePageForm::moveToNewTitle';
2328 $comment = wfMsgForContent('1movedto2', $this->getPrefixedText(), $nt->getPrefixedText());
2329 if ($reason) {
2330 $comment .= ": $reason";
2331 }
2332
2333 $newid = $nt->getArticleID();
2334 $oldid = $this->getArticleID();
2335 $dbw = wfGetDB(DB_MASTER);
2336 $now = $dbw->timestamp();
2337 $linkCache = &LinkCache::singleton();
2338
2339 # Save a null revision in the page's history notifying of the move
2340 $nullRevision = Revision::newNullRevision($dbw, $oldid, $comment, true);
2341 $nullRevId = $nullRevision->insertOn($dbw);
2342
2343 # Rename cur entry
2344 $dbw->update(
2345 'page',
2346 /* SET */
2347 array(
2348 'page_touched' => $now,
2349 'page_namespace' => $nt->getNamespace(),
2350 'page_title' => $nt->getDBkey(),
2351 'page_latest' => $nullRevId,
2352 ),
2353 /* WHERE */
2354 array( 'page_id' => $oldid ),
2355 $fname
2356 );
2357
2358 $linkCache->clearLink($nt->getPrefixedDBkey());
2359
2360 # Insert redirect
2361 $mwRedir = MagicWord::get('redirect');
2362 $redirectText = $mwRedir->getSynonym(0) . ' [[' . $nt->getPrefixedText() . "]]\n";
2363 $redirectArticle = new Article($this);
2364 $newid = $redirectArticle->insertOn($dbw);
2365 $redirectRevision = new Revision(array(
2366 'page' => $newid,
2367 'comment' => $comment,
2368 'text' => $redirectText ));
2369 $redirectRevision->insertOn($dbw);
2370 $redirectArticle->updateRevisionOn($dbw, $redirectRevision, 0);
2371 $linkCache->clearLink($this->getPrefixedDBkey());
2372
2373 # Log the move
2374 $log = new LogPage('move');
2375 $log->addEntry('move', $this, $reason, array( 1 => $nt->getPrefixedText()));
2376
2377 # Purge caches as per article creation
2378 Article::onArticleCreate($nt);
2379
2380 # Record the just-created redirect's linking to the page
2381 $dbw->insert(
2382 'pagelinks',
2383 array(
2384 'pl_from' => $newid,
2385 'pl_namespace' => $nt->getNamespace(),
2386 'pl_title' => $nt->getDBkey() ),
2387 $fname
2388 );
2389
2390 # Purge old title from squid
2391 # The new title, and links to the new title, are purged in Article::onArticleCreate()
2392 $this->purgeSquid();
2393 }
2394
2401 public function isValidMoveTarget($nt)
2402 {
2403 $fname = 'Title::isValidMoveTarget';
2404 $dbw = wfGetDB(DB_MASTER);
2405
2406 # Is it a redirect?
2407 $id = $nt->getArticleID();
2408 $obj = $dbw->selectRow(
2409 array( 'page', 'revision', 'text'),
2410 array( 'page_is_redirect','old_text','old_flags' ),
2411 array( 'page_id' => $id, 'page_latest=rev_id', 'rev_text_id=old_id' ),
2412 $fname,
2413 'FOR UPDATE'
2414 );
2415
2416 if (!$obj || 0 == $obj->page_is_redirect) {
2417 # Not a redirect
2418 wfDebug(__METHOD__ . ": not a redirect\n");
2419 return false;
2420 }
2421 $text = Revision::getRevisionText($obj);
2422
2423 # Does the redirect point to the source?
2424 # Or is it a broken self-redirect, usually caused by namespace collisions?
2425 $m = array();
2426 if (preg_match("/\\[\\[\\s*([^\\]\\|]*)]]/", $text, $m)) {
2427 $redirTitle = Title::newFromText($m[1]);
2428 if (!is_object($redirTitle) ||
2429 ($redirTitle->getPrefixedDBkey() != $this->getPrefixedDBkey() &&
2430 $redirTitle->getPrefixedDBkey() != $nt->getPrefixedDBkey())) {
2431 wfDebug(__METHOD__ . ": redirect points to other page\n");
2432 return false;
2433 }
2434 } else {
2435 # Fail safe
2436 wfDebug(__METHOD__ . ": failsafe\n");
2437 return false;
2438 }
2439
2440 # Does the article have a history?
2441 $row = $dbw->selectRow(
2442 array( 'page', 'revision'),
2443 array( 'rev_id' ),
2444 array( 'page_namespace' => $nt->getNamespace(),
2445 'page_title' => $nt->getDBkey(),
2446 'page_id=rev_page AND page_latest != rev_id'
2447 ),
2448 $fname,
2449 'FOR UPDATE'
2450 );
2451
2452 # Return true if there was no history
2453 return $row === false;
2454 }
2455
2463 public function getParentCategories()
2464 {
2465 global $wgContLang;
2466
2467 $titlekey = $this->getArticleId();
2468 $dbr = wfGetDB(DB_SLAVE);
2469 $categorylinks = $dbr->tableName('categorylinks');
2470
2471 # NEW SQL
2472 $sql = "SELECT * FROM $categorylinks"
2473 . " WHERE cl_from='$titlekey'"
2474 . " AND cl_from <> '0'"
2475 . " ORDER BY cl_sortkey";
2476
2477 $res = $dbr->query($sql) ;
2478
2479 if ($dbr->numRows($res) > 0) {
2480 while ($x = $dbr->fetchObject($res)) {
2481 //$data[] = Title::newFromText($wgContLang->getNSText ( NS_CATEGORY ).':'.$x->cl_to);
2482 $data[$wgContLang->getNSText(NS_CATEGORY) . ':' . $x->cl_to] = $this->getFullText();
2483 }
2484 $dbr->freeResult($res) ;
2485 } else {
2486 $data = '';
2487 }
2488 return $data;
2489 }
2490
2496 public function getParentCategoryTree($children = array())
2497 {
2498 $parents = $this->getParentCategories();
2499
2500 if ($parents != '') {
2501 foreach ($parents as $parent => $current) {
2502 if (array_key_exists($parent, $children)) {
2503 # Circular reference
2504 $stack[$parent] = array();
2505 } else {
2506 $nt = Title::newFromText($parent);
2507 if ($nt) {
2508 $stack[$parent] = $nt->getParentCategoryTree($children + array($parent => 1));
2509 }
2510 }
2511 }
2512 return $stack;
2513 } else {
2514 return array();
2515 }
2516 }
2517
2518
2525 public function pageCond()
2526 {
2527 return array( 'page_namespace' => $this->mNamespace, 'page_title' => $this->mDbkeyform );
2528 }
2529
2536 public function getPreviousRevisionID($revision)
2537 {
2538 $dbr = wfGetDB(DB_SLAVE);
2539 return $dbr->selectField(
2540 'revision',
2541 'rev_id',
2542 'rev_page=' . intval($this->getArticleId()) .
2543 ' AND rev_id<' . intval($revision) . ' ORDER BY rev_id DESC'
2544 );
2545 }
2546
2553 public function getNextRevisionID($revision)
2554 {
2555 $dbr = wfGetDB(DB_SLAVE);
2556 return $dbr->selectField(
2557 'revision',
2558 'rev_id',
2559 'rev_page=' . intval($this->getArticleId()) .
2560 ' AND rev_id>' . intval($revision) . ' ORDER BY rev_id'
2561 );
2562 }
2563
2571 public function countRevisionsBetween($old, $new)
2572 {
2573 $dbr = wfGetDB(DB_SLAVE);
2574 return $dbr->selectField(
2575 'revision',
2576 'count(*)',
2577 'rev_page = ' . intval($this->getArticleId()) .
2578 ' AND rev_id > ' . intval($old) .
2579 ' AND rev_id < ' . intval($new)
2580 );
2581 }
2582
2589 public function equals($title)
2590 {
2591 // Note: === is necessary for proper matching of number-like titles.
2592 return $this->getInterwiki() === $title->getInterwiki()
2593 && $this->getNamespace() == $title->getNamespace()
2594 && $this->getDbkey() === $title->getDbkey();
2595 }
2596
2601 public function exists()
2602 {
2603 return $this->getArticleId() != 0;
2604 }
2605
2612 public function isAlwaysKnown()
2613 {
2614 return $this->isExternal() || (0 == $this->mNamespace && "" == $this->mDbkeyform)
2615 || NS_SPECIAL == $this->mNamespace;
2616 }
2617
2623 public function touchLinks()
2624 {
2625 $u = new HTMLCacheUpdate($this, 'pagelinks');
2626 $u->doUpdate();
2627
2628 if ($this->getNamespace() == NS_CATEGORY) {
2629 $u = new HTMLCacheUpdate($this, 'categorylinks');
2630 $u->doUpdate();
2631 }
2632 }
2633
2637 public function getTouched()
2638 {
2639 $dbr = wfGetDB(DB_SLAVE);
2640 $touched = $dbr->selectField(
2641 'page',
2642 'page_touched',
2643 array(
2644 'page_namespace' => $this->getNamespace(),
2645 'page_title' => $this->getDBkey()
2646 ),
2647 __METHOD__
2648 );
2649 return $touched;
2650 }
2651
2652 public function trackbackURL()
2653 {
2654 global $wgTitle, $wgScriptPath, $wgServer;
2655
2656 return "$wgServer$wgScriptPath/trackback.php?article="
2657 . htmlspecialchars(urlencode($wgTitle->getPrefixedDBkey()));
2658 }
2659
2660 public function trackbackRDF()
2661 {
2662 $url = htmlspecialchars($this->getFullURL());
2663 $title = htmlspecialchars($this->getText());
2664 $tburl = $this->trackbackURL();
2665
2666 return "
2667<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"
2668 xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
2669 xmlns:trackback=\"http://madskills.com/public/xml/rss/module/trackback/\">
2670<rdf:Description
2671 rdf:about=\"$url\"
2672 dc:identifier=\"$url\"
2673 dc:title=\"$title\"
2674 trackback:ping=\"$tburl\" />
2675</rdf:RDF>";
2676 }
2677
2682 public function getNamespaceKey()
2683 {
2684 global $wgContLang;
2685 switch ($this->getNamespace()) {
2686 case NS_MAIN:
2687 case NS_TALK:
2688 return 'nstab-main';
2689 case NS_USER:
2690 case NS_USER_TALK:
2691 return 'nstab-user';
2692 case NS_MEDIA:
2693 return 'nstab-media';
2694 case NS_SPECIAL:
2695 return 'nstab-special';
2696 case NS_PROJECT:
2697 case NS_PROJECT_TALK:
2698 return 'nstab-project';
2699 case NS_IMAGE:
2700 case NS_IMAGE_TALK:
2701 return 'nstab-image';
2702 case NS_MEDIAWIKI:
2703 case NS_MEDIAWIKI_TALK:
2704 return 'nstab-mediawiki';
2705 case NS_TEMPLATE:
2706 case NS_TEMPLATE_TALK:
2707 return 'nstab-template';
2708 case NS_HELP:
2709 case NS_HELP_TALK:
2710 return 'nstab-help';
2711 case NS_CATEGORY:
2712 case NS_CATEGORY_TALK:
2713 return 'nstab-category';
2714 default:
2715 return 'nstab-' . $wgContLang->lc($this->getSubjectNsText());
2716 }
2717 }
2718
2723 public function isSpecial($name)
2724 {
2725 if ($this->getNamespace() == NS_SPECIAL) {
2726 list($thisName, /* $subpage */ ) = SpecialPage::resolveAliasWithSubpage($this->getDBkey());
2727 if ($name == $thisName) {
2728 return true;
2729 }
2730 }
2731 return false;
2732 }
2733
2738 public function fixSpecialName()
2739 {
2740 if ($this->getNamespace() == NS_SPECIAL) {
2741 $canonicalName = SpecialPage::resolveAlias($this->mDbkeyform);
2742 if ($canonicalName) {
2743 $localName = SpecialPage::getLocalNameFor($canonicalName);
2744 if ($localName != $this->mDbkeyform) {
2745 return Title::makeTitle(NS_SPECIAL, $localName);
2746 }
2747 }
2748 }
2749 return $this;
2750 }
2751
2759/* public function isContentPage() {
2760 return Namespace::isContent( $this->getNamespace() );
2761 }*/
2762}
$result
$n
Definition: RandomTest.php:85
const MW_TITLECACHE_MAX
Definition: Title.php:25
const GAID_FOR_UPDATE
Definition: Title.php:18
const NS_SPECIAL
Definition: Title.php:16
const NS_MAIN(!class_exists('UtfNormal'))
See title.txt.
Definition: Title.php:15
$success
Definition: Utf8Test.php:86
$comment
Definition: buildRTE.php:83
An exception for terminatinating execution or to throw for unit testing.
static decodeCharReferences($text)
Decode any character references, numeric or named entities, in the text and return a UTF-8 string.
Definition: Sanitizer.php:1018
Title class.
Definition: Title.php:37
getInternalURL($query='', $variant=false)
Get the URL form for an internal link.
Definition: Title.php:953
static newFromRedirect($text)
Create a new Title for a redirect.
Definition: Title.php:301
escapeFullURL($query='')
Get an HTML-escaped version of the URL form, suitable for using in a link, including the server name ...
Definition: Title.php:939
getTouched()
Get the last touched timestamp.
Definition: Title.php:2637
getNamespace()
Get the namespace index, i.e.
Definition: Title.php:596
static getInterwikiCached($key)
Fetch interwiki prefix data from local cache in constant database.
Definition: Title.php:474
userCanRead()
Would anybody with sufficient privileges be able to move this page? Some pages just aren't movable.
Definition: Title.php:1244
static $titleCache
Static cache variables.
Definition: Title.php:41
invalidateCache()
Updates page_touched for this page; called from LinksUpdate.php.
Definition: Title.php:1688
isValidMoveOperation(&$nt, $auth=true)
Check whether a given move operation would be valid.
Definition: Title.php:2117
purgeSquid()
Definition: Title.php:2089
$mHasCascadingRestrictions
Definition: Title.php:65
moveTo(&$nt, $auth=true, $reason='')
Move a title to a new location.
Definition: Title.php:2167
$mInterwiki
Definition: Title.php:58
$mTextform
All member variables should be considered private Please use the accessor functions.
Definition: Title.php:54
nameOf($id)
Get the prefixed DB key associated with an ID.
Definition: Title.php:337
getNextRevisionID($revision)
Get the revision ID of the next revision.
Definition: Title.php:2553
secureAndSplit()
Secure and split - main initialisation function for this object.
Definition: Title.php:1747
getSkinFromCssJsSubpage()
Trim down a .css or .js subpage title to get the corresponding skin name.
Definition: Title.php:1330
getDefaultNamespace()
Get the default namespace index, for when there is no namespace.
Definition: Title.php:679
$mArticleID
Definition: Title.php:60
resetArticleID($newid)
This clears some fields in this object, and clears any associated keys in the "bad links" section of ...
Definition: Title.php:1670
$mNamespace
Definition: Title.php:57
getFragment()
Get the Title fragment (i.e.
Definition: Title.php:659
isCascadeProtected()
Cascading protection: Return true if cascading restrictions apply to this page, false if not.
Definition: Title.php:1370
isProtected($action='')
Does the title correspond to a protected article?
Definition: Title.php:1028
getIndexTitle()
Get title for search index.
Definition: Title.php:689
getPrefixedURL()
Get a URL-encoded title (not an actual URL) including interwiki.
Definition: Title.php:786
getLinksTo($options='', $table='pagelinks', $prefix='pl')
Get a Title object associated with the talk page of this article.
Definition: Title.php:1971
$mWatched
Definition: Title.php:71
prefix($name)
Prefix some arbitrary text with the namespace or interwiki prefix of this object.
Definition: Title.php:1725
static newFromText($text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:124
areRestrictionsCascading()
Definition: Title.php:1474
$mDbkeyform
Definition: Title.php:56
$mRestrictionsLoaded
Definition: Title.php:67
getEscapedText()
Get the HTML-escaped displayable text form.
Definition: Title.php:981
getFullText()
Get the prefixed title with spaces, plus any fragment (part beginning with '#')
Definition: Title.php:727
getFullURL($query='', $variant=false)
Get a real URL referring to this title, with interwiki link and fragment.
Definition: Title.php:809
isLocal()
Determine whether the object refers to a page within this project.
Definition: Title.php:520
moveNoAuth(&$nt)
Move this page without authentication.
Definition: Title.php:2103
$mCascadeRestrictionSources
Definition: Title.php:66
static makeTitleSafe($ns, $title)
Create a new Title from a namespace index and a DB key.
Definition: Title.php:275
quickUserCan($action)
Can $wgUser perform $action on this page? This skips potentially expensive cascading permission check...
Definition: Title.php:1089
fixSpecialName()
If the Title refers to a special page alias which is not the local default, returns a new Title which...
Definition: Title.php:2738
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition: Title.php:355
isCssJsSubpage()
Is this a .css or .js subpage of a user page?
Definition: Title.php:1310
getPrefixedDBkey()
Get the prefixed database key form.
Definition: Title.php:699
getNsText()
Get the namespace text.
Definition: Title.php:604
static purgeExpiredRestrictions()
Purge expired restrictions from the page_restrictions table.
Definition: Title.php:1568
equals($title)
Compare with another title.
Definition: Title.php:2589
userCanCreate($doExpensiveQueries=true)
Can $wgUser create this page?
Definition: Title.php:1213
static $interwikiCache
Definition: Title.php:42
isTrans()
Determine whether the object refers to a page within this project and is transcludable.
Definition: Title.php:538
static makeName($ns, $title)
Definition: Title.php:400
touchLinks()
Update page_touched timestamps and send squid purge messages for pages linking to this title.
Definition: Title.php:2623
trackbackRDF()
Definition: Title.php:2660
userIsWatching()
Is $wgUser is watching this page?
Definition: Title.php:1063
isExternal()
Is this Title interwiki?
Definition: Title.php:990
getFragmentForURL()
Get the fragment in URL form, including the "#" character if there is one.
Definition: Title.php:667
static newFromID($id)
Create a new Title from an article ID.
Definition: Title.php:204
$mRestrictionsExpiry
Definition: Title.php:64
getArticleID($flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
Definition: Title.php:1630
static & makeTitle($ns, $title)
Create a new Title from a namespace index and a DB key.
Definition: Title.php:253
getSubpageUrlForm()
Get a URL-encoded form of the subpage text.
Definition: Title.php:774
getDBkey()
Get the main part with underscores.
Definition: Title.php:588
countRevisionsBetween($old, $new)
Get the number of revisions between the given revision IDs.
Definition: Title.php:2571
userCanEditCssJsSubpage()
Protect css/js subpages of user pages: can $wgUser edit this page?
Definition: Title.php:1359
isValidCssJsSubpage()
Is this a valid .css or .js subpage of a user page? Check that the corresponding skin exists.
Definition: Title.php:1318
userCanEdit($doExpensiveQueries=true)
Can $wgUser edit this page?
Definition: Title.php:1203
static indexTitle($ns, $title)
Get a string representation of a title suitable for including in a search index.
Definition: Title.php:373
getBrokenLinksFrom($options='')
Get an array of Title objects referring to non-existent articles linked from this page.
Definition: Title.php:2026
getCascadeProtectionSources($get_pages=true)
Cascading protection: Get the source of any cascading restrictions on this page.
Definition: Title.php:1384
$mRestrictions
Definition: Title.php:62
getPartialURL()
Get the URL-encoded form of the main part.
Definition: Title.php:580
getBaseText()
Get the base name, i.e.
Definition: Title.php:740
getText()
Simple accessors.
Definition: Title.php:572
pageCond()
Get an associative array for selecting this title from the "page" table.
Definition: Title.php:2525
isSemiProtected($action='edit')
Is this page "semi-protected" - the only protection is autoconfirm?
Definition: Title.php:1001
isJsSubpage()
Is this a .js subpage of a user page?
Definition: Title.php:1348
userCanMove($doExpensiveQueries=true)
Can $wgUser move this page?
Definition: Title.php:1223
isSpecial($name)
Returns true if this title resolves to the named special page.
Definition: Title.php:2723
$mUrlform
Definition: Title.php:55
__construct()
#-
Definition: Title.php:79
$mLatestID
Definition: Title.php:61
static newMainPage()
Create a new Title for the Main Page.
Definition: Title.php:290
isCssSubpage()
Is this a .css subpage of a user page?
Definition: Title.php:1340
exists()
Check if page exists.
Definition: Title.php:2601
getSquidURLs()
Get a list of URLs to purge from the Squid cache when this page changes.
Definition: Title.php:2066
getLocalURL($query='', $variant=false)
Get a URL with no fragment or server name.
Definition: Title.php:849
static newFromURL($url)
Create a new Title from URL-encoded text.
Definition: Title.php:175
isDeleted()
Is there a version of this page in the deletion archive?
Definition: Title.php:1602
moveOverExistingRedirect(&$nt, $reason='')
Move page to a title which is at present a redirect to the source page.
Definition: Title.php:2241
static newFromDBkey($key)
Create a new Title from a prefixed DB key.
Definition: Title.php:102
setFragment($fragment)
Set the fragment for this title This is kind of bad, since except for this rarely-used function,...
Definition: Title.php:1938
loadRestrictions($oldFashionedRestrictions=null)
Definition: Title.php:1549
$mFragment
Definition: Title.php:59
getParentCategoryTree($children=array())
Get a tree of parent categories.
Definition: Title.php:2496
getEditURL()
Get the edit URL for this Title.
Definition: Title.php:966
getParentCategories()
Get categories to which this Title belongs and return an array of categories' names.
Definition: Title.php:2463
getNamespaceKey()
Generate strings used for xml 'id' names in monobook tabs.
Definition: Title.php:2682
trackbackURL()
Definition: Title.php:2652
$mCascadeRestriction
Definition: Title.php:63
static newFromIDs($ids)
Make an array of titles from an array of IDs.
Definition: Title.php:225
getInterwikiLink($key)
Returns the URL associated with an interwiki prefix.
Definition: Title.php:415
isSubpage()
Is this a talk page of some sort?
Definition: Title.php:1295
moveToNewTitle(&$nt, $reason='')
Move page to non-existing title.
Definition: Title.php:2324
$mPrefixedText
Definition: Title.php:68
getInterwiki()
Get the namespace text of the subject (rather than talk) page.
Definition: Title.php:651
$mDefaultNamespace
Definition: Title.php:69
isValidMoveTarget($nt)
Checks if $this can be moved to a given Title.
Definition: Title.php:2401
userCan($action, $doExpensiveQueries=true)
Can $wgUser perform $action on this page?
Definition: Title.php:1100
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:2015
getSubpageText()
Get the lowest-level subpage name, i.e.
Definition: Title.php:759
getPreviousRevisionID($revision)
Get the revision ID of the previous revision.
Definition: Title.php:2536
getPrefixedText()
Get the prefixed title with spaces.
Definition: Title.php:711
getRestrictions($action)
Accessor/initialisation for mRestrictions.
Definition: Title.php:1584
loadRestrictionsFromRow($res, $oldFashionedRestrictions=null)
Loads a string into mRestrictions array.
Definition: Title.php:1487
isAlwaysKnown()
Should a link should be displayed as a known link, just based on its title?
Definition: Title.php:2612
getLatestRevID()
Definition: Title.php:1645
static escapeFragmentForURL($fragment)
Escape a text fragment, say from a link, for a URL.
Definition: Title.php:552
escapeLocalURL($query='')
Get an HTML-escaped version of the URL form, suitable for using in a link, without a server name or f...
Definition: Title.php:927
static wfUrlencode($s)
From GlobalFunctions.php.
$lc
Definition: date.php:267
if($err=$client->getError()) $namespace
if($format !==null) $name
Definition: metadata.php:230
$auth
Definition: metadata.php:59
get(string $class_name)
$ret
Definition: parser.php:6
$query
$url
$log
Definition: result.php:15
foreach($_POST as $key=> $value) $res
$data
Definition: storeScorm.php:23
up()
Definition: up.php:2
$cols
Definition: xhr_table.php:11