ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
Title.php
Go to the documentation of this file.
1<?php
2
19// patched: alex, 30.4.2019: Added missing defines
20define('NS_MAIN', "nsmain");
21define('NS_SPECIAL', "nsspecial");
22
23define('GAID_FOR_UPDATE', 1);
24
25# Title::newFromTitle maintains a cache to avoid
26# expensive re-normalization of commonly used titles.
27# On a batch operation this can become a memory leak
28# if not bounded. After hitting this many titles,
29# reset the cache.
30define('MW_TITLECACHE_MAX', 1000);
31
32# Constants for pr_cascade bitfield
33define('CASCADE', 1);
34
41class Title
42{
46 private static $titleCache = array();
47 private static $interwikiCache = array();
51 protected bool $mOldRestrictions;
52
62 public $mTextform; # Text form (spaces not underscores) of the main part
63 public $mUrlform; # URL-encoded form of the main part
64 public $mDbkeyform; # Main part with underscores
65 public $mNamespace; # Namespace index, i.e. one of the NS_xxxx constants
66 public $mInterwiki; # Interwiki prefix (or null string)
67 public $mFragment; # Title fragment (i.e. the bit after the #)
68 public $mArticleID; # Article ID, fetched from the link cache on demand
69 public $mLatestID; # ID of most recent revision
70 public $mRestrictions; # Array of groups allowed to edit this article
71 public $mCascadeRestriction; # Cascade restrictions on this page to included templates and images?
72 public $mRestrictionsExpiry; # When do the restrictions on this page expire?
73 public $mHasCascadingRestrictions; # Are cascading restrictions in effect on this page?
74 public $mCascadeRestrictionSources;# Where are the cascading restrictions coming from on this page?
75 public $mRestrictionsLoaded; # Boolean for initialisation on demand
76 public $mPrefixedText; # Text form including namespace/interwiki, initialised on demand
77 public $mDefaultNamespace; # Namespace index when there is no namespace
78 # Zero except in {{transclusion}} tags
79 public $mWatched; # Is $wgUser watching this page? NULL if unfilled, accessed through userIsWatching()
87 /* private */ public function __construct()
88 {
89 $this->mInterwiki = $this->mUrlform =
90 $this->mTextform = $this->mDbkeyform = '';
91 $this->mArticleID = -1;
92 $this->mNamespace = NS_MAIN;
93 $this->mRestrictionsLoaded = false;
94 $this->mRestrictions = array();
95 # Dont change the following, NS_MAIN is hardcoded in several place
96 # See bug #696
97 $this->mDefaultNamespace = NS_MAIN;
98 $this->mWatched = null;
99 $this->mLatestID = false;
100 $this->mOldRestrictions = false;
101 }
102
103
115 public static function newFromText($text, $defaultNamespace = NS_MAIN)
116 {
125 if ($defaultNamespace == NS_MAIN && isset(Title::$titleCache[$text])) {
126 return Title::$titleCache[$text];
127 }
128
132 $filteredText = Sanitizer::decodeCharReferences($text);
133
134 $t = new Title();
135 $t->mDbkeyform = str_replace(' ', '_', $filteredText);
136 $t->mDefaultNamespace = $defaultNamespace;
137
138 static $cachedcount = 0 ;
139 if ($t->secureAndSplit()) {
140 if ($defaultNamespace == NS_MAIN) {
141 if ($cachedcount >= MW_TITLECACHE_MAX) {
142 # Avoid memory leaks on mass operations...
143 Title::$titleCache = array();
144 $cachedcount = 0;
145 }
146 $cachedcount++;
147 Title::$titleCache[$text] = &$t;
148 }
149 return $t;
150 } else {
151 $ret = null;
152 return $ret;
153 }
154 }
155
156
157 #----------------------------------------------------------------------------
158 # Static functions
159 #----------------------------------------------------------------------------
160
161
166 public static function legalChars()
167 {
168 global $wgLegalTitleChars;
169
170 $wgLegalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+";
171
172 return $wgLegalTitleChars;
173 }
174
175
183 public function getInterwikiLink($key)
184 {
185 return "";
186 }
187
188 #----------------------------------------------------------------------------
189 # Other stuff
190 #----------------------------------------------------------------------------
191
197 public function getText()
198 {
199 return $this->mTextform;
200 }
201
206 public function getDBkey()
207 {
208 return $this->mDbkeyform;
209 }
214 public function getNamespace()
215 {
216 return $this->mNamespace;
217 }
222 public function getNsText()
223 {
224 global $wgContLang, $wgCanonicalNamespaceNames;
225
226 if ('' != $this->mInterwiki) {
227 // This probably shouldn't even happen. ohh man, oh yuck.
228 // But for interwiki transclusion it sometimes does.
229 // Shit. Shit shit shit.
230 //
231 // Use the canonical namespaces if possible to try to
232 // resolve a foreign namespace.
233 if (isset($wgCanonicalNamespaceNames[$this->mNamespace])) {
234 return $wgCanonicalNamespaceNames[$this->mNamespace];
235 }
236 }
237 return $wgContLang->getNsText($this->mNamespace);
238 }
243 public function getInterwiki()
244 {
245 return $this->mInterwiki;
246 }
251 public function getFragment()
252 {
253 return $this->mFragment;
254 }
255
264 /* private */ public function prefix($name)
265 {
266 $p = '';
267 if ('' != $this->mInterwiki) {
268 $p = $this->mInterwiki . ':';
269 }
270 if (0 != $this->mNamespace) {
271 $p .= $this->getNsText() . ':';
272 }
273 return $p . $name;
274 }
275
286 private function secureAndSplit()
287 {
288 global $wgContLang, $wgLocalInterwiki, $wgCapitalLinks;
289
290 # Initialisation
291 static $rxTc = false;
292 if (!$rxTc) {
293 # % is needed as well
294 $rxTc = '/[^' . Title::legalChars() . ']|%[0-9A-Fa-f]{2}/S';
295 }
296
297 $this->mInterwiki = $this->mFragment = '';
298 $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN
299
300 $dbkey = $this->mDbkeyform;
301
302 # Strip Unicode bidi override characters.
303 # Sometimes they slip into cut-n-pasted page titles, where the
304 # override chars get included in list displays.
305 $dbkey = str_replace("\xE2\x80\x8E", '', $dbkey); // 200E LEFT-TO-RIGHT MARK
306 $dbkey = str_replace("\xE2\x80\x8F", '', $dbkey); // 200F RIGHT-TO-LEFT MARK
307
308 # Clean up whitespace
309 #
310 $dbkey = preg_replace('/[ _]+/', '_', $dbkey);
311 $dbkey = trim($dbkey, '_');
312
313 if ('' == $dbkey) {
314 return false;
315 }
316
317 if (false !== strpos($dbkey, UTF8_REPLACEMENT)) {
318 # Contained illegal UTF-8 sequences or forbidden Unicode chars.
319 return false;
320 }
321
322 $this->mDbkeyform = $dbkey;
323
324 # Initial colon indicates main namespace rather than specified default
325 # but should not create invalid {ns,title} pairs such as {0,Project:Foo}
326 if (':' == $dbkey[0]) {
327 $this->mNamespace = NS_MAIN;
328 $dbkey = substr($dbkey, 1); # remove the colon but continue processing
329 $dbkey = trim($dbkey, '_'); # remove any subsequent whitespace
330 }
331
332 # Namespace or interwiki prefix
333 $firstPass = true;
334 do {
335 $m = array();
336 if (preg_match("/^(.+?)_*:_*(.*)$/S", $dbkey, $m)) {
337 $p = $m[1];
338 if ($ns = $wgContLang->getNsIndex($p)) {
339 # Ordinary namespace
340 $dbkey = $m[2];
341 $this->mNamespace = $ns;
342 } elseif ($this->getInterwikiLink($p)) {
343 if (!$firstPass) {
344 # Can't make a local interwiki link to an interwiki link.
345 # That's just crazy!
346 return false;
347 }
348
349 # Interwiki link
350 $dbkey = $m[2];
351 $this->mInterwiki = $wgContLang->lc($p);
352
353 # Redundant interwiki prefix to the local wiki
354 if (0 == strcasecmp($this->mInterwiki, $wgLocalInterwiki)) {
355 if ($dbkey == '') {
356 # Can't have an empty self-link
357 return false;
358 }
359 $this->mInterwiki = '';
360 $firstPass = false;
361 # Do another namespace split...
362 continue;
363 }
364
365 # If there's an initial colon after the interwiki, that also
366 # resets the default namespace
367 if ($dbkey !== '' && $dbkey[0] == ':') {
368 $this->mNamespace = NS_MAIN;
369 $dbkey = substr($dbkey, 1);
370 }
371 }
372 # If there's no recognized interwiki or namespace,
373 # then let the colon expression be part of the title.
374 }
375 break;
376 } while (true);
377
378 # We already know that some pages won't be in the database!
379 #
380 if ('' != $this->mInterwiki || NS_SPECIAL == $this->mNamespace) {
381 $this->mArticleID = 0;
382 }
383 $fragment = strstr($dbkey, '#');
384 if (false !== $fragment) {
385 $this->setFragment($fragment);
386 $dbkey = substr($dbkey, 0, strlen($dbkey) - strlen($fragment));
387 # remove whitespace again: prevents "Foo_bar_#"
388 # becoming "Foo_bar_"
389 $dbkey = preg_replace('/_*$/', '', $dbkey);
390 }
391
392 # Reject illegal characters.
393 #
394 if (preg_match($rxTc, $dbkey)) {
395 return false;
396 }
397
403 if (strpos($dbkey, '.') !== false &&
404 ($dbkey === '.' || $dbkey === '..' ||
405 strpos($dbkey, './') === 0 ||
406 strpos($dbkey, '../') === 0 ||
407 strpos($dbkey, '/./') !== false ||
408 strpos($dbkey, '/../') !== false)) {
409 return false;
410 }
411
415 if (strpos($dbkey, '~~~') !== false) {
416 return false;
417 }
418
426 if (($this->mNamespace != NS_SPECIAL && strlen($dbkey) > 255) ||
427 strlen($dbkey) > 512) {
428 return false;
429 }
430
439 if ($wgCapitalLinks && $this->mInterwiki == '') {
440 $dbkey = $wgContLang->ucfirst($dbkey);
441 }
442
448 if ($dbkey == '' &&
449 $this->mInterwiki == '' &&
450 $this->mNamespace != NS_MAIN) {
451 return false;
452 }
453
454 // Any remaining initial :s are illegal.
455 if ($dbkey !== '' && ':' == $dbkey[0]) {
456 return false;
457 }
458
459 # Fill fields
460 $this->mDbkeyform = $dbkey;
461 $this->mUrlform = ilWikiUtil::wfUrlencode($dbkey);
462
463 $this->mTextform = str_replace('_', ' ', $dbkey);
464
465 return true;
466 }
467
477 public function setFragment($fragment)
478 {
479 $this->mFragment = str_replace('_', ' ', substr($fragment, 1));
480 }
481
488 public function equals($title)
489 {
490 // Note: === is necessary for proper matching of number-like titles.
491 return $this->getInterwiki() === $title->getInterwiki()
492 && $this->getNamespace() == $title->getNamespace()
493 && $this->getDBkey() === $title->getDBkey();
494 }
495}
const NS_MAIN
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Title.php:20
const MW_TITLECACHE_MAX
Definition: Title.php:30
const NS_SPECIAL
Definition: Title.php:21
static decodeCharReferences($text)
Decode any character references, numeric or named entities, in the text and return a UTF-8 string.
Definition: Sanitizer.php:373
Title class.
Definition: Title.php:42
getNamespace()
Get the namespace index, i.e.
Definition: Title.php:214
static $titleCache
Static cache variables.
Definition: Title.php:46
$mHasCascadingRestrictions
Definition: Title.php:73
$mInterwiki
Definition: Title.php:66
$mTextform
All member variables should be considered private Please use the accessor functions.
Definition: Title.php:62
secureAndSplit()
Secure and split - main initialisation function for this object.
Definition: Title.php:286
$mArticleID
Definition: Title.php:68
$mNamespace
Definition: Title.php:65
getFragment()
Get the Title fragment (i.e.
Definition: Title.php:251
$mWatched
Definition: Title.php:79
prefix($name)
Prefix some arbitrary text with the namespace or interwiki prefix of this object.
Definition: Title.php:264
static newFromText($text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:115
$mDbkeyform
Definition: Title.php:64
$mRestrictionsLoaded
Definition: Title.php:75
$mCascadeRestrictionSources
Definition: Title.php:74
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition: Title.php:166
getNsText()
Get the namespace text.
Definition: Title.php:222
equals($title)
Compare with another title.
Definition: Title.php:488
static $interwikiCache
Definition: Title.php:47
$mRestrictionsExpiry
Definition: Title.php:72
getDBkey()
Get the main part with underscores.
Definition: Title.php:206
$mRestrictions
Definition: Title.php:70
getText()
Simple accessors.
Definition: Title.php:197
$mUrlform
Definition: Title.php:63
__construct()
#-
Definition: Title.php:87
$mLatestID
Definition: Title.php:69
setFragment($fragment)
Set the fragment for this title This is kind of bad, since except for this rarely-used function,...
Definition: Title.php:477
$mFragment
Definition: Title.php:67
bool $mOldRestrictions
Definition: Title.php:51
$mCascadeRestriction
Definition: Title.php:71
getInterwikiLink($key)
Returns the URL associated with an interwiki prefix.
Definition: Title.php:183
$mPrefixedText
Definition: Title.php:76
getInterwiki()
Get the interwiki prefix (or null string)
Definition: Title.php:243
$mDefaultNamespace
Definition: Title.php:77
static wfUrlencode(string $s)
form( $class_path, string $cmd, string $submit_caption="")
link(string $caption, string $href, bool $new_viewport=false)
to(\GdImage $image, ?int $quality=null)
Currently this is the only way to make a FileStream from a GD image resource.