- * removes illegal characters, splits off the interwiki and
- * namespace prefixes, sets the other forms, and canonicalizes
- * everything.
- * @return \type{\bool} true on success
- */
- private function secureAndSplit() {
- global $wgContLang, $wgLocalInterwiki, $wgCapitalLinks;
-
- # Initialisation
- static $rxTc = false;
- if( !$rxTc ) {
- # Matching titles will be held as illegal.
- $rxTc = '/' .
- # Any character not allowed is forbidden...
- '[^' . Title::legalChars() . ']' .
- # URL percent encoding sequences interfere with the ability
- # to round-trip titles -- you can't link to them consistently.
- '|%[0-9A-Fa-f]{2}' .
- # XML/HTML character references produce similar issues.
- '|&[A-Za-z0-9\x80-\xff]+;' .
- '|&#[0-9]+;' .
- '|&#x[0-9A-Fa-f]+;' .
- '/S';
- }
-
- $this->mInterwiki = $this->mFragment = '';
- $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN
-
- $dbkey = $this->mDbkeyform;
-
- # Strip Unicode bidi override characters.
- # Sometimes they slip into cut-n-pasted page titles, where the
- # override chars get included in list displays.
- $dbkey = preg_replace( '/\xE2\x80[\x8E\x8F\xAA-\xAE]/S', '', $dbkey );
-
- # Clean up whitespace
- #
- $dbkey = preg_replace( '/[ _]+/', '_', $dbkey );
- $dbkey = trim( $dbkey, '_' );
-
- if ( '' == $dbkey ) {
- return false;
- }
-
- if( false !== strpos( $dbkey, UTF8_REPLACEMENT ) ) {
- # Contained illegal UTF-8 sequences or forbidden Unicode chars.
- return false;
- }
-
- $this->mDbkeyform = $dbkey;
-
- # Initial colon indicates main namespace rather than specified default
- # but should not create invalid {ns,title} pairs such as {0,Project:Foo}
- if ( ':' == $dbkey{0} ) {
- $this->mNamespace = NS_MAIN;
- $dbkey = substr( $dbkey, 1 ); # remove the colon but continue processing
- $dbkey = trim( $dbkey, '_' ); # remove any subsequent whitespace
- }
-
- # Namespace or interwiki prefix
- $firstPass = true;
- $prefixRegexp = "/^(.+?)_*:_*(.*)$/S";
- do {
- $m = array();
- if ( preg_match( $prefixRegexp, $dbkey, $m ) ) {
- $p = $m[1];
- if ( $ns = $wgContLang->getNsIndex( $p ) ) {
- # Ordinary namespace
- $dbkey = $m[2];
- $this->mNamespace = $ns;
- # For Talk:X pages, check if X has a "namespace" prefix
- if( $ns == NS_TALK && preg_match( $prefixRegexp, $dbkey, $x ) ) {
- if( $wgContLang->getNsIndex( $x[1] ) )
- return false; # Disallow Talk:File:x type titles...
- else if( Interwiki::isValidInterwiki( $x[1] ) )
- return false; # Disallow Talk:Interwiki:x type titles...
- }
- } elseif( Interwiki::isValidInterwiki( $p ) ) {
- if( !$firstPass ) {
- # Can't make a local interwiki link to an interwiki link.
- # That's just crazy!
- return false;
- }
-
- # Interwiki link
- $dbkey = $m[2];
- $this->mInterwiki = $wgContLang->lc( $p );
-
- # Redundant interwiki prefix to the local wiki
- if ( 0 == strcasecmp( $this->mInterwiki, $wgLocalInterwiki ) ) {
- if( $dbkey == '' ) {
- # Can't have an empty self-link
- return false;
- }
- $this->mInterwiki = '';
- $firstPass = false;
- # Do another namespace split...
- continue;
- }
-
- # If there's an initial colon after the interwiki, that also
- # resets the default namespace
- if ( $dbkey !== '' && $dbkey[0] == ':' ) {
- $this->mNamespace = NS_MAIN;
- $dbkey = substr( $dbkey, 1 );
- }
- }
- # If there's no recognized interwiki or namespace,
- # then let the colon expression be part of the title.
- }
- break;
- } while( true );
-
- # We already know that some pages won't be in the database!
- #
- if ( '' != $this->mInterwiki || NS_SPECIAL == $this->mNamespace ) {
- $this->mArticleID = 0;
- }
- $fragment = strstr( $dbkey, '#' );
- if ( false !== $fragment ) {
- $this->setFragment( $fragment );
- $dbkey = substr( $dbkey, 0, strlen( $dbkey ) - strlen( $fragment ) );
- # remove whitespace again: prevents "Foo_bar_#"
- # becoming "Foo_bar_"
- $dbkey = preg_replace( '/_*$/', '', $dbkey );
- }
-
- # Reject illegal characters.
- #
- if( preg_match( $rxTc, $dbkey ) ) {
- return false;
- }
-
- /**
- * Pages with "/./" or "/../" appearing in the URLs will often be un-
- * reachable due to the way web browsers deal with 'relative' URLs.
- * Also, they conflict with subpage syntax. Forbid them explicitly.
- */
- if ( strpos( $dbkey, '.' ) !== false &&
- ( $dbkey === '.' || $dbkey === '..' ||
- strpos( $dbkey, './' ) === 0 ||
- strpos( $dbkey, '../' ) === 0 ||
- strpos( $dbkey, '/./' ) !== false ||
- strpos( $dbkey, '/../' ) !== false ||
- substr( $dbkey, -2 ) == '/.' ||
- substr( $dbkey, -3 ) == '/..' ) )
- {
- return false;
- }
-
- /**
- * Magic tilde sequences? Nu-uh!
- */
- if( strpos( $dbkey, '~~~' ) !== false ) {
- return false;
- }
-
- /**
- * Limit the size of titles to 255 bytes.
- * This is typically the size of the underlying database field.
- * We make an exception for special pages, which don't need to be stored
- * in the database, and may edge over 255 bytes due to subpage syntax
- * for long titles, e.g. [[Special:Block/Long name]]
- */
- if ( ( $this->mNamespace != NS_SPECIAL && strlen( $dbkey ) > 255 ) ||
- strlen( $dbkey ) > 512 )
- {
- return false;
- }
-
- /**
- * Normally, all wiki links are forced to have
- * an initial capital letter so [[foo]] and [[Foo]]
- * point to the same place.
- *
- * Don't force it for interwikis, since the other
- * site might be case-sensitive.
- */
- $this->mUserCaseDBKey = $dbkey;
- if( $wgCapitalLinks && $this->mInterwiki == '') {
- $dbkey = $wgContLang->ucfirst( $dbkey );
- }
-
- /**
- * Can't make a link to a namespace alone...
- * "empty" local links can only be self-links
- * with a fragment identifier.
- */
- if( $dbkey == '' &&
- $this->mInterwiki == '' &&
- $this->mNamespace != NS_MAIN ) {
- return false;
- }
- // Allow IPv6 usernames to start with '::' by canonicalizing IPv6 titles.
- // IP names are not allowed for accounts, and can only be referring to
- // edits from the IP. Given '::' abbreviations and caps/lowercaps,
- // there are numerous ways to present the same IP. Having sp:contribs scan
- // them all is silly and having some show the edits and others not is
- // inconsistent. Same for talk/userpages. Keep them normalized instead.
- $dbkey = ($this->mNamespace == NS_USER || $this->mNamespace == NS_USER_TALK) ?
- IP::sanitizeIP( $dbkey ) : $dbkey;
- // Any remaining initial :s are illegal.
- if ( $dbkey !== '' && ':' == $dbkey{0} ) {
- return false;
- }
-
- # Fill fields
- $this->mDbkeyform = $dbkey;
- $this->mUrlform = wfUrlencode( $dbkey );
-
- $this->mTextform = str_replace( '_', ' ', $dbkey );
-
- return true;
- }
-
- /**
- * Set the fragment for this title. Removes the first character from the
- * specified fragment before setting, so it assumes you're passing it with
- * an initial "#".
- *
- * Deprecated for public use, use Title::makeTitle() with fragment parameter.
- * Still in active use privately.
- *
- * @param $fragment \type{\string} text
- */
- public function setFragment( $fragment ) {
- $this->mFragment = str_replace( '_', ' ', substr( $fragment, 1 ) );
- }
-
- /**
- * Get a Title object associated with the talk page of this article
- * @return \type{Title} the object for the talk page
- */
- public function getTalkPage() {
- return Title::makeTitle( MWNamespace::getTalk( $this->getNamespace() ), $this->getDBkey() );
- }
-
- /**
- * Get a title object associated with the subject page of this
- * talk page