MediaWiki  1.23.14
MediaWikiTitleCodec.php
Go to the documentation of this file.
1 <?php
36 
40  protected $language;
41 
45  protected $genderCache;
46 
50  protected $localInterwikis;
51 
58  $this->language = $language;
59  $this->genderCache = $genderCache;
60  $this->localInterwikis = (array)$localInterwikis;
61  }
62 
72  public function getNamespaceName( $namespace, $text ) {
73  if ( $this->language->needsGenderDistinction() &&
74  MWNamespace::hasGenderDistinction( $namespace ) ) {
75 
76  //NOTE: we are assuming here that the title text is a user name!
77  $gender = $this->genderCache->getGenderOf( $text, __METHOD__ );
78  $name = $this->language->getGenderNsText( $namespace, $gender );
79  } else {
80  $name = $this->language->getNsText( $namespace );
81  }
82 
83  if ( $name === false ) {
84  throw new InvalidArgumentException( 'Unknown namespace ID: ' . $namespace );
85  }
86 
87  return $name;
88  }
89 
101  public function formatTitle( $namespace, $text, $fragment = '' ) {
102  if ( $namespace !== false ) {
103  $namespace = $this->getNamespaceName( $namespace, $text );
104 
105  if ( $namespace !== '' ) {
106  $text = $namespace . ':' . $text;
107  }
108  }
109 
110  if ( $fragment !== '' ) {
111  $text = $text . '#' . $fragment;
112  }
113 
114  $text = str_replace( '_', ' ', $text );
115 
116  return $text;
117  }
118 
129  public function parseTitle( $text, $defaultNamespace ) {
130  // NOTE: this is an ugly cludge that allows this class to share the
131  // code for parsing with the old Title class. The parser code should
132  // be refactored to avoid this.
133  $parts = $this->splitTitleString( $text, $defaultNamespace );
134 
135  // Interwiki links are not supported by TitleValue
136  if ( $parts['interwiki'] !== '' ) {
137  throw new MalformedTitleException( 'Title must not contain an interwiki prefix: ' . $text );
138  }
139 
140  // Relative fragment links are not supported by TitleValue
141  if ( $parts['dbkey'] === '' ) {
142  throw new MalformedTitleException( 'Title must not be empty: ' . $text );
143  }
144 
145  return new TitleValue( $parts['namespace'], $parts['dbkey'], $parts['fragment'] );
146  }
147 
155  public function getText( TitleValue $title ) {
156  return $this->formatTitle( false, $title->getText(), '' );
157  }
158 
166  public function getPrefixedText( TitleValue $title ) {
167  return $this->formatTitle( $title->getNamespace(), $title->getText(), '' );
168  }
169 
177  public function getFullText( TitleValue $title ) {
178  return $this->formatTitle( $title->getNamespace(), $title->getText(), $title->getFragment() );
179  }
180 
201  public function splitTitleString( $text, $defaultNamespace = NS_MAIN ) {
202  $dbkey = str_replace( ' ', '_', $text );
203 
204  # Initialisation
205  $parts = array(
206  'interwiki' => '',
207  'fragment' => '',
208  'namespace' => $defaultNamespace,
209  'dbkey' => $dbkey,
210  'user_case_dbkey' => $dbkey,
211  );
212 
213  # Strip Unicode bidi override characters.
214  # Sometimes they slip into cut-n-pasted page titles, where the
215  # override chars get included in list displays.
216  $dbkey = preg_replace( '/\xE2\x80[\x8E\x8F\xAA-\xAE]/S', '', $dbkey );
217 
218  # Clean up whitespace
219  # Note: use of the /u option on preg_replace here will cause
220  # input with invalid UTF-8 sequences to be nullified out in PHP 5.2.x,
221  # conveniently disabling them.
222  $dbkey = preg_replace( '/[ _\xA0\x{1680}\x{180E}\x{2000}-\x{200A}\x{2028}\x{2029}\x{202F}\x{205F}\x{3000}]+/u', '_', $dbkey );
223  $dbkey = trim( $dbkey, '_' );
224 
225  if ( strpos( $dbkey, UTF8_REPLACEMENT ) !== false ) {
226  # Contained illegal UTF-8 sequences or forbidden Unicode chars.
227  throw new MalformedTitleException( 'Bad UTF-8 sequences found in title: ' . $text );
228  }
229 
230  $parts['dbkey'] = $dbkey;
231 
232  # Initial colon indicates main namespace rather than specified default
233  # but should not create invalid {ns,title} pairs such as {0,Project:Foo}
234  if ( $dbkey !== '' && ':' == $dbkey[0] ) {
235  $parts['namespace'] = NS_MAIN;
236  $dbkey = substr( $dbkey, 1 ); # remove the colon but continue processing
237  $dbkey = trim( $dbkey, '_' ); # remove any subsequent whitespace
238  }
239 
240  if ( $dbkey == '' ) {
241  throw new MalformedTitleException( 'Empty title: ' . $text );
242  }
243 
244  # Namespace or interwiki prefix
245  $firstPass = true;
246  $prefixRegexp = "/^(.+?)_*:_*(.*)$/S";
247  do {
248  $m = array();
249  if ( preg_match( $prefixRegexp, $dbkey, $m ) ) {
250  $p = $m[1];
251  if ( ( $ns = $this->language->getNsIndex( $p ) ) !== false ) {
252  # Ordinary namespace
253  $dbkey = $m[2];
254  $parts['namespace'] = $ns;
255  # For Talk:X pages, check if X has a "namespace" prefix
256  if ( $ns == NS_TALK && preg_match( $prefixRegexp, $dbkey, $x ) ) {
257  if ( $this->language->getNsIndex( $x[1] ) ) {
258  # Disallow Talk:File:x type titles...
259  throw new MalformedTitleException( 'Bad namespace prefix: ' . $text );
260  } elseif ( Interwiki::isValidInterwiki( $x[1] ) ) {
261  //TODO: get rid of global state!
262  # Disallow Talk:Interwiki:x type titles...
263  throw new MalformedTitleException( 'Interwiki prefix found in title: ' . $text );
264  }
265  }
266  } elseif ( Interwiki::isValidInterwiki( $p ) ) {
267  if ( !$firstPass ) {
268  //TODO: get rid of global state!
269  # Can't make a local interwiki link to an interwiki link.
270  # That's just crazy!
271  throw new MalformedTitleException( 'Interwiki prefix found in title: ' . $text );
272  }
273 
274  # Interwiki link
275  $dbkey = $m[2];
276  $parts['interwiki'] = $this->language->lc( $p );
277 
278  # Redundant interwiki prefix to the local wiki
279  foreach ( $this->localInterwikis as $localIW ) {
280  if ( 0 == strcasecmp( $parts['interwiki'], $localIW ) ) {
281  if ( $dbkey == '' ) {
282  # Can't have an empty self-link
283  throw new MalformedTitleException( 'Local interwiki with empty title: ' . $text );
284  }
285  $parts['interwiki'] = '';
286  $firstPass = false;
287 
288  # Do another namespace split...
289  continue 2;
290  }
291  }
292 
293  # If there's an initial colon after the interwiki, that also
294  # resets the default namespace
295  if ( $dbkey !== '' && $dbkey[0] == ':' ) {
296  $parts['namespace'] = NS_MAIN;
297  $dbkey = substr( $dbkey, 1 );
298  }
299  }
300  # If there's no recognized interwiki or namespace,
301  # then let the colon expression be part of the title.
302  }
303  break;
304  } while ( true );
305 
306  $fragment = strstr( $dbkey, '#' );
307  if ( false !== $fragment ) {
308  $parts['fragment'] = str_replace( '_', ' ', substr( $fragment, 1 ) );
309  $dbkey = substr( $dbkey, 0, strlen( $dbkey ) - strlen( $fragment ) );
310  # remove whitespace again: prevents "Foo_bar_#"
311  # becoming "Foo_bar_"
312  $dbkey = preg_replace( '/_*$/', '', $dbkey );
313  }
314 
315  # Reject illegal characters.
316  $rxTc = Title::getTitleInvalidRegex();
317  if ( preg_match( $rxTc, $dbkey ) ) {
318  throw new MalformedTitleException( 'Illegal characters found in title: ' . $text );
319  }
320 
321  # Pages with "/./" or "/../" appearing in the URLs will often be un-
322  # reachable due to the way web browsers deal with 'relative' URLs.
323  # Also, they conflict with subpage syntax. Forbid them explicitly.
324  if (
325  strpos( $dbkey, '.' ) !== false &&
326  (
327  $dbkey === '.' || $dbkey === '..' ||
328  strpos( $dbkey, './' ) === 0 ||
329  strpos( $dbkey, '../' ) === 0 ||
330  strpos( $dbkey, '/./' ) !== false ||
331  strpos( $dbkey, '/../' ) !== false ||
332  substr( $dbkey, -2 ) == '/.' ||
333  substr( $dbkey, -3 ) == '/..'
334  )
335  ) {
336  throw new MalformedTitleException( 'Bad title: ' . $text );
337  }
338 
339  # Magic tilde sequences? Nu-uh!
340  if ( strpos( $dbkey, '~~~' ) !== false ) {
341  throw new MalformedTitleException( 'Bad title: ' . $text );
342  }
343 
344  # Limit the size of titles to 255 bytes. This is typically the size of the
345  # underlying database field. We make an exception for special pages, which
346  # don't need to be stored in the database, and may edge over 255 bytes due
347  # to subpage syntax for long titles, e.g. [[Special:Block/Long name]]
348  if (
349  ( $parts['namespace'] != NS_SPECIAL && strlen( $dbkey ) > 255 )
350  || strlen( $dbkey ) > 512
351  ) {
352  throw new MalformedTitleException( 'Title too long: ' . substr( $dbkey, 0, 255 ) . '...' );
353  }
354 
355  # Normally, all wiki links are forced to have an initial capital letter so [[foo]]
356  # and [[Foo]] point to the same place. Don't force it for interwikis, since the
357  # other site might be case-sensitive.
358  $parts['user_case_dbkey'] = $dbkey;
359  if ( $parts['interwiki'] === '' ) {
360  $dbkey = Title::capitalize( $dbkey, $parts['namespace'] );
361  }
362 
363  # Can't make a link to a namespace alone... "empty" local links can only be
364  # self-links with a fragment identifier.
365  if ( $dbkey == '' && $parts['interwiki'] === '' ) {
366  if ( $parts['namespace'] != NS_MAIN ) {
367  throw new MalformedTitleException( 'Empty title: ' . $text );
368  }
369  }
370 
371  // Allow IPv6 usernames to start with '::' by canonicalizing IPv6 titles.
372  // IP names are not allowed for accounts, and can only be referring to
373  // edits from the IP. Given '::' abbreviations and caps/lowercaps,
374  // there are numerous ways to present the same IP. Having sp:contribs scan
375  // them all is silly and having some show the edits and others not is
376  // inconsistent. Same for talk/userpages. Keep them normalized instead.
377  if ( $parts['namespace'] == NS_USER || $parts['namespace'] == NS_USER_TALK ) {
378  $dbkey = IP::sanitizeIP( $dbkey );
379  }
380 
381  // Any remaining initial :s are illegal.
382  if ( $dbkey !== '' && ':' == $dbkey[0] ) {
383  throw new MalformedTitleException( 'Title must not start with a colon: ' . $text );
384  }
385 
386  # Fill fields
387  $parts['dbkey'] = $dbkey;
388  return $parts;
389  }
390 
391 }
MediaWikiTitleCodec\__construct
__construct(Language $language, GenderCache $genderCache, $localInterwikis=array())
Definition: MediaWikiTitleCodec.php:54
MediaWikiTitleCodec
A codec for MediaWiki page titles.
Definition: MediaWikiTitleCodec.php:35
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
MWNamespace\hasGenderDistinction
static hasGenderDistinction( $index)
Does the namespace (potentially) have different aliases for different genders.
Definition: Namespace.php:406
MediaWikiTitleCodec\getText
getText(TitleValue $title)
Definition: MediaWikiTitleCodec.php:152
GenderCache
Caches user genders when needed to use correct namespace aliases.
Definition: GenderCache.php:30
MediaWikiTitleCodec\splitTitleString
splitTitleString( $text, $defaultNamespace=NS_MAIN)
Normalizes and splits a title string.
Definition: MediaWikiTitleCodec.php:198
MediaWikiTitleCodec\getNamespaceName
getNamespaceName( $namespace, $text)
Definition: MediaWikiTitleCodec.php:69
processing
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after processing
Definition: hooks.txt:1530
MediaWikiTitleCodec\parseTitle
parseTitle( $text, $defaultNamespace)
Parses the given text and constructs a TitleValue.
Definition: MediaWikiTitleCodec.php:126
MediaWikiTitleCodec\formatTitle
formatTitle( $namespace, $text, $fragment='')
Definition: MediaWikiTitleCodec.php:98
NS_MAIN
const NS_MAIN
Definition: Defines.php:79
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:68
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
MediaWikiTitleCodec\$localInterwikis
string[] $localInterwikis
Definition: MediaWikiTitleCodec.php:47
TitleParser
A title parser service for MediaWiki.
Definition: TitleParser.php:33
$title
presenting them properly to the user as errors is done by the caller $title
Definition: hooks.txt:1324
NS_USER_TALK
const NS_USER_TALK
Definition: Defines.php:82
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
TitleValue\getText
getText()
Returns the title in text form, without namespace prefix or fragment.
Definition: TitleValue.php:128
MediaWikiTitleCodec\getPrefixedText
getPrefixedText(TitleValue $title)
Definition: MediaWikiTitleCodec.php:163
UTF8_REPLACEMENT
const UTF8_REPLACEMENT
Definition: UtfNormalDefines.php:64
MediaWikiTitleCodec\$genderCache
GenderCache $genderCache
Definition: MediaWikiTitleCodec.php:43
TitleValue\getNamespace
getNamespace()
Definition: TitleValue.php:96
IP\sanitizeIP
static sanitizeIP( $ip)
Convert an IP into a verbose, uppercase, normalized form.
Definition: IP.php:135
MalformedTitleException
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Definition: MalformedTitleException.php:31
Title\capitalize
static capitalize( $text, $ns=NS_MAIN)
Capitalize a text string for a title if it belongs to a namespace that capitalizes.
Definition: Title.php:3269
TitleFormatter
A title formatter service for MediaWiki.
Definition: TitleFormatter.php:33
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
MediaWikiTitleCodec\getFullText
getFullText(TitleValue $title)
Definition: MediaWikiTitleCodec.php:174
NS_USER
const NS_USER
Definition: Defines.php:81
NS_TALK
const NS_TALK
Definition: Defines.php:80
Title\getTitleInvalidRegex
static getTitleInvalidRegex()
Returns a simple regex that will match on characters and sequences invalid in titles.
Definition: Title.php:543
Language
Internationalisation code.
Definition: Language.php:74
MediaWikiTitleCodec\$language
Language $language
Definition: MediaWikiTitleCodec.php:39
Interwiki\isValidInterwiki
static isValidInterwiki( $prefix)
Check whether an interwiki prefix exists.
Definition: Interwiki.php:65
TitleValue
Represents a page (or page fragment) title within MediaWiki.
Definition: TitleValue.php:36