ILIAS  trunk Revision v11.0_alpha-2645-g16283d3b3f8
Title.php
Go to the documentation of this file.
1 <?php
2 
19 // patched: alex, 30.4.2019: Added missing defines
20 define('NS_MAIN', "nsmain");
21 define('NS_SPECIAL', "nsspecial");
22 
23 define('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.
30 define('MW_TITLECACHE_MAX', 1000);
31 
32 # Constants for pr_cascade bitfield
33 define('CASCADE', 1);
34 
41 class 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 }
setFragment($fragment)
Set the fragment for this title This is kind of bad, since except for this rarely-used function...
Definition: Title.php:477
getFragment()
Get the Title fragment (i.e.
Definition: Title.php:251
$mNamespace
Definition: Title.php:65
getText()
Simple accessors.
Definition: Title.php:197
$mArticleID
Definition: Title.php:68
$mRestrictionsExpiry
Definition: Title.php:72
$mInterwiki
Definition: Title.php:66
const NS_SPECIAL
Definition: Title.php:21
secureAndSplit()
Secure and split - main initialisation function for this object.
Definition: Title.php:286
getInterwikiLink($key)
Returns the URL associated with an interwiki prefix.
Definition: Title.php:183
prefix($name)
Prefix some arbitrary text with the namespace or interwiki prefix of this object. ...
Definition: Title.php:264
static $interwikiCache
Definition: Title.php:47
$mHasCascadingRestrictions
Definition: Title.php:73
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
$mRestrictionsLoaded
Definition: Title.php:75
Title class.
Definition: Title.php:41
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
$mCascadeRestriction
Definition: Title.php:71
$mDefaultNamespace
Definition: Title.php:77
static decodeCharReferences($text)
Decode any character references, numeric or named entities, in the text and return a UTF-8 string...
Definition: Sanitizer.php:373
getNsText()
Get the namespace text.
Definition: Title.php:222
__construct()
#-
Definition: Title.php:87
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
getDBkey()
Get the main part with underscores.
Definition: Title.php:206
$mFragment
Definition: Title.php:67
$mRestrictions
Definition: Title.php:70
static $titleCache
Static cache variables.
Definition: Title.php:46
getNamespace()
Get the namespace index, i.e.
Definition: Title.php:214
bool $mOldRestrictions
Definition: Title.php:51
getInterwiki()
Get the interwiki prefix (or null string)
Definition: Title.php:243
$mDbkeyform
Definition: Title.php:64
$mLatestID
Definition: Title.php:69
form( $class_path, string $cmd, string $submit_caption="")
const MW_TITLECACHE_MAX
Definition: Title.php:30
$mTextform
All member variables should be considered private Please use the accessor functions.
Definition: Title.php:62
link(string $caption, string $href, bool $new_viewport=false)
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition: Title.php:166
$mPrefixedText
Definition: Title.php:76
$mWatched
Definition: Title.php:79
to(\GdImage $image, ?int $quality=null)
Currently this is the only way to make a FileStream from a GD image resource.
static wfUrlencode(string $s)
$mCascadeRestrictionSources
Definition: Title.php:74
$mUrlform
Definition: Title.php:63
equals($title)
Compare with another title.
Definition: Title.php:488