* Extract a redirect destination from a string and return the
* Title, or null if the text doesn't contain a valid redirect
*
- * @param $text \type{String} Text with possible redirect
+ * @param $text \type{\string} Text with possible redirect
+ * @param $getAllTargets \type{\bool} Should we get an array of every target or just the final one?
+ * @param $noRecurse \type{\bool} This will prevent any and all recursion, only getting the very next target
+ * This is mainly meant for Article::insertRedirect so that the redirect table still works properly
+ * (makes double redirect and broken redirect reports display accurate results).
* @return \type{Title} The corresponding Title
- */
- public static function newFromRedirect( $text ) {
+ * @return \type{\array} Array of redirect targets (Title objects), with the destination being last
+ */
+ public static function newFromRedirect( $text, $getAllTargets = false, $noRecurse = false ) {
+ global $wgMaxRedirects;
+ // are redirects disabled?
+ // Note that we should get a Title object if possible if $noRecurse is true so that the redirect table functions properly
+ if( !$noRecurse && $wgMaxRedirects < 1 )
+ return null;
$redir = MagicWord::get( 'redirect' );
$text = trim($text);
if( $redir->matchStartAndRemove( $text ) ) {
$m[1] = urldecode( ltrim( $m[1], ':' ) );
}
$title = Title::newFromText( $m[1] );
- // Redirects to some special pages are not permitted
- if( $title instanceof Title
- && !$title->isSpecial( 'Userlogout' )
- && !$title->isSpecial( 'Filepath' ) )
- {
+ // If the initial title is a redirect to bad special pages or is invalid, quit early
+ if( !$title instanceof Title || !$title->isValidRedirectTarget() ) {
+ return null;
+ }
+ // If $noRecurse is true, simply return here
+ if( $noRecurse ) {
+ return $title;
+ }
+ // recursive check to follow double redirects
+ $recurse = $wgMaxRedirects;
+ $targets = array();
+ while( --$recurse >= 0 ) {
+ // Redirects to some special pages are not permitted
+ if( $title instanceof Title && $title->isValidRedirectTarget() ) {
+ $targets[] = $title;
+ if( $title->isRedirect() ) {
+ $article = new Article( $title, 0 );
+ $title = $article->getRedirectTarget();
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ if( $getAllTargets ) {
+ // return every target or null if no targets due to invalid title or whatever
+ return ( $targets === array() ) ? null : $targets;
+ } else {
+ // return the final destination -- invalid titles are checked earlier
return $title;
}
}
*/
static function escapeFragmentForURL( $fragment ) {
global $wgEnforceHtmlIds;
+ # Note that we don't urlencode the fragment. urlencoded Unicode
+ # fragments appear not to work in IE (at least up to 7) or in at least
+ # one version of Opera 9.x. The W3C validator, for one, doesn't seem
+ # to care if they aren't encoded.
return Sanitizer::escapeId( $fragment,
- $wgEnforceHtmlIds ? array() : 'xml' );
+ $wgEnforceHtmlIds ? 'noninitial' : 'xml' );
}
#----------------------------------------------------------------------------
else if( $result === false )
$errors[] = array('badaccess-group0'); # a generic "We don't want them to do that"
}
- if( $doExpensiveQueries && !wfRunHooks( 'getUserPermissionsErrorsExpensive',
- array(&$this,&$user,$action,&$result) ) )
- {
+ if( $doExpensiveQueries && !wfRunHooks( 'getUserPermissionsErrorsExpensive', array(&$this,&$user,$action,&$result) ) ) {
if( is_array($result) && count($result) && !is_array($result[0]) )
$errors[] = $result; # A single array representing an error
else if( is_array($result) && is_array($result[0]) )
# protect css/js subpages of user pages
# XXX: this might be better using restrictions
- # XXX: Find a way to work around the php bug that prevents using
- # $this->userCanEditCssJsSubpage() from working
+ # XXX: Find a way to work around the php bug that prevents using $this->userCanEditCssJsSubpage() from working
if( $this->isCssJsSubpage() && !$user->isAllowed('editusercssjs')
&& !preg_match('/^'.preg_quote($user->getName(), '/').'\//', $this->mTextform) )
{
$right = ( $right == 'sysop' ) ? 'protect' : $right;
if( '' != $right && !$user->isAllowed( $right ) ) {
$pages = '';
- foreach( $cascadingSources as $page ) {
+ foreach( $cascadingSources as $page )
$pages .= '* [[:' . $page->getPrefixedText() . "]]\n";
- }
$errors[] = array( 'cascadeprotected', count( $cascadingSources ), $pages );
}
}
}
}
- # Get restrictions on each action, 'create' handled below
- if( $action != 'create' ) {
- foreach( $this->getRestrictions($action) as $right ) {
- // Backwards compatibility, rewrite sysop -> protect
- if( $right == 'sysop' ) {
- $right = 'protect';
- }
- if( '' != $right && !$user->isAllowed( $right ) ) {
- // Users with 'editprotected' permission can edit protected pages
- if( $action=='edit' && $user->isAllowed( 'editprotected' ) ) {
- // Users with 'editprotected' permission cannot edit protected pages
- // with cascading option turned on.
- if( $this->mCascadeRestriction ) {
- $errors[] = array( 'protectedpagetext', $right );
- } else {
- // Nothing, user can edit!
- }
- } else {
+ foreach( $this->getRestrictions($action) as $right ) {
+ // Backwards compatibility, rewrite sysop -> protect
+ if( $right == 'sysop' ) {
+ $right = 'protect';
+ }
+ if( '' != $right && !$user->isAllowed( $right ) ) {
+ // Users with 'editprotected' permission can edit protected pages
+ if( $action=='edit' && $user->isAllowed( 'editprotected' ) ) {
+ // Users with 'editprotected' permission cannot edit protected pages
+ // with cascading option turned on.
+ if( $this->mCascadeRestriction ) {
$errors[] = array( 'protectedpagetext', $right );
+ } else {
+ // Nothing, user can edit!
}
+ } else {
+ $errors[] = array( 'protectedpagetext', $right );
}
}
}
- if( $action == 'protect' && $this->getUserPermissionsErrors('edit',$user) != array() ) {
- $errors[] = array( 'protect-cantedit' ); // If they can't edit, they shouldn't protect.
+ if( $action == 'protect' ) {
+ if( $this->getUserPermissionsErrors('edit', $user) != array() ) {
+ $errors[] = array( 'protect-cantedit' ); // If they can't edit, they shouldn't protect.
+ }
}
if( $action == 'create' ) {
# Namespace or interwiki prefix
$firstPass = true;
+ $prefixRegexp = "/^(.+?)_*:_*(.*)$/S";
do {
$m = array();
- if ( preg_match( "/^(.+?)_*:_*(.*)$/S", $dbkey, $m ) ) {
+ if ( preg_match( $prefixRegexp, $dbkey, $m ) ) {
$p = $m[1];
- if ( $ns = $wgContLang->getNsIndex( $p )) {
+ if ( $ns = $wgContLang->getNsIndex( $p ) ) {
# Ordinary namespace
$dbkey = $m[2];
- # Disallow Talk:File:x type titles...
- if( $this->mNamespace == NS_TALK && $ns > 0 )
- return false; // bug 5280 title issues
$this->mNamespace = $ns;
- if( $ns == NS_TALK && $firstPass )
- continue; # Do another namespace split...
+ # 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.
);
# Update the protection log
$log = new LogPage( 'protect' );
- $comment = wfMsgForContent('prot_1movedto2',$this->getPrefixedText(), $nt->getPrefixedText() );
- if( $reason ) $comment .= ': ' . $reason;
+ $comment = wfMsgForContent( 'prot_1movedto2', $this->getPrefixedText(), $nt->getPrefixedText() );
+ if( $reason ) $comment .= wfMsgForContent( 'colon-separator' ) . $reason;
$log->addEntry( 'move_prot', $nt, $comment, array($this->getPrefixedText()) ); // FIXME: $params?
}
);
}
+ /**
+ * Get the first revision of the page
+ *
+ * @param $flags \type{\int} GAID_FOR_UPDATE
+ * @return Revision (or NULL if page doesn't exist)
+ */
+ public function getFirstRevision( $flags=0 ) {
+ $db = ($flags & GAID_FOR_UPDATE) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
+ $pageId = $this->getArticleId($flags);
+ if( !$pageId ) return NULL;
+ $row = $db->selectRow( 'revision', '*',
+ array( 'rev_page' => $pageId ),
+ __METHOD__,
+ array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 1 )
+ );
+ if( !$row ) {
+ return NULL;
+ } else {
+ return new Revision( $row );
+ }
+ }
+
/**
* Check if this is a new page
*
}
return $redirs;
}
+
+ /**
+ * Check if this Title is a valid redirect target
+ *
+ * @return \type{\bool} TRUE or FALSE
+ */
+ public function isValidRedirectTarget() {
+ global $wgInvalidRedirectTargets;
+
+ // invalid redirect targets are stored in a global array, but explicity disallow Userlogout here
+ if( $this->isSpecial( 'Userlogout' ) ) {
+ return false;
+ }
+
+ foreach( $wgInvalidRedirectTargets as $target ) {
+ if( $this->isSpecial( $target ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}