ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
Title.php
Go to the documentation of this file.
1<?php
8if ( !class_exists( 'UtfNormal' ) ) {
9 require_once( dirname(__FILE__) . '/normal/UtfNormal.php' );
10}
11
12define ( 'GAID_FOR_UPDATE', 1 );
13
14# Title::newFromTitle maintains a cache to avoid
15# expensive re-normalization of commonly used titles.
16# On a batch operation this can become a memory leak
17# if not bounded. After hitting this many titles,
18# reset the cache.
19define( 'MW_TITLECACHE_MAX', 1000 );
20
21# Constants for pr_cascade bitfield
22define( 'CASCADE', 1 );
23
30class Title {
34 static private $titleCache=array();
35 static private $interwikiCache=array();
36
37
47 var $mTextform; # Text form (spaces not underscores) of the main part
48 var $mUrlform; # URL-encoded form of the main part
49 var $mDbkeyform; # Main part with underscores
50 var $mNamespace; # Namespace index, i.e. one of the NS_xxxx constants
51 var $mInterwiki; # Interwiki prefix (or null string)
52 var $mFragment; # Title fragment (i.e. the bit after the #)
53 var $mArticleID; # Article ID, fetched from the link cache on demand
54 var $mLatestID; # ID of most recent revision
55 var $mRestrictions; # Array of groups allowed to edit this article
56 var $mCascadeRestriction; # Cascade restrictions on this page to included templates and images?
57 var $mRestrictionsExpiry; # When do the restrictions on this page expire?
58 var $mHasCascadingRestrictions; # Are cascading restrictions in effect on this page?
59 var $mCascadeRestrictionSources;# Where are the cascading restrictions coming from on this page?
60 var $mRestrictionsLoaded; # Boolean for initialisation on demand
61 var $mPrefixedText; # Text form including namespace/interwiki, initialised on demand
62 var $mDefaultNamespace; # Namespace index when there is no namespace
63 # Zero except in {{transclusion}} tags
64 var $mWatched; # Is $wgUser watching this page? NULL if unfilled, accessed through userIsWatching()
72 /* private */ function __construct() {
73 $this->mInterwiki = $this->mUrlform =
74 $this->mTextform = $this->mDbkeyform = '';
75 $this->mArticleID = -1;
76 $this->mNamespace = NS_MAIN;
77 $this->mRestrictionsLoaded = false;
78 $this->mRestrictions = array();
79 # Dont change the following, NS_MAIN is hardcoded in several place
80 # See bug #696
81 $this->mDefaultNamespace = NS_MAIN;
82 $this->mWatched = NULL;
83 $this->mLatestID = false;
84 $this->mOldRestrictions = false;
85 }
86
94 public static function newFromDBkey( $key ) {
95 $t = new Title();
96 $t->mDbkeyform = $key;
97 if( $t->secureAndSplit() )
98 return $t;
99 else
100 return NULL;
101 }
102
114 public static function newFromText( $text, $defaultNamespace = NS_MAIN ) {
115 if( is_object( $text ) ) {
116 throw new MWException( 'Title::newFromText given an object' );
117 }
118
127 if( $defaultNamespace == NS_MAIN && isset( Title::$titleCache[$text] ) ) {
129 }
130
134 $filteredText = Sanitizer::decodeCharReferences( $text );
135
136 $t = new Title();
137 $t->mDbkeyform = str_replace( ' ', '_', $filteredText );
138 $t->mDefaultNamespace = $defaultNamespace;
139
140 static $cachedcount = 0 ;
141 if( $t->secureAndSplit() ) {
142 if( $defaultNamespace == NS_MAIN ) {
143 if( $cachedcount >= MW_TITLECACHE_MAX ) {
144 # Avoid memory leaks on mass operations...
145 Title::$titleCache = array();
146 $cachedcount=0;
147 }
148 $cachedcount++;
150 }
151 return $t;
152 } else {
153 $ret = NULL;
154 return $ret;
155 }
156 }
157
164 public static function newFromURL( $url ) {
165 global $wgLegalTitleChars;
166 $t = new Title();
167
168 # For compatibility with old buggy URLs. "+" is usually not valid in titles,
169 # but some URLs used it as a space replacement and they still come
170 # from some external search tools.
171 if ( strpos( $wgLegalTitleChars, '+' ) === false ) {
172 $url = str_replace( '+', ' ', $url );
173 }
174
175 $t->mDbkeyform = str_replace( ' ', '_', $url );
176 if( $t->secureAndSplit() ) {
177 return $t;
178 } else {
179 return NULL;
180 }
181 }
182
192 public static function newFromID( $id ) {
193 $fname = 'Title::newFromID';
194 $dbr = wfGetDB( DB_SLAVE );
195 $row = $dbr->selectRow( 'page', array( 'page_namespace', 'page_title' ),
196 array( 'page_id' => $id ), $fname );
197 if ( $row !== false ) {
198 $title = Title::makeTitle( $row->page_namespace, $row->page_title );
199 } else {
200 $title = NULL;
201 }
202 return $title;
203 }
204
208 public static function newFromIDs( $ids ) {
209 $dbr = wfGetDB( DB_SLAVE );
210 $res = $dbr->select( 'page', array( 'page_namespace', 'page_title' ),
211 'page_id IN (' . $dbr->makeList( $ids ) . ')', __METHOD__ );
212
213 $titles = array();
214 while ( $row = $dbr->fetchObject( $res ) ) {
215 $titles[] = Title::makeTitle( $row->page_namespace, $row->page_title );
216 }
217 return $titles;
218 }
219
231 public static function &makeTitle( $ns, $title ) {
232 $t = new Title();
233 $t->mInterwiki = '';
234 $t->mFragment = '';
235 $t->mNamespace = intval( $ns );
236 $t->mDbkeyform = str_replace( ' ', '_', $title );
237 $t->mArticleID = ( $ns >= 0 ) ? -1 : 0;
238 $t->mUrlform = wfUrlencode( $t->mDbkeyform );
239 $t->mTextform = str_replace( '_', ' ', $title );
240 return $t;
241 }
242
252 public static function makeTitleSafe( $ns, $title ) {
253 $t = new Title();
254 $t->mDbkeyform = Title::makeName( $ns, $title );
255 if( $t->secureAndSplit() ) {
256 return $t;
257 } else {
258 return NULL;
259 }
260 }
261
266 public static function newMainPage() {
267 return Title::newFromText( wfMsgForContent( 'mainpage' ) );
268 }
269
276 public static function newFromRedirect( $text ) {
277 $mwRedir = MagicWord::get( 'redirect' );
278 $rt = NULL;
279 if ( $mwRedir->matchStart( $text ) ) {
280 $m = array();
281 if ( preg_match( '/\[{2}(.*?)(?:\||\]{2})/', $text, $m ) ) {
282 # categories are escaped using : for example one can enter:
283 # #REDIRECT [[:Category:Music]]. Need to remove it.
284 if ( substr($m[1],0,1) == ':') {
285 # We don't want to keep the ':'
286 $m[1] = substr( $m[1], 1 );
287 }
288
289 $rt = Title::newFromText( $m[1] );
290 # Disallow redirects to Special:Userlogout
291 if ( !is_null($rt) && $rt->isSpecial( 'Userlogout' ) ) {
292 $rt = NULL;
293 }
294 }
295 }
296 return $rt;
297 }
298
299#----------------------------------------------------------------------------
300# Static functions
301#----------------------------------------------------------------------------
302
311 function nameOf( $id ) {
312 $fname = 'Title::nameOf';
313 $dbr = wfGetDB( DB_SLAVE );
314
315 $s = $dbr->selectRow( 'page', array( 'page_namespace','page_title' ), array( 'page_id' => $id ), $fname );
316 if ( $s === false ) { return NULL; }
317
318 $n = Title::makeName( $s->page_namespace, $s->page_title );
319 return $n;
320 }
321
326 public static function legalChars() {
327 global $wgLegalTitleChars;
328
329 $wgLegalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+";
330
331 return $wgLegalTitleChars;
332 }
333
343 public static function indexTitle( $ns, $title ) {
344 global $wgContLang;
345
346 $lc = SearchEngine::legalSearchChars() . '&#;';
347 $t = $wgContLang->stripForSearch( $title );
348 $t = preg_replace( "/[^{$lc}]+/", ' ', $t );
349 $t = $wgContLang->lc( $t );
350
351 # Handle 's, s'
352 $t = preg_replace( "/([{$lc}]+)'s( |$)/", "\\1 \\1's ", $t );
353 $t = preg_replace( "/([{$lc}]+)s'( |$)/", "\\1s ", $t );
354
355 $t = preg_replace( "/\\s+/", ' ', $t );
356
357 if ( $ns == NS_IMAGE ) {
358 $t = preg_replace( "/ (png|gif|jpg|jpeg|ogg)$/", "", $t );
359 }
360 return trim( $t );
361 }
362
363 /*
364 * Make a prefixed DB key from a DB key and a namespace index
365 * @param int $ns numerical representation of the namespace
366 * @param string $title the DB key form the title
367 * @return string the prefixed form of the title
368 */
369 public static function makeName( $ns, $title ) {
370 global $wgContLang;
371
372 $n = $wgContLang->getNsText( $ns );
373 return $n == '' ? $title : "$n:$title";
374 }
375
383 public function getInterwikiLink( $key ) {
384 global $wgMemc, $wgInterwikiExpiry;
385 global $wgInterwikiCache, $wgContLang;
386
387return ""; // changed. alex
388
389 $fname = 'Title::getInterwikiLink';
390
391 $key = $wgContLang->lc( $key );
392
393 $k = wfMemcKey( 'interwiki', $key );
394 if( array_key_exists( $k, Title::$interwikiCache ) ) {
395 return Title::$interwikiCache[$k]->iw_url;
396 }
397
398 if ($wgInterwikiCache) {
399 return Title::getInterwikiCached( $key );
400 }
401
402 $s = $wgMemc->get( $k );
403 # Ignore old keys with no iw_local
404 if( $s && isset( $s->iw_local ) && isset($s->iw_trans)) {
405 Title::$interwikiCache[$k] = $s;
406 return $s->iw_url;
407 }
408
409 $dbr = wfGetDB( DB_SLAVE );
410 $res = $dbr->select( 'interwiki',
411 array( 'iw_url', 'iw_local', 'iw_trans' ),
412 array( 'iw_prefix' => $key ), $fname );
413 if( !$res ) {
414 return '';
415 }
416
417 $s = $dbr->fetchObject( $res );
418 if( !$s ) {
419 # Cache non-existence: create a blank object and save it to memcached
420 $s = (object)false;
421 $s->iw_url = '';
422 $s->iw_local = 0;
423 $s->iw_trans = 0;
424 }
425 $wgMemc->set( $k, $s, $wgInterwikiExpiry );
426 Title::$interwikiCache[$k] = $s;
427
428 return $s->iw_url;
429 }
430
438 public static function getInterwikiCached( $key ) {
439 global $wgInterwikiCache, $wgInterwikiScopes, $wgInterwikiFallbackSite;
440 static $db, $site;
441
442 if (!$db)
443 $db=dba_open($wgInterwikiCache,'r','cdb');
444 /* Resolve site name */
445 if ($wgInterwikiScopes>=3 and !$site) {
446 $site = dba_fetch('__sites:' . wfWikiID(), $db);
447 if ($site=="")
448 $site = $wgInterwikiFallbackSite;
449 }
450 $value = dba_fetch( wfMemcKey( $key ), $db);
451 if ($value=='' and $wgInterwikiScopes>=3) {
452 /* try site-level */
453 $value = dba_fetch("_{$site}:{$key}", $db);
454 }
455 if ($value=='' and $wgInterwikiScopes>=2) {
456 /* try globals */
457 $value = dba_fetch("__global:{$key}", $db);
458 }
459 if ($value=='undef')
460 $value='';
461 $s = (object)false;
462 $s->iw_url = '';
463 $s->iw_local = 0;
464 $s->iw_trans = 0;
465 if ($value!='') {
466 list($local,$url)=explode(' ',$value,2);
467 $s->iw_url=$url;
468 $s->iw_local=(int)$local;
469 }
470 Title::$interwikiCache[wfMemcKey( 'interwiki', $key )] = $s;
471 return $s->iw_url;
472 }
480 public function isLocal() {
481 if ( $this->mInterwiki != '' ) {
482 # Make sure key is loaded into cache
483 $this->getInterwikiLink( $this->mInterwiki );
484 $k = wfMemcKey( 'interwiki', $this->mInterwiki );
485 return (bool)(Title::$interwikiCache[$k]->iw_local);
486 } else {
487 return true;
488 }
489 }
490
497 public function isTrans() {
498 if ($this->mInterwiki == '')
499 return false;
500 # Make sure key is loaded into cache
501 $this->getInterwikiLink( $this->mInterwiki );
502 $k = wfMemcKey( 'interwiki', $this->mInterwiki );
503 return (bool)(Title::$interwikiCache[$k]->iw_trans);
504 }
505
509 static function escapeFragmentForURL( $fragment ) {
510 $fragment = str_replace( ' ', '_', $fragment );
511 $fragment = urlencode( Sanitizer::decodeCharReferences( $fragment ) );
512 $replaceArray = array(
513 '%3A' => ':',
514 '%' => '.'
515 );
516 return strtr( $fragment, $replaceArray );
517 }
518
519#----------------------------------------------------------------------------
520# Other stuff
521#----------------------------------------------------------------------------
522
528 public function getText() { return $this->mTextform; }
533 public function getPartialURL() { return $this->mUrlform; }
538 public function getDBkey() { return $this->mDbkeyform; }
543 public function getNamespace() { return $this->mNamespace; }
548 public function getNsText() {
549 global $wgContLang, $wgCanonicalNamespaceNames;
550
551 if ( '' != $this->mInterwiki ) {
552 // This probably shouldn't even happen. ohh man, oh yuck.
553 // But for interwiki transclusion it sometimes does.
554 // Shit. Shit shit shit.
555 //
556 // Use the canonical namespaces if possible to try to
557 // resolve a foreign namespace.
558 if( isset( $wgCanonicalNamespaceNames[$this->mNamespace] ) ) {
559 return $wgCanonicalNamespaceNames[$this->mNamespace];
560 }
561 }
562 return $wgContLang->getNsText( $this->mNamespace );
563 }
568/* public function getSubjectNsText() {
569 global $wgContLang;
570 return $wgContLang->getNsText( Namespace::getSubject( $this->mNamespace ) );
571 }*/
572
577/* public function getTalkNsText() {
578 global $wgContLang;
579 return( $wgContLang->getNsText( Namespace::getTalk( $this->mNamespace ) ) );
580 }*/
581
586/* public function canTalk() {
587 return( Namespace::canTalk( $this->mNamespace ) );
588 }*/
589
594 public function getInterwiki() { return $this->mInterwiki; }
599 public function getFragment() { return $this->mFragment; }
604 public function getFragmentForURL() {
605 if ( $this->mFragment == '' ) {
606 return '';
607 } else {
608 return '#' . Title::escapeFragmentForURL( $this->mFragment );
609 }
610 }
615 public function getDefaultNamespace() { return $this->mDefaultNamespace; }
616
622 public function getIndexTitle() {
623 return Title::indexTitle( $this->mNamespace, $this->mTextform );
624 }
625
631 public function getPrefixedDBkey() {
632 $s = $this->prefix( $this->mDbkeyform );
633 $s = str_replace( ' ', '_', $s );
634 return $s;
635 }
636
642 public function getPrefixedText() {
643 if ( empty( $this->mPrefixedText ) ) { // FIXME: bad usage of empty() ?
644 $s = $this->prefix( $this->mTextform );
645 $s = str_replace( '_', ' ', $s );
646 $this->mPrefixedText = $s;
647 }
649 }
650
657 public function getFullText() {
658 $text = $this->getPrefixedText();
659 if( '' != $this->mFragment ) {
660 $text .= '#' . $this->mFragment;
661 }
662 return $text;
663 }
664
669 public function getBaseText() {
670 global $wgNamespacesWithSubpages;
671 if( isset( $wgNamespacesWithSubpages[ $this->mNamespace ] ) && $wgNamespacesWithSubpages[ $this->mNamespace ] ) {
672 $parts = explode( '/', $this->getText() );
673 # Don't discard the real title if there's no subpage involved
674 if( count( $parts ) > 1 )
675 unset( $parts[ count( $parts ) - 1 ] );
676 return implode( '/', $parts );
677 } else {
678 return $this->getText();
679 }
680 }
681
686 public function getSubpageText() {
687 global $wgNamespacesWithSubpages;
688 if( isset( $wgNamespacesWithSubpages[ $this->mNamespace ] ) && $wgNamespacesWithSubpages[ $this->mNamespace ] ) {
689 $parts = explode( '/', $this->mTextform );
690 return( $parts[ count( $parts ) - 1 ] );
691 } else {
692 return( $this->mTextform );
693 }
694 }
695
700 public function getSubpageUrlForm() {
701 $text = $this->getSubpageText();
702 $text = wfUrlencode( str_replace( ' ', '_', $text ) );
703 $text = str_replace( '%28', '(', str_replace( '%29', ')', $text ) ); # Clean up the URL; per below, this might not be safe
704 return( $text );
705 }
706
711 public function getPrefixedURL() {
712 $s = $this->prefix( $this->mDbkeyform );
713 $s = str_replace( ' ', '_', $s );
714
715 $s = wfUrlencode ( $s ) ;
716
717 # Cleaning up URL to make it look nice -- is this safe?
718 $s = str_replace( '%28', '(', $s );
719 $s = str_replace( '%29', ')', $s );
720
721 return $s;
722 }
723
733 public function getFullURL( $query = '', $variant = false ) {
734 global $wgContLang, $wgServer, $wgRequest;
735
736 if ( '' == $this->mInterwiki ) {
737 $url = $this->getLocalUrl( $query, $variant );
738
739 // Ugly quick hack to avoid duplicate prefixes (bug 4571 etc)
740 // Correct fix would be to move the prepending elsewhere.
741 if ($wgRequest->getVal('action') != 'render') {
742 $url = $wgServer . $url;
743 }
744 } else {
745 $baseUrl = $this->getInterwikiLink( $this->mInterwiki );
746
747 $namespace = wfUrlencode( $this->getNsText() );
748 if ( '' != $namespace ) {
749 # Can this actually happen? Interwikis shouldn't be parsed.
750 # Yes! It can in interwiki transclusion. But... it probably shouldn't.
751 $namespace .= ':';
752 }
753 $url = str_replace( '$1', $namespace . $this->mUrlform, $baseUrl );
754 $url = wfAppendQuery( $url, $query );
755 }
756
757 # Finally, add the fragment.
758 $url .= $this->getFragmentForURL();
759
760 wfRunHooks( 'GetFullURL', array( &$this, &$url, $query ) );
761 return $url;
762 }
763
772 public function getLocalURL( $query = '', $variant = false ) {
773 global $wgArticlePath, $wgScript, $wgServer, $wgRequest;
774 global $wgVariantArticlePath, $wgContLang, $wgUser;
775
776 // internal links should point to same variant as current page (only anonymous users)
777 if($variant == false && $wgContLang->hasVariants() && !$wgUser->isLoggedIn()){
778 $pref = $wgContLang->getPreferredVariant(false);
779 if($pref != $wgContLang->getCode())
780 $variant = $pref;
781 }
782
783 if ( $this->isExternal() ) {
784 $url = $this->getFullURL();
785 if ( $query ) {
786 // This is currently only used for edit section links in the
787 // context of interwiki transclusion. In theory we should
788 // append the query to the end of any existing query string,
789 // but interwiki transclusion is already broken in that case.
790 $url .= "?$query";
791 }
792 } else {
793 $dbkey = wfUrlencode( $this->getPrefixedDBkey() );
794 if ( $query == '' ) {
795 if($variant!=false && $wgContLang->hasVariants()){
796 if($wgVariantArticlePath==false) {
797 $variantArticlePath = "$wgScript?title=$1&variant=$2"; // default
798 } else {
799 $variantArticlePath = $wgVariantArticlePath;
800 }
801 $url = str_replace( '$2', urlencode( $variant ), $variantArticlePath );
802 $url = str_replace( '$1', $dbkey, $url );
803 }
804 else {
805 $url = str_replace( '$1', $dbkey, $wgArticlePath );
806 }
807 } else {
808 global $wgActionPaths;
809 $url = false;
810 $matches = array();
811 if( !empty( $wgActionPaths ) &&
812 preg_match( '/^(.*&|)action=([^&]*)(&(.*)|)$/', $query, $matches ) )
813 {
814 $action = urldecode( $matches[2] );
815 if( isset( $wgActionPaths[$action] ) ) {
816 $query = $matches[1];
817 if( isset( $matches[4] ) ) $query .= $matches[4];
818 $url = str_replace( '$1', $dbkey, $wgActionPaths[$action] );
819 if( $query != '' ) $url .= '?' . $query;
820 }
821 }
822 if ( $url === false ) {
823 if ( $query == '-' ) {
824 $query = '';
825 }
826 $url = "{$wgScript}?title={$dbkey}&{$query}";
827 }
828 }
829
830 // FIXME: this causes breakage in various places when we
831 // actually expected a local URL and end up with dupe prefixes.
832 if ($wgRequest->getVal('action') == 'render') {
833 $url = $wgServer . $url;
834 }
835 }
836 wfRunHooks( 'GetLocalURL', array( &$this, &$url, $query ) );
837 return $url;
838 }
839
846 public function escapeLocalURL( $query = '' ) {
847 return htmlspecialchars( $this->getLocalURL( $query ) );
848 }
849
857 public function escapeFullURL( $query = '' ) {
858 return htmlspecialchars( $this->getFullURL( $query ) );
859 }
860
870 public function getInternalURL( $query = '', $variant = false ) {
871 global $wgInternalServer;
872 $url = $wgInternalServer . $this->getLocalURL( $query, $variant );
873 wfRunHooks( 'GetInternalURL', array( &$this, &$url, $query ) );
874 return $url;
875 }
876
882 public function getEditURL() {
883 if ( '' != $this->mInterwiki ) { return ''; }
884 $s = $this->getLocalURL( 'action=edit' );
885
886 return $s;
887 }
888
894 public function getEscapedText() {
895 return htmlspecialchars( $this->getPrefixedText() );
896 }
897
902 public function isExternal() { return ( '' != $this->mInterwiki ); }
903
910 public function isSemiProtected( $action = 'edit' ) {
911 if( $this->exists() ) {
912 $restrictions = $this->getRestrictions( $action );
913 if( count( $restrictions ) > 0 ) {
914 foreach( $restrictions as $restriction ) {
915 if( strtolower( $restriction ) != 'autoconfirmed' )
916 return false;
917 }
918 } else {
919 # Not protected
920 return false;
921 }
922 return true;
923 } else {
924 # If it doesn't exist, it can't be protected
925 return false;
926 }
927 }
928
935 public function isProtected( $action = '' ) {
936 global $wgRestrictionLevels;
937
938 # Special pages have inherent protection
939 if( $this->getNamespace() == NS_SPECIAL )
940 return true;
941
942 # Check regular protection levels
943 if( $action == 'edit' || $action == '' ) {
944 $r = $this->getRestrictions( 'edit' );
945 foreach( $wgRestrictionLevels as $level ) {
946 if( in_array( $level, $r ) && $level != '' ) {
947 return( true );
948 }
949 }
950 }
951
952 if( $action == 'move' || $action == '' ) {
953 $r = $this->getRestrictions( 'move' );
954 foreach( $wgRestrictionLevels as $level ) {
955 if( in_array( $level, $r ) && $level != '' ) {
956 return( true );
957 }
958 }
959 }
960
961 return false;
962 }
963
968 public function userIsWatching() {
969 global $wgUser;
970
971 if ( is_null( $this->mWatched ) ) {
972 if ( NS_SPECIAL == $this->mNamespace || !$wgUser->isLoggedIn()) {
973 $this->mWatched = false;
974 } else {
975 $this->mWatched = $wgUser->isWatched( $this );
976 }
977 }
978 return $this->mWatched;
979 }
980
993 public function quickUserCan( $action ) {
994 return $this->userCan( $action, false );
995 }
996
1003 public function userCan( $action, $doExpensiveQueries = true ) {
1004 $fname = 'Title::userCan';
1005 wfProfileIn( $fname );
1006
1007 global $wgUser, $wgNamespaceProtection;
1008
1009 $result = null;
1010 wfRunHooks( 'userCan', array( &$this, &$wgUser, $action, &$result ) );
1011 if ( $result !== null ) {
1012 wfProfileOut( $fname );
1013 return $result;
1014 }
1015
1016 if( NS_SPECIAL == $this->mNamespace ) {
1017 wfProfileOut( $fname );
1018 return false;
1019 }
1020
1021 if ( array_key_exists( $this->mNamespace, $wgNamespaceProtection ) ) {
1022 $nsProt = $wgNamespaceProtection[ $this->mNamespace ];
1023 if ( !is_array($nsProt) ) $nsProt = array($nsProt);
1024 foreach( $nsProt as $right ) {
1025 if( '' != $right && !$wgUser->isAllowed( $right ) ) {
1026 wfProfileOut( $fname );
1027 return false;
1028 }
1029 }
1030 }
1031
1032 if( $this->mDbkeyform == '_' ) {
1033 # FIXME: Is this necessary? Shouldn't be allowed anyway...
1034 wfProfileOut( $fname );
1035 return false;
1036 }
1037
1038 # protect css/js subpages of user pages
1039 # XXX: this might be better using restrictions
1040 # XXX: Find a way to work around the php bug that prevents using $this->userCanEditCssJsSubpage() from working
1041 if( $this->isCssJsSubpage()
1042 && !$wgUser->isAllowed('editinterface')
1043 && !preg_match('/^'.preg_quote($wgUser->getName(), '/').'\//', $this->mTextform) ) {
1044 wfProfileOut( $fname );
1045 return false;
1046 }
1047
1048 if ( $doExpensiveQueries && !$this->isCssJsSubpage() ) {
1049 # We /could/ use the protection level on the source page, but it's fairly ugly
1050 # as we have to establish a precedence hierarchy for pages included by multiple
1051 # cascade-protected pages. So just restrict it to people with 'protect' permission,
1052 # as they could remove the protection anyway.
1053 list( $cascadingSources, $restrictions ) = $this->getCascadeProtectionSources();
1054 # Cascading protection depends on more than this page...
1055 # Several cascading protected pages may include this page...
1056 # Check each cascading level
1057 # This is only for protection restrictions, not for all actions
1058 if( $cascadingSources > 0 && isset($restrictions[$action]) ) {
1059 foreach( $restrictions[$action] as $right ) {
1060 $right = ( $right == 'sysop' ) ? 'protect' : $right;
1061 if( '' != $right && !$wgUser->isAllowed( $right ) ) {
1062 wfProfileOut( $fname );
1063 return false;
1064 }
1065 }
1066 }
1067 }
1068
1069 foreach( $this->getRestrictions($action) as $right ) {
1070 // Backwards compatibility, rewrite sysop -> protect
1071 if ( $right == 'sysop' ) {
1072 $right = 'protect';
1073 }
1074 if( '' != $right && !$wgUser->isAllowed( $right ) ) {
1075 wfProfileOut( $fname );
1076 return false;
1077 }
1078 }
1079
1080 if( $action == 'move' &&
1081 !( $this->isMovable() && $wgUser->isAllowed( 'move' ) ) ) {
1082 wfProfileOut( $fname );
1083 return false;
1084 }
1085
1086 if( $action == 'create' ) {
1087 if( ( $this->isTalkPage() && !$wgUser->isAllowed( 'createtalk' ) ) ||
1088 ( !$this->isTalkPage() && !$wgUser->isAllowed( 'createpage' ) ) ) {
1089 wfProfileOut( $fname );
1090 return false;
1091 }
1092 }
1093
1094 wfProfileOut( $fname );
1095 return true;
1096 }
1097
1103 public function userCanEdit( $doExpensiveQueries = true ) {
1104 return $this->userCan( 'edit', $doExpensiveQueries );
1105 }
1106
1112 public function userCanCreate( $doExpensiveQueries = true ) {
1113 return $this->userCan( 'create', $doExpensiveQueries );
1114 }
1115
1121 public function userCanMove( $doExpensiveQueries = true ) {
1122 return $this->userCan( 'move', $doExpensiveQueries );
1123 }
1124
1131/* public function isMovable() {
1132 return Namespace::isMovable( $this->getNamespace() )
1133 && $this->getInterwiki() == '';
1134 }*/
1135
1141 public function userCanRead() {
1142 global $wgUser;
1143
1144 $result = null;
1145 wfRunHooks( 'userCan', array( &$this, &$wgUser, 'read', &$result ) );
1146 if ( $result !== null ) {
1147 return $result;
1148 }
1149
1150 if( $wgUser->isAllowed('read') ) {
1151 return true;
1152 } else {
1153 global $wgWhitelistRead;
1154
1159 if( $this->isSpecial( 'Userlogin' ) || $this->isSpecial( 'Resetpass' ) ) {
1160 return true;
1161 }
1162
1164 $name = $this->getPrefixedText();
1165 if( $wgWhitelistRead && in_array( $name, $wgWhitelistRead ) ) {
1166 return true;
1167 }
1168
1169 # Compatibility with old settings
1170 if( $wgWhitelistRead && $this->getNamespace() == NS_MAIN ) {
1171 if( in_array( ':' . $name, $wgWhitelistRead ) ) {
1172 return true;
1173 }
1174 }
1175 }
1176 return false;
1177 }
1178
1183/* public function isTalkPage() {
1184 return Namespace::isTalk( $this->getNamespace() );
1185 }*/
1186
1191 public function isSubpage() {
1192 global $wgNamespacesWithSubpages;
1193
1194 if( isset( $wgNamespacesWithSubpages[ $this->mNamespace ] ) ) {
1195 return ( strpos( $this->getText(), '/' ) !== false && $wgNamespacesWithSubpages[ $this->mNamespace ] == true );
1196 } else {
1197 return false;
1198 }
1199 }
1200
1205 public function isCssJsSubpage() {
1206 return ( NS_USER == $this->mNamespace and preg_match("/\\/.*\\.(?:css|js)$/", $this->mTextform ) );
1207 }
1212 public function isValidCssJsSubpage() {
1213 if ( $this->isCssJsSubpage() ) {
1214 $skinNames = Skin::getSkinNames();
1215 return array_key_exists( $this->getSkinFromCssJsSubpage(), $skinNames );
1216 } else {
1217 return false;
1218 }
1219 }
1223 public function getSkinFromCssJsSubpage() {
1224 $subpage = explode( '/', $this->mTextform );
1225 $subpage = $subpage[ count( $subpage ) - 1 ];
1226 return( str_replace( array( '.css', '.js' ), array( '', '' ), $subpage ) );
1227 }
1232 public function isCssSubpage() {
1233 return ( NS_USER == $this->mNamespace and preg_match("/\\/.*\\.css$/", $this->mTextform ) );
1234 }
1239 public function isJsSubpage() {
1240 return ( NS_USER == $this->mNamespace and preg_match("/\\/.*\\.js$/", $this->mTextform ) );
1241 }
1249 public function userCanEditCssJsSubpage() {
1250 global $wgUser;
1251 return ( $wgUser->isAllowed('editinterface') or preg_match('/^'.preg_quote($wgUser->getName(), '/').'\//', $this->mTextform) );
1252 }
1253
1259 public function isCascadeProtected() {
1260 list( $sources, $restrictions ) = $this->getCascadeProtectionSources( false );
1261 return ( $sources > 0 );
1262 }
1263
1272 public function getCascadeProtectionSources( $get_pages = true ) {
1273 global $wgEnableCascadingProtection, $wgRestrictionTypes;
1274
1275 # Define our dimension of restrictions types
1276 $pagerestrictions = array();
1277 foreach( $wgRestrictionTypes as $action )
1278 $pagerestrictions[$action] = array();
1279
1280 if (!$wgEnableCascadingProtection)
1281 return array( false, $pagerestrictions );
1282
1283 if ( isset( $this->mCascadeSources ) && $get_pages ) {
1284 return array( $this->mCascadeSources, $this->mCascadingRestrictions );
1285 } else if ( isset( $this->mHasCascadingRestrictions ) && !$get_pages ) {
1286 return array( $this->mHasCascadingRestrictions, $pagerestrictions );
1287 }
1288
1289 wfProfileIn( __METHOD__ );
1290
1291 $dbr = wfGetDb( DB_SLAVE );
1292
1293 if ( $this->getNamespace() == NS_IMAGE ) {
1294 $tables = array ('imagelinks', 'page_restrictions');
1295 $where_clauses = array(
1296 'il_to' => $this->getDBkey(),
1297 'il_from=pr_page',
1298 'pr_cascade' => 1 );
1299 } else {
1300 $tables = array ('templatelinks', 'page_restrictions');
1301 $where_clauses = array(
1302 'tl_namespace' => $this->getNamespace(),
1303 'tl_title' => $this->getDBkey(),
1304 'tl_from=pr_page',
1305 'pr_cascade' => 1 );
1306 }
1307
1308 if ( $get_pages ) {
1309 $cols = array('pr_page', 'page_namespace', 'page_title', 'pr_expiry', 'pr_type', 'pr_level' );
1310 $where_clauses[] = 'page_id=pr_page';
1311 $tables[] = 'page';
1312 } else {
1313 $cols = array( 'pr_expiry' );
1314 }
1315
1316 $res = $dbr->select( $tables, $cols, $where_clauses, __METHOD__ );
1317
1318 $sources = $get_pages ? array() : false;
1319 $now = wfTimestampNow();
1320 $purgeExpired = false;
1321
1322 while( $row = $dbr->fetchObject( $res ) ) {
1323 $expiry = Block::decodeExpiry( $row->pr_expiry );
1324 if( $expiry > $now ) {
1325 if ($get_pages) {
1326 $page_id = $row->pr_page;
1327 $page_ns = $row->page_namespace;
1328 $page_title = $row->page_title;
1329 $sources[$page_id] = Title::makeTitle($page_ns, $page_title);
1330 # Add groups needed for each restriction type if its not already there
1331 # Make sure this restriction type still exists
1332 if ( isset($pagerestrictions[$row->pr_type]) && !in_array($row->pr_level, $pagerestrictions[$row->pr_type]) ) {
1333 $pagerestrictions[$row->pr_type][]=$row->pr_level;
1334 }
1335 } else {
1336 $sources = true;
1337 }
1338 } else {
1339 // Trigger lazy purge of expired restrictions from the db
1340 $purgeExpired = true;
1341 }
1342 }
1343 if( $purgeExpired ) {
1345 }
1346
1347 wfProfileOut( __METHOD__ );
1348
1349 if ( $get_pages ) {
1350 $this->mCascadeSources = $sources;
1351 $this->mCascadingRestrictions = $pagerestrictions;
1352 } else {
1353 $this->mHasCascadingRestrictions = $sources;
1354 }
1355
1356 return array( $sources, $pagerestrictions );
1357 }
1358
1360 if (!$this->mRestrictionsLoaded) {
1361 $this->loadRestrictions();
1362 }
1363
1365 }
1366
1371 private function loadRestrictionsFromRow( $res, $oldFashionedRestrictions = NULL ) {
1372 $dbr = wfGetDb( DB_SLAVE );
1373
1374 $this->mRestrictions['edit'] = array();
1375 $this->mRestrictions['move'] = array();
1376
1377 # Backwards-compatibility: also load the restrictions from the page record (old format).
1378
1379 if ( $oldFashionedRestrictions == NULL ) {
1380 $oldFashionedRestrictions = $dbr->selectField( 'page', 'page_restrictions', array( 'page_id' => $this->getArticleId() ), __METHOD__ );
1381 }
1382
1383 if ($oldFashionedRestrictions != '') {
1384
1385 foreach( explode( ':', trim( $oldFashionedRestrictions ) ) as $restrict ) {
1386 $temp = explode( '=', trim( $restrict ) );
1387 if(count($temp) == 1) {
1388 // old old format should be treated as edit/move restriction
1389 $this->mRestrictions["edit"] = explode( ',', trim( $temp[0] ) );
1390 $this->mRestrictions["move"] = explode( ',', trim( $temp[0] ) );
1391 } else {
1392 $this->mRestrictions[$temp[0]] = explode( ',', trim( $temp[1] ) );
1393 }
1394 }
1395
1396 $this->mOldRestrictions = true;
1397 $this->mCascadeRestriction = false;
1398 $this->mRestrictionsExpiry = Block::decodeExpiry('');
1399
1400 }
1401
1402 if( $dbr->numRows( $res ) ) {
1403 # Current system - load second to make them override.
1404 $now = wfTimestampNow();
1405 $purgeExpired = false;
1406
1407 while ($row = $dbr->fetchObject( $res ) ) {
1408 # Cycle through all the restrictions.
1409
1410 // This code should be refactored, now that it's being used more generally,
1411 // But I don't really see any harm in leaving it in Block for now -werdna
1412 $expiry = Block::decodeExpiry( $row->pr_expiry );
1413
1414 // Only apply the restrictions if they haven't expired!
1415 if ( !$expiry || $expiry > $now ) {
1416 $this->mRestrictionsExpiry = $expiry;
1417 $this->mRestrictions[$row->pr_type] = explode( ',', trim( $row->pr_level ) );
1418
1419 $this->mCascadeRestriction |= $row->pr_cascade;
1420 } else {
1421 // Trigger a lazy purge of expired restrictions
1422 $purgeExpired = true;
1423 }
1424 }
1425
1426 if( $purgeExpired ) {
1428 }
1429 }
1430
1431 $this->mRestrictionsLoaded = true;
1432 }
1433
1434 public function loadRestrictions( $oldFashionedRestrictions = NULL ) {
1435 if( !$this->mRestrictionsLoaded ) {
1436 $dbr = wfGetDB( DB_SLAVE );
1437
1438 $res = $dbr->select( 'page_restrictions', '*',
1439 array ( 'pr_page' => $this->getArticleId() ), __METHOD__ );
1440
1441 $this->loadRestrictionsFromRow( $res, $oldFashionedRestrictions );
1442 }
1443 }
1444
1448 static function purgeExpiredRestrictions() {
1449 $dbw = wfGetDB( DB_MASTER );
1450 $dbw->delete( 'page_restrictions',
1451 array( 'pr_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ),
1452 __METHOD__ );
1453 }
1454
1461 public function getRestrictions( $action ) {
1462 if( $this->exists() ) {
1463 if( !$this->mRestrictionsLoaded ) {
1464 $this->loadRestrictions();
1465 }
1466 return isset( $this->mRestrictions[$action] )
1467 ? $this->mRestrictions[$action]
1468 : array();
1469 } else {
1470 return array();
1471 }
1472 }
1473
1478 public function isDeleted() {
1479 $fname = 'Title::isDeleted';
1480 if ( $this->getNamespace() < 0 ) {
1481 $n = 0;
1482 } else {
1483 $dbr = wfGetDB( DB_SLAVE );
1484 $n = $dbr->selectField( 'archive', 'COUNT(*)', array( 'ar_namespace' => $this->getNamespace(),
1485 'ar_title' => $this->getDBkey() ), $fname );
1486 if( $this->getNamespace() == NS_IMAGE ) {
1487 $n += $dbr->selectField( 'filearchive', 'COUNT(*)',
1488 array( 'fa_name' => $this->getDBkey() ), $fname );
1489 }
1490 }
1491 return (int)$n;
1492 }
1493
1501 public function getArticleID( $flags = 0 ) {
1502 $linkCache =& LinkCache::singleton();
1503 if ( $flags & GAID_FOR_UPDATE ) {
1504 $oldUpdate = $linkCache->forUpdate( true );
1505 $this->mArticleID = $linkCache->addLinkObj( $this );
1506 $linkCache->forUpdate( $oldUpdate );
1507 } else {
1508 if ( -1 == $this->mArticleID ) {
1509 $this->mArticleID = $linkCache->addLinkObj( $this );
1510 }
1511 }
1512 return $this->mArticleID;
1513 }
1514
1515 public function getLatestRevID() {
1516 if ($this->mLatestID !== false)
1517 return $this->mLatestID;
1518
1519 $db = wfGetDB(DB_SLAVE);
1520 return $this->mLatestID = $db->selectField( 'revision',
1521 "max(rev_id)",
1522 array('rev_page' => $this->getArticleID()),
1523 'Title::getLatestRevID' );
1524 }
1525
1536 public function resetArticleID( $newid ) {
1537 $linkCache =& LinkCache::singleton();
1538 $linkCache->clearBadLink( $this->getPrefixedDBkey() );
1539
1540 if ( 0 == $newid ) { $this->mArticleID = -1; }
1541 else { $this->mArticleID = $newid; }
1542 $this->mRestrictionsLoaded = false;
1543 $this->mRestrictions = array();
1544 }
1545
1550 public function invalidateCache() {
1551 global $wgUseFileCache;
1552
1553 if ( wfReadOnly() ) {
1554 return;
1555 }
1556
1557 $dbw = wfGetDB( DB_MASTER );
1558 $success = $dbw->update( 'page',
1559 array( /* SET */
1560 'page_touched' => $dbw->timestamp()
1561 ), array( /* WHERE */
1562 'page_namespace' => $this->getNamespace() ,
1563 'page_title' => $this->getDBkey()
1564 ), 'Title::invalidateCache'
1565 );
1566
1567 if ($wgUseFileCache) {
1568 $cache = new HTMLFileCache($this);
1569 @unlink($cache->fileCacheName());
1570 }
1571
1572 return $success;
1573 }
1574
1583 /* private */ function prefix( $name ) {
1584 $p = '';
1585 if ( '' != $this->mInterwiki ) {
1586 $p = $this->mInterwiki . ':';
1587 }
1588 if ( 0 != $this->mNamespace ) {
1589 $p .= $this->getNsText() . ':';
1590 }
1591 return $p . $name;
1592 }
1593
1604 private function secureAndSplit() {
1605 global $wgContLang, $wgLocalInterwiki, $wgCapitalLinks;
1606
1607 # Initialisation
1608 static $rxTc = false;
1609 if( !$rxTc ) {
1610 # % is needed as well
1611 $rxTc = '/[^' . Title::legalChars() . ']|%[0-9A-Fa-f]{2}/S';
1612 }
1613
1614 $this->mInterwiki = $this->mFragment = '';
1615 $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN
1616
1617 $dbkey = $this->mDbkeyform;
1618
1619 # Strip Unicode bidi override characters.
1620 # Sometimes they slip into cut-n-pasted page titles, where the
1621 # override chars get included in list displays.
1622 $dbkey = str_replace( "\xE2\x80\x8E", '', $dbkey ); // 200E LEFT-TO-RIGHT MARK
1623 $dbkey = str_replace( "\xE2\x80\x8F", '', $dbkey ); // 200F RIGHT-TO-LEFT MARK
1624
1625 # Clean up whitespace
1626 #
1627 $dbkey = preg_replace( '/[ _]+/', '_', $dbkey );
1628 $dbkey = trim( $dbkey, '_' );
1629
1630 if ( '' == $dbkey ) {
1631 return false;
1632 }
1633
1634 if( false !== strpos( $dbkey, UTF8_REPLACEMENT ) ) {
1635 # Contained illegal UTF-8 sequences or forbidden Unicode chars.
1636 return false;
1637 }
1638
1639 $this->mDbkeyform = $dbkey;
1640
1641 # Initial colon indicates main namespace rather than specified default
1642 # but should not create invalid {ns,title} pairs such as {0,Project:Foo}
1643 if ( ':' == $dbkey{0} ) {
1644 $this->mNamespace = NS_MAIN;
1645 $dbkey = substr( $dbkey, 1 ); # remove the colon but continue processing
1646 $dbkey = trim( $dbkey, '_' ); # remove any subsequent whitespace
1647 }
1648
1649 # Namespace or interwiki prefix
1650 $firstPass = true;
1651 do {
1652 $m = array();
1653 if ( preg_match( "/^(.+?)_*:_*(.*)$/S", $dbkey, $m ) ) {
1654 $p = $m[1];
1655 if ( $ns = $wgContLang->getNsIndex( $p )) {
1656 # Ordinary namespace
1657 $dbkey = $m[2];
1658 $this->mNamespace = $ns;
1659 } elseif( $this->getInterwikiLink( $p ) ) {
1660 if( !$firstPass ) {
1661 # Can't make a local interwiki link to an interwiki link.
1662 # That's just crazy!
1663 return false;
1664 }
1665
1666 # Interwiki link
1667 $dbkey = $m[2];
1668 $this->mInterwiki = $wgContLang->lc( $p );
1669
1670 # Redundant interwiki prefix to the local wiki
1671 if ( 0 == strcasecmp( $this->mInterwiki, $wgLocalInterwiki ) ) {
1672 if( $dbkey == '' ) {
1673 # Can't have an empty self-link
1674 return false;
1675 }
1676 $this->mInterwiki = '';
1677 $firstPass = false;
1678 # Do another namespace split...
1679 continue;
1680 }
1681
1682 # If there's an initial colon after the interwiki, that also
1683 # resets the default namespace
1684 if ( $dbkey !== '' && $dbkey[0] == ':' ) {
1685 $this->mNamespace = NS_MAIN;
1686 $dbkey = substr( $dbkey, 1 );
1687 }
1688 }
1689 # If there's no recognized interwiki or namespace,
1690 # then let the colon expression be part of the title.
1691 }
1692 break;
1693 } while( true );
1694
1695 # We already know that some pages won't be in the database!
1696 #
1697 if ( '' != $this->mInterwiki || NS_SPECIAL == $this->mNamespace ) {
1698 $this->mArticleID = 0;
1699 }
1700 $fragment = strstr( $dbkey, '#' );
1701 if ( false !== $fragment ) {
1702 $this->setFragment( $fragment );
1703 $dbkey = substr( $dbkey, 0, strlen( $dbkey ) - strlen( $fragment ) );
1704 # remove whitespace again: prevents "Foo_bar_#"
1705 # becoming "Foo_bar_"
1706 $dbkey = preg_replace( '/_*$/', '', $dbkey );
1707 }
1708
1709 # Reject illegal characters.
1710 #
1711 if( preg_match( $rxTc, $dbkey ) ) {
1712 return false;
1713 }
1714
1720 if ( strpos( $dbkey, '.' ) !== false &&
1721 ( $dbkey === '.' || $dbkey === '..' ||
1722 strpos( $dbkey, './' ) === 0 ||
1723 strpos( $dbkey, '../' ) === 0 ||
1724 strpos( $dbkey, '/./' ) !== false ||
1725 strpos( $dbkey, '/../' ) !== false ) )
1726 {
1727 return false;
1728 }
1729
1733 if( strpos( $dbkey, '~~~' ) !== false ) {
1734 return false;
1735 }
1736
1744 if ( ( $this->mNamespace != NS_SPECIAL && strlen( $dbkey ) > 255 ) ||
1745 strlen( $dbkey ) > 512 )
1746 {
1747 return false;
1748 }
1749
1758 if( $wgCapitalLinks && $this->mInterwiki == '') {
1759 $dbkey = $wgContLang->ucfirst( $dbkey );
1760 }
1761
1767 if( $dbkey == '' &&
1768 $this->mInterwiki == '' &&
1769 $this->mNamespace != NS_MAIN ) {
1770 return false;
1771 }
1772
1773 // Any remaining initial :s are illegal.
1774 if ( $dbkey !== '' && ':' == $dbkey{0} ) {
1775 return false;
1776 }
1777
1778 # Fill fields
1779 $this->mDbkeyform = $dbkey;
1780 $this->mUrlform = ilWikiUtil::wfUrlencode( $dbkey );
1781
1782 $this->mTextform = str_replace( '_', ' ', $dbkey );
1783
1784 return true;
1785 }
1786
1796 public function setFragment( $fragment ) {
1797 $this->mFragment = str_replace( '_', ' ', substr( $fragment, 1 ) );
1798 }
1799
1804/* public function getTalkPage() {
1805 return Title::makeTitle( Namespace::getTalk( $this->getNamespace() ), $this->getDBkey() );
1806 }*/
1807
1814/* public function getSubjectPage() {
1815 return Title::makeTitle( Namespace::getSubject( $this->getNamespace() ), $this->getDBkey() );
1816 }*/
1817
1828 public function getLinksTo( $options = '', $table = 'pagelinks', $prefix = 'pl' ) {
1829 $linkCache =& LinkCache::singleton();
1830
1831 if ( $options ) {
1832 $db = wfGetDB( DB_MASTER );
1833 } else {
1834 $db = wfGetDB( DB_SLAVE );
1835 }
1836
1837 $res = $db->select( array( 'page', $table ),
1838 array( 'page_namespace', 'page_title', 'page_id' ),
1839 array(
1840 "{$prefix}_from=page_id",
1841 "{$prefix}_namespace" => $this->getNamespace(),
1842 "{$prefix}_title" => $this->getDbKey() ),
1843 'Title::getLinksTo',
1844 $options );
1845
1846 $retVal = array();
1847 if ( $db->numRows( $res ) ) {
1848 while ( $row = $db->fetchObject( $res ) ) {
1849 if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
1850 $linkCache->addGoodLinkObj( $row->page_id, $titleObj );
1851 $retVal[] = $titleObj;
1852 }
1853 }
1854 }
1855 $db->freeResult( $res );
1856 return $retVal;
1857 }
1858
1869 public function getTemplateLinksTo( $options = '' ) {
1870 return $this->getLinksTo( $options, 'templatelinks', 'tl' );
1871 }
1872
1879 public function getBrokenLinksFrom( $options = '' ) {
1880 if ( $options ) {
1881 $db = wfGetDB( DB_MASTER );
1882 } else {
1883 $db = wfGetDB( DB_SLAVE );
1884 }
1885
1886 $res = $db->safeQuery(
1887 "SELECT pl_namespace, pl_title
1888 FROM !
1889 LEFT JOIN !
1890 ON pl_namespace=page_namespace
1891 AND pl_title=page_title
1892 WHERE pl_from=?
1893 AND page_namespace IS NULL
1894 !",
1895 $db->tableName( 'pagelinks' ),
1896 $db->tableName( 'page' ),
1897 $this->getArticleId(),
1898 $options );
1899
1900 $retVal = array();
1901 if ( $db->numRows( $res ) ) {
1902 while ( $row = $db->fetchObject( $res ) ) {
1903 $retVal[] = Title::makeTitle( $row->pl_namespace, $row->pl_title );
1904 }
1905 }
1906 $db->freeResult( $res );
1907 return $retVal;
1908 }
1909
1910
1917 public function getSquidURLs() {
1918 global $wgContLang;
1919
1920 $urls = array(
1921 $this->getInternalURL(),
1922 $this->getInternalURL( 'action=history' )
1923 );
1924
1925 // purge variant urls as well
1926 if($wgContLang->hasVariants()){
1927 $variants = $wgContLang->getVariants();
1928 foreach($variants as $vCode){
1929 if($vCode==$wgContLang->getCode()) continue; // we don't want default variant
1930 $urls[] = $this->getInternalURL('',$vCode);
1931 }
1932 }
1933
1934 return $urls;
1935 }
1936
1937 public function purgeSquid() {
1938 global $wgUseSquid;
1939 if ( $wgUseSquid ) {
1940 $urls = $this->getSquidURLs();
1941 $u = new SquidUpdate( $urls );
1942 $u->doUpdate();
1943 }
1944 }
1945
1950 public function moveNoAuth( &$nt ) {
1951 return $this->moveTo( $nt, false );
1952 }
1953
1963 public function isValidMoveOperation( &$nt, $auth = true ) {
1964 if( !$this or !$nt ) {
1965 return 'badtitletext';
1966 }
1967 if( $this->equals( $nt ) ) {
1968 return 'selfmove';
1969 }
1970 if( !$this->isMovable() || !$nt->isMovable() ) {
1971 return 'immobile_namespace';
1972 }
1973
1974 $oldid = $this->getArticleID();
1975 $newid = $nt->getArticleID();
1976
1977 if ( strlen( $nt->getDBkey() ) < 1 ) {
1978 return 'articleexists';
1979 }
1980 if ( ( '' == $this->getDBkey() ) ||
1981 ( !$oldid ) ||
1982 ( '' == $nt->getDBkey() ) ) {
1983 return 'badarticleerror';
1984 }
1985
1986 if ( $auth && (
1987 !$this->userCan( 'edit' ) || !$nt->userCan( 'edit' ) ||
1988 !$this->userCan( 'move' ) || !$nt->userCan( 'move' ) ) ) {
1989 return 'protectedpage';
1990 }
1991
1992 # The move is allowed only if (1) the target doesn't exist, or
1993 # (2) the target is a redirect to the source, and has no history
1994 # (so we can undo bad moves right after they're done).
1995
1996 if ( 0 != $newid ) { # Target exists; check for validity
1997 if ( ! $this->isValidMoveTarget( $nt ) ) {
1998 return 'articleexists';
1999 }
2000 }
2001 return true;
2002 }
2003
2011 public function moveTo( &$nt, $auth = true, $reason = '' ) {
2012 $err = $this->isValidMoveOperation( $nt, $auth );
2013 if( is_string( $err ) ) {
2014 return $err;
2015 }
2016
2017 $pageid = $this->getArticleID();
2018 if( $nt->exists() ) {
2019 $this->moveOverExistingRedirect( $nt, $reason );
2020 $pageCountChange = 0;
2021 } else { # Target didn't exist, do normal move.
2022 $this->moveToNewTitle( $nt, $reason );
2023 $pageCountChange = 1;
2024 }
2025 $redirid = $this->getArticleID();
2026
2027 # Fixing category links (those without piped 'alternate' names) to be sorted under the new title
2028 $dbw = wfGetDB( DB_MASTER );
2029 $categorylinks = $dbw->tableName( 'categorylinks' );
2030 $sql = "UPDATE $categorylinks SET cl_sortkey=" . $dbw->addQuotes( $nt->getPrefixedText() ) .
2031 " WHERE cl_from=" . $dbw->addQuotes( $pageid ) .
2032 " AND cl_sortkey=" . $dbw->addQuotes( $this->getPrefixedText() );
2033 $dbw->query( $sql, 'SpecialMovepage::doSubmit' );
2034
2035 # Update watchlists
2036
2037 $oldnamespace = $this->getNamespace() & ~1;
2038 $newnamespace = $nt->getNamespace() & ~1;
2039 $oldtitle = $this->getDBkey();
2040 $newtitle = $nt->getDBkey();
2041
2042 if( $oldnamespace != $newnamespace || $oldtitle != $newtitle ) {
2043 WatchedItem::duplicateEntries( $this, $nt );
2044 }
2045
2046 # Update search engine
2047 $u = new SearchUpdate( $pageid, $nt->getPrefixedDBkey() );
2048 $u->doUpdate();
2049 $u = new SearchUpdate( $redirid, $this->getPrefixedDBkey(), '' );
2050 $u->doUpdate();
2051
2052 # Update site_stats
2053 if( $this->isContentPage() && !$nt->isContentPage() ) {
2054 # No longer a content page
2055 # Not viewed, edited, removing
2056 $u = new SiteStatsUpdate( 0, 1, -1, $pageCountChange );
2057 } elseif( !$this->isContentPage() && $nt->isContentPage() ) {
2058 # Now a content page
2059 # Not viewed, edited, adding
2060 $u = new SiteStatsUpdate( 0, 1, +1, $pageCountChange );
2061 } elseif( $pageCountChange ) {
2062 # Redirect added
2063 $u = new SiteStatsUpdate( 0, 0, 0, 1 );
2064 } else {
2065 # Nothing special
2066 $u = false;
2067 }
2068 if( $u )
2069 $u->doUpdate();
2070
2071 global $wgUser;
2072 wfRunHooks( 'TitleMoveComplete', array( &$this, &$nt, &$wgUser, $pageid, $redirid ) );
2073 return true;
2074 }
2075
2083 private function moveOverExistingRedirect( &$nt, $reason = '' ) {
2084 global $wgUseSquid;
2086 $comment = wfMsgForContent( '1movedto2_redir', $this->getPrefixedText(), $nt->getPrefixedText() );
2087
2088 if ( $reason ) {
2089 $comment .= ": $reason";
2090 }
2091
2092 $now = wfTimestampNow();
2093 $newid = $nt->getArticleID();
2094 $oldid = $this->getArticleID();
2095 $dbw = wfGetDB( DB_MASTER );
2096 $linkCache =& LinkCache::singleton();
2097
2098 # Delete the old redirect. We don't save it to history since
2099 # by definition if we've got here it's rather uninteresting.
2100 # We have to remove it so that the next step doesn't trigger
2101 # a conflict on the unique namespace+title index...
2102 $dbw->delete( 'page', array( 'page_id' => $newid ), $fname );
2103
2104 # Save a null revision in the page's history notifying of the move
2105 $nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true );
2106 $nullRevId = $nullRevision->insertOn( $dbw );
2107
2108 # Change the name of the target page:
2109 $dbw->update( 'page',
2110 /* SET */ array(
2111 'page_touched' => $dbw->timestamp($now),
2112 'page_namespace' => $nt->getNamespace(),
2113 'page_title' => $nt->getDBkey(),
2114 'page_latest' => $nullRevId,
2115 ),
2116 /* WHERE */ array( 'page_id' => $oldid ),
2117 $fname
2118 );
2119 $linkCache->clearLink( $nt->getPrefixedDBkey() );
2120
2121 # Recreate the redirect, this time in the other direction.
2122 $mwRedir = MagicWord::get( 'redirect' );
2123 $redirectText = $mwRedir->getSynonym( 0 ) . ' [[' . $nt->getPrefixedText() . "]]\n";
2124 $redirectArticle = new Article( $this );
2125 $newid = $redirectArticle->insertOn( $dbw );
2126 $redirectRevision = new Revision( array(
2127 'page' => $newid,
2128 'comment' => $comment,
2129 'text' => $redirectText ) );
2130 $redirectRevision->insertOn( $dbw );
2131 $redirectArticle->updateRevisionOn( $dbw, $redirectRevision, 0 );
2132 $linkCache->clearLink( $this->getPrefixedDBkey() );
2133
2134 # Log the move
2135 $log = new LogPage( 'move' );
2136 $log->addEntry( 'move_redir', $this, $reason, array( 1 => $nt->getPrefixedText() ) );
2137
2138 # Now, we record the link from the redirect to the new title.
2139 # It should have no other outgoing links...
2140 $dbw->delete( 'pagelinks', array( 'pl_from' => $newid ), $fname );
2141 $dbw->insert( 'pagelinks',
2142 array(
2143 'pl_from' => $newid,
2144 'pl_namespace' => $nt->getNamespace(),
2145 'pl_title' => $nt->getDbKey() ),
2146 $fname );
2147
2148 # Purge squid
2149 if ( $wgUseSquid ) {
2150 $urls = array_merge( $nt->getSquidURLs(), $this->getSquidURLs() );
2151 $u = new SquidUpdate( $urls );
2152 $u->doUpdate();
2153 }
2154 }
2155
2160 private function moveToNewTitle( &$nt, $reason = '' ) {
2161 global $wgUseSquid;
2162 $fname = 'MovePageForm::moveToNewTitle';
2163 $comment = wfMsgForContent( '1movedto2', $this->getPrefixedText(), $nt->getPrefixedText() );
2164 if ( $reason ) {
2165 $comment .= ": $reason";
2166 }
2167
2168 $newid = $nt->getArticleID();
2169 $oldid = $this->getArticleID();
2170 $dbw = wfGetDB( DB_MASTER );
2171 $now = $dbw->timestamp();
2172 $linkCache =& LinkCache::singleton();
2173
2174 # Save a null revision in the page's history notifying of the move
2175 $nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true );
2176 $nullRevId = $nullRevision->insertOn( $dbw );
2177
2178 # Rename cur entry
2179 $dbw->update( 'page',
2180 /* SET */ array(
2181 'page_touched' => $now,
2182 'page_namespace' => $nt->getNamespace(),
2183 'page_title' => $nt->getDBkey(),
2184 'page_latest' => $nullRevId,
2185 ),
2186 /* WHERE */ array( 'page_id' => $oldid ),
2187 $fname
2188 );
2189
2190 $linkCache->clearLink( $nt->getPrefixedDBkey() );
2191
2192 # Insert redirect
2193 $mwRedir = MagicWord::get( 'redirect' );
2194 $redirectText = $mwRedir->getSynonym( 0 ) . ' [[' . $nt->getPrefixedText() . "]]\n";
2195 $redirectArticle = new Article( $this );
2196 $newid = $redirectArticle->insertOn( $dbw );
2197 $redirectRevision = new Revision( array(
2198 'page' => $newid,
2199 'comment' => $comment,
2200 'text' => $redirectText ) );
2201 $redirectRevision->insertOn( $dbw );
2202 $redirectArticle->updateRevisionOn( $dbw, $redirectRevision, 0 );
2203 $linkCache->clearLink( $this->getPrefixedDBkey() );
2204
2205 # Log the move
2206 $log = new LogPage( 'move' );
2207 $log->addEntry( 'move', $this, $reason, array( 1 => $nt->getPrefixedText()) );
2208
2209 # Purge caches as per article creation
2210 Article::onArticleCreate( $nt );
2211
2212 # Record the just-created redirect's linking to the page
2213 $dbw->insert( 'pagelinks',
2214 array(
2215 'pl_from' => $newid,
2216 'pl_namespace' => $nt->getNamespace(),
2217 'pl_title' => $nt->getDBkey() ),
2218 $fname );
2219
2220 # Purge old title from squid
2221 # The new title, and links to the new title, are purged in Article::onArticleCreate()
2222 $this->purgeSquid();
2223 }
2224
2231 public function isValidMoveTarget( $nt ) {
2232
2233 $fname = 'Title::isValidMoveTarget';
2234 $dbw = wfGetDB( DB_MASTER );
2235
2236 # Is it a redirect?
2237 $id = $nt->getArticleID();
2238 $obj = $dbw->selectRow( array( 'page', 'revision', 'text'),
2239 array( 'page_is_redirect','old_text','old_flags' ),
2240 array( 'page_id' => $id, 'page_latest=rev_id', 'rev_text_id=old_id' ),
2241 $fname, 'FOR UPDATE' );
2242
2243 if ( !$obj || 0 == $obj->page_is_redirect ) {
2244 # Not a redirect
2245 wfDebug( __METHOD__ . ": not a redirect\n" );
2246 return false;
2247 }
2248 $text = Revision::getRevisionText( $obj );
2249
2250 # Does the redirect point to the source?
2251 # Or is it a broken self-redirect, usually caused by namespace collisions?
2252 $m = array();
2253 if ( preg_match( "/\\[\\[\\s*([^\\]\\|]*)]]/", $text, $m ) ) {
2254 $redirTitle = Title::newFromText( $m[1] );
2255 if( !is_object( $redirTitle ) ||
2256 ( $redirTitle->getPrefixedDBkey() != $this->getPrefixedDBkey() &&
2257 $redirTitle->getPrefixedDBkey() != $nt->getPrefixedDBkey() ) ) {
2258 wfDebug( __METHOD__ . ": redirect points to other page\n" );
2259 return false;
2260 }
2261 } else {
2262 # Fail safe
2263 wfDebug( __METHOD__ . ": failsafe\n" );
2264 return false;
2265 }
2266
2267 # Does the article have a history?
2268 $row = $dbw->selectRow( array( 'page', 'revision'),
2269 array( 'rev_id' ),
2270 array( 'page_namespace' => $nt->getNamespace(),
2271 'page_title' => $nt->getDBkey(),
2272 'page_id=rev_page AND page_latest != rev_id'
2273 ), $fname, 'FOR UPDATE'
2274 );
2275
2276 # Return true if there was no history
2277 return $row === false;
2278 }
2279
2287 public function getParentCategories() {
2288 global $wgContLang;
2289
2290 $titlekey = $this->getArticleId();
2291 $dbr = wfGetDB( DB_SLAVE );
2292 $categorylinks = $dbr->tableName( 'categorylinks' );
2293
2294 # NEW SQL
2295 $sql = "SELECT * FROM $categorylinks"
2296 ." WHERE cl_from='$titlekey'"
2297 ." AND cl_from <> '0'"
2298 ." ORDER BY cl_sortkey";
2299
2300 $res = $dbr->query ( $sql ) ;
2301
2302 if($dbr->numRows($res) > 0) {
2303 while ( $x = $dbr->fetchObject ( $res ) )
2304 //$data[] = Title::newFromText($wgContLang->getNSText ( NS_CATEGORY ).':'.$x->cl_to);
2305 $data[$wgContLang->getNSText ( NS_CATEGORY ).':'.$x->cl_to] = $this->getFullText();
2306 $dbr->freeResult ( $res ) ;
2307 } else {
2308 $data = '';
2309 }
2310 return $data;
2311 }
2312
2318 public function getParentCategoryTree( $children = array() ) {
2319 $parents = $this->getParentCategories();
2320
2321 if($parents != '') {
2322 foreach($parents as $parent => $current) {
2323 if ( array_key_exists( $parent, $children ) ) {
2324 # Circular reference
2325 $stack[$parent] = array();
2326 } else {
2327 $nt = Title::newFromText($parent);
2328 if ( $nt ) {
2329 $stack[$parent] = $nt->getParentCategoryTree( $children + array($parent => 1) );
2330 }
2331 }
2332 }
2333 return $stack;
2334 } else {
2335 return array();
2336 }
2337 }
2338
2339
2346 public function pageCond() {
2347 return array( 'page_namespace' => $this->mNamespace, 'page_title' => $this->mDbkeyform );
2348 }
2349
2356 public function getPreviousRevisionID( $revision ) {
2357 $dbr = wfGetDB( DB_SLAVE );
2358 return $dbr->selectField( 'revision', 'rev_id',
2359 'rev_page=' . intval( $this->getArticleId() ) .
2360 ' AND rev_id<' . intval( $revision ) . ' ORDER BY rev_id DESC' );
2361 }
2362
2369 public function getNextRevisionID( $revision ) {
2370 $dbr = wfGetDB( DB_SLAVE );
2371 return $dbr->selectField( 'revision', 'rev_id',
2372 'rev_page=' . intval( $this->getArticleId() ) .
2373 ' AND rev_id>' . intval( $revision ) . ' ORDER BY rev_id' );
2374 }
2375
2383 public function countRevisionsBetween( $old, $new ) {
2384 $dbr = wfGetDB( DB_SLAVE );
2385 return $dbr->selectField( 'revision', 'count(*)',
2386 'rev_page = ' . intval( $this->getArticleId() ) .
2387 ' AND rev_id > ' . intval( $old ) .
2388 ' AND rev_id < ' . intval( $new ) );
2389 }
2390
2397 public function equals( $title ) {
2398 // Note: === is necessary for proper matching of number-like titles.
2399 return $this->getInterwiki() === $title->getInterwiki()
2400 && $this->getNamespace() == $title->getNamespace()
2401 && $this->getDbkey() === $title->getDbkey();
2402 }
2403
2408 public function exists() {
2409 return $this->getArticleId() != 0;
2410 }
2411
2418 public function isAlwaysKnown() {
2419 return $this->isExternal() || ( 0 == $this->mNamespace && "" == $this->mDbkeyform )
2420 || NS_SPECIAL == $this->mNamespace;
2421 }
2422
2428 public function touchLinks() {
2429 $u = new HTMLCacheUpdate( $this, 'pagelinks' );
2430 $u->doUpdate();
2431
2432 if ( $this->getNamespace() == NS_CATEGORY ) {
2433 $u = new HTMLCacheUpdate( $this, 'categorylinks' );
2434 $u->doUpdate();
2435 }
2436 }
2437
2441 public function getTouched() {
2442 $dbr = wfGetDB( DB_SLAVE );
2443 $touched = $dbr->selectField( 'page', 'page_touched',
2444 array(
2445 'page_namespace' => $this->getNamespace(),
2446 'page_title' => $this->getDBkey()
2447 ), __METHOD__
2448 );
2449 return $touched;
2450 }
2451
2452 public function trackbackURL() {
2453 global $wgTitle, $wgScriptPath, $wgServer;
2454
2455 return "$wgServer$wgScriptPath/trackback.php?article="
2456 . htmlspecialchars(urlencode($wgTitle->getPrefixedDBkey()));
2457 }
2458
2459 public function trackbackRDF() {
2460 $url = htmlspecialchars($this->getFullURL());
2461 $title = htmlspecialchars($this->getText());
2462 $tburl = $this->trackbackURL();
2463
2464 return "
2465<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"
2466 xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
2467 xmlns:trackback=\"http://madskills.com/public/xml/rss/module/trackback/\">
2468<rdf:Description
2469 rdf:about=\"$url\"
2470 dc:identifier=\"$url\"
2471 dc:title=\"$title\"
2472 trackback:ping=\"$tburl\" />
2473</rdf:RDF>";
2474 }
2475
2480 public function getNamespaceKey() {
2481 global $wgContLang;
2482 switch ($this->getNamespace()) {
2483 case NS_MAIN:
2484 case NS_TALK:
2485 return 'nstab-main';
2486 case NS_USER:
2487 case NS_USER_TALK:
2488 return 'nstab-user';
2489 case NS_MEDIA:
2490 return 'nstab-media';
2491 case NS_SPECIAL:
2492 return 'nstab-special';
2493 case NS_PROJECT:
2494 case NS_PROJECT_TALK:
2495 return 'nstab-project';
2496 case NS_IMAGE:
2497 case NS_IMAGE_TALK:
2498 return 'nstab-image';
2499 case NS_MEDIAWIKI:
2500 case NS_MEDIAWIKI_TALK:
2501 return 'nstab-mediawiki';
2502 case NS_TEMPLATE:
2503 case NS_TEMPLATE_TALK:
2504 return 'nstab-template';
2505 case NS_HELP:
2506 case NS_HELP_TALK:
2507 return 'nstab-help';
2508 case NS_CATEGORY:
2509 case NS_CATEGORY_TALK:
2510 return 'nstab-category';
2511 default:
2512 return 'nstab-' . $wgContLang->lc( $this->getSubjectNsText() );
2513 }
2514 }
2515
2520 public function isSpecial( $name ) {
2521 if ( $this->getNamespace() == NS_SPECIAL ) {
2522 list( $thisName, /* $subpage */ ) = SpecialPage::resolveAliasWithSubpage( $this->getDBkey() );
2523 if ( $name == $thisName ) {
2524 return true;
2525 }
2526 }
2527 return false;
2528 }
2529
2534 public function fixSpecialName() {
2535 if ( $this->getNamespace() == NS_SPECIAL ) {
2536 $canonicalName = SpecialPage::resolveAlias( $this->mDbkeyform );
2537 if ( $canonicalName ) {
2538 $localName = SpecialPage::getLocalNameFor( $canonicalName );
2539 if ( $localName != $this->mDbkeyform ) {
2540 return Title::makeTitle( NS_SPECIAL, $localName );
2541 }
2542 }
2543 }
2544 return $this;
2545 }
2546
2554/* public function isContentPage() {
2555 return Namespace::isContent( $this->getNamespace() );
2556 }*/
2557
2558}
2559
2560?>
$result
$n
Definition: RandomTest.php:80
const GAID_FOR_UPDATE(!class_exists( 'UtfNormal'))
See title.txt.
Definition: Title.php:12
const MW_TITLECACHE_MAX
Definition: Title.php:19
$success
Definition: Utf8Test.php:87
$comment
Definition: buildRTE.php:83
static decodeCharReferences( $text)
Decode any character references, numeric or named entities, in the text and return a UTF-8 string.
Definition: Sanitizer.php:978
Title class.
Definition: Title.php:30
getTouched()
Get the last touched timestamp.
Definition: Title.php:2441
getNamespace()
Get the namespace index, i.e.
Definition: Title.php:543
static newFromDBkey( $key)
Create a new Title from a prefixed DB key.
Definition: Title.php:94
isProtected( $action='')
Does the title correspond to a protected article?
Definition: Title.php:935
userCanRead()
Would anybody with sufficient privileges be able to move this page? Some pages just aren't movable.
Definition: Title.php:1141
static $titleCache
Static cache variables.
Definition: Title.php:34
invalidateCache()
Updates page_touched for this page; called from LinksUpdate.php.
Definition: Title.php:1550
equals( $title)
Compare with another title.
Definition: Title.php:2397
getNextRevisionID( $revision)
Get the revision ID of the next revision.
Definition: Title.php:2369
isValidMoveOperation(&$nt, $auth=true)
Check whether a given move operation would be valid.
Definition: Title.php:1963
nameOf( $id)
Get the prefixed DB key associated with an ID.
Definition: Title.php:311
userCanMove( $doExpensiveQueries=true)
Can $wgUser move this page?
Definition: Title.php:1121
purgeSquid()
Definition: Title.php:1937
$mHasCascadingRestrictions
Definition: Title.php:58
getRestrictions( $action)
Accessor/initialisation for mRestrictions.
Definition: Title.php:1461
moveTo(&$nt, $auth=true, $reason='')
Move a title to a new location.
Definition: Title.php:2011
$mInterwiki
Definition: Title.php:51
$mTextform
All member variables should be considered private Please use the accessor functions.
Definition: Title.php:47
secureAndSplit()
Secure and split - main initialisation function for this object.
Definition: Title.php:1604
getBrokenLinksFrom( $options='')
Get an array of Title objects referring to non-existent articles linked from this page.
Definition: Title.php:1879
getSkinFromCssJsSubpage()
Trim down a .css or .js subpage title to get the corresponding skin name.
Definition: Title.php:1223
loadRestrictions( $oldFashionedRestrictions=NULL)
Definition: Title.php:1434
getDefaultNamespace()
Get the default namespace index, for when there is no namespace.
Definition: Title.php:615
userCanEdit( $doExpensiveQueries=true)
Can $wgUser edit this page?
Definition: Title.php:1103
$mArticleID
Definition: Title.php:53
$mNamespace
Definition: Title.php:50
getFragment()
Get the Title fragment (i.e.
Definition: Title.php:599
isCascadeProtected()
Cascading protection: Return true if cascading restrictions apply to this page, false if not.
Definition: Title.php:1259
getIndexTitle()
Get title for search index.
Definition: Title.php:622
getPrefixedURL()
Get a URL-encoded title (not an actual URL) including interwiki.
Definition: Title.php:711
$mWatched
Definition: Title.php:64
areRestrictionsCascading()
Definition: Title.php:1359
$mDbkeyform
Definition: Title.php:49
$mRestrictionsLoaded
Definition: Title.php:60
isSpecial( $name)
Returns true if this title resolves to the named special page.
Definition: Title.php:2520
static newFromID( $id)
Create a new Title from an article ID.
Definition: Title.php:192
getEscapedText()
Get the HTML-escaped displayable text form.
Definition: Title.php:894
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:846
getFullText()
Get the prefixed title with spaces, plus any fragment (part beginning with '#')
Definition: Title.php:657
userCan( $action, $doExpensiveQueries=true)
Can $wgUser perform $action on this page?
Definition: Title.php:1003
static newFromURL( $url)
Create a new Title from URL-encoded text.
Definition: Title.php:164
isLocal()
Determine whether the object refers to a page within this project.
Definition: Title.php:480
moveNoAuth(&$nt)
Move this page without authentication.
Definition: Title.php:1950
$mCascadeRestrictionSources
Definition: Title.php:59
loadRestrictionsFromRow( $res, $oldFashionedRestrictions=NULL)
Loads a string into mRestrictions array.
Definition: Title.php:1371
fixSpecialName()
If the Title refers to a special page alias which is not the local default, returns a new Title which...
Definition: Title.php:2534
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition: Title.php:326
static & makeTitle( $ns, $title)
Create a new Title from a namespace index and a DB key.
Definition: Title.php:231
isSemiProtected( $action='edit')
Is this page "semi-protected" - the only protection is autoconfirm?
Definition: Title.php:910
isCssJsSubpage()
Is this a .css or .js subpage of a user page?
Definition: Title.php:1205
getPrefixedDBkey()
Get the prefixed database key form.
Definition: Title.php:631
getNsText()
Get the namespace text.
Definition: Title.php:548
getInternalURL( $query='', $variant=false)
Get the URL form for an internal link.
Definition: Title.php:870
static purgeExpiredRestrictions()
Purge expired restrictions from the page_restrictions table.
Definition: Title.php:1448
getCascadeProtectionSources( $get_pages=true)
Cascading protection: Get the source of any cascading restrictions on this page.
Definition: Title.php:1272
static $interwikiCache
Definition: Title.php:35
isTrans()
Determine whether the object refers to a page within this project and is transcludable.
Definition: Title.php:497
resetArticleID( $newid)
This clears some fields in this object, and clears any associated keys in the "bad links" section of ...
Definition: Title.php:1536
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:1869
escapeFullURL( $query='')
Get an HTML-escaped version of the URL form, suitable for using in a link, including the server name ...
Definition: Title.php:857
static newFromRedirect( $text)
Create a new Title for a redirect.
Definition: Title.php:276
touchLinks()
Update page_touched timestamps and send squid purge messages for pages linking to this title.
Definition: Title.php:2428
trackbackRDF()
Definition: Title.php:2459
userIsWatching()
Is $wgUser is watching this page?
Definition: Title.php:968
isExternal()
Is this Title interwiki?
Definition: Title.php:902
getFragmentForURL()
Get the fragment in URL form, including the "#" character if there is one.
Definition: Title.php:604
$mRestrictionsExpiry
Definition: Title.php:57
getSubpageUrlForm()
Get a URL-encoded form of the subpage text.
Definition: Title.php:700
getDBkey()
Get the main part with underscores.
Definition: Title.php:538
quickUserCan( $action)
Can $wgUser perform $action on this page? This skips potentially expensive cascading permission check...
Definition: Title.php:993
prefix( $name)
Prefix some arbitrary text with the namespace or interwiki prefix of this object.
Definition: Title.php:1583
userCanEditCssJsSubpage()
Protect css/js subpages of user pages: can $wgUser edit this page?
Definition: Title.php:1249
isValidCssJsSubpage()
Is this a valid .css or .js subpage of a user page? Check that the corresponding skin exists.
Definition: Title.php:1212
getFullURL( $query='', $variant=false)
Get a real URL referring to this title, with interwiki link and fragment.
Definition: Title.php:733
$mRestrictions
Definition: Title.php:55
getPartialURL()
Get the URL-encoded form of the main part.
Definition: Title.php:533
getBaseText()
Get the base name, i.e.
Definition: Title.php:669
getText()
Simple accessors.
Definition: Title.php:528
pageCond()
Get an associative array for selecting this title from the "page" table.
Definition: Title.php:2346
getPreviousRevisionID( $revision)
Get the revision ID of the previous revision.
Definition: Title.php:2356
isJsSubpage()
Is this a .js subpage of a user page?
Definition: Title.php:1239
static newFromIDs( $ids)
Make an array of titles from an array of IDs.
Definition: Title.php:208
$mUrlform
Definition: Title.php:48
__construct()
#-
Definition: Title.php:72
$mLatestID
Definition: Title.php:54
static newMainPage()
Create a new Title for the Main Page.
Definition: Title.php:266
isCssSubpage()
Is this a .css subpage of a user page?
Definition: Title.php:1232
static indexTitle( $ns, $title)
Get a string representation of a title suitable for including in a search index.
Definition: Title.php:343
exists()
Check if page exists.
Definition: Title.php:2408
isValidMoveTarget( $nt)
Checks if $this can be moved to a given Title.
Definition: Title.php:2231
getSquidURLs()
Get a list of URLs to purge from the Squid cache when this page changes.
Definition: Title.php:1917
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:114
static escapeFragmentForURL( $fragment)
Escape a text fragment, say from a link, for a URL.
Definition: Title.php:509
getArticleID( $flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
Definition: Title.php:1501
getParentCategoryTree( $children=array())
Get a tree of parent categories.
Definition: Title.php:2318
getInterwikiLink( $key)
Returns the URL associated with an interwiki prefix.
Definition: Title.php:383
isDeleted()
Is there a version of this page in the deletion archive?
Definition: Title.php:1478
moveOverExistingRedirect(&$nt, $reason='')
Move page to a title which is at present a redirect to the source page.
Definition: Title.php:2083
getLinksTo( $options='', $table='pagelinks', $prefix='pl')
Get a Title object associated with the talk page of this article.
Definition: Title.php:1828
static makeTitleSafe( $ns, $title)
Create a new Title from a namespace index and a DB key.
Definition: Title.php:252
$mFragment
Definition: Title.php:52
userCanCreate( $doExpensiveQueries=true)
Can $wgUser create this page?
Definition: Title.php:1112
getEditURL()
Get the edit URL for this Title.
Definition: Title.php:882
getParentCategories()
Get categories to which this Title belongs and return an array of categories' names.
Definition: Title.php:2287
getLocalURL( $query='', $variant=false)
Get a URL with no fragment or server name.
Definition: Title.php:772
getNamespaceKey()
Generate strings used for xml 'id' names in monobook tabs.
Definition: Title.php:2480
trackbackURL()
Definition: Title.php:2452
$mCascadeRestriction
Definition: Title.php:56
isSubpage()
Is this a talk page of some sort?
Definition: Title.php:1191
moveToNewTitle(&$nt, $reason='')
Move page to non-existing title.
Definition: Title.php:2160
setFragment( $fragment)
Set the fragment for this title This is kind of bad, since except for this rarely-used function,...
Definition: Title.php:1796
$mPrefixedText
Definition: Title.php:61
static makeName( $ns, $title)
Definition: Title.php:369
static getInterwikiCached( $key)
Fetch interwiki prefix data from local cache in constant database.
Definition: Title.php:438
getInterwiki()
Get the namespace text of the subject (rather than talk) page.
Definition: Title.php:594
$mDefaultNamespace
Definition: Title.php:62
getSubpageText()
Get the lowest-level subpage name, i.e.
Definition: Title.php:686
getPrefixedText()
Get the prefixed title with spaces.
Definition: Title.php:642
isAlwaysKnown()
Should a link should be displayed as a known link, just based on its title?
Definition: Title.php:2418
getLatestRevID()
Definition: Title.php:1515
countRevisionsBetween( $old, $new)
Get the number of revisions between the given revision IDs.
Definition: Title.php:2383
static wfUrlencode( $s)
From GlobalFunctions.php.
if($err=$client->getError()) $namespace
$x
Definition: example_009.php:98
$data
$text
$r
Definition: example_031.php:79
const UTF8_REPLACEMENT
Definition: UtfNormal.php:83
$url
Definition: shib_logout.php:72
if(!is_array($argv)) $options