/**
* Handle Special:Redirect/user/xxxx (by redirecting to User:YYYY)
*
- * @return string|null Url to redirect to, or null if $mValue is invalid.
+ * @return Status A good status contains the url to redirect to
*/
function dispatchUser() {
if ( !ctype_digit( $this->mValue ) ) {
- return null;
+ // Message: redirect-not-numeric
+ return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
}
$user = User::newFromId( (int)$this->mValue );
$username = $user->getName(); // load User as side-effect
if ( $user->isAnon() ) {
- return null;
+ // Message: redirect-not-exists
+ return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
+ }
+ if ( $user->isHidden() && !$this->getUser()->isAllowed( 'hideuser' ) ) {
+ throw new PermissionsError( null, [ 'badaccess-group0' ] );
}
$userpage = Title::makeTitle( NS_USER, $username );
- return $userpage->getFullURL( '', false, PROTO_CURRENT );
+ return Status::newGood( [
+ $userpage->getFullURL( '', false, PROTO_CURRENT ), 302
+ ] );
}
/**
* Handle Special:Redirect/file/xxxx
*
- * @return string|null Url to redirect to, or null if $mValue is not found.
+ * @return Status A good status contains the url to redirect to
*/
function dispatchFile() {
- $title = Title::makeTitleSafe( NS_FILE, $this->mValue );
-
- if ( !$title instanceof Title ) {
- return null;
+ try {
+ $title = Title::newFromTextThrow( $this->mValue, NS_FILE );
+ if ( $title && !$title->inNamespace( NS_FILE ) ) {
+ // If the given value contains a namespace enforce file namespace
+ $title = Title::newFromTextThrow( Title::makeName( NS_FILE, $this->mValue ) );
+ }
+ } catch ( MalformedTitleException $e ) {
+ return Status::newFatal( $e->getMessageObject() );
}
$file = wfFindFile( $title );
if ( !$file || !$file->exists() ) {
- return null;
+ // Message: redirect-not-exists
+ return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
}
// Default behavior: Use the direct link to the file.
$url = $file->getUrl();
// ... and we can
if ( $mto && !$mto->isError() ) {
// ... change the URL to point to a thumbnail.
- $url = $mto->getUrl();
+ // Note: This url is more temporary as can change
+ // if file is reuploaded and has different aspect ratio.
+ $url = [ $mto->getUrl(), $height === -1 ? 301 : 302 ];
}
}
- return $url;
+ return Status::newGood( $url );
}
/**
* Handle Special:Redirect/revision/xxx
* (by redirecting to index.php?oldid=xxx)
*
- * @return string|null Url to redirect to, or null if $mValue is invalid.
+ * @return Status A good status contains the url to redirect to
*/
function dispatchRevision() {
$oldid = $this->mValue;
if ( !ctype_digit( $oldid ) ) {
- return null;
+ // Message: redirect-not-numeric
+ return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
}
$oldid = (int)$oldid;
if ( $oldid === 0 ) {
- return null;
+ // Message: redirect-not-exists
+ return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
}
- return wfAppendQuery( wfScript( 'index' ), [
+ return Status::newGood( wfAppendQuery( wfScript( 'index' ), [
'oldid' => $oldid
- ] );
+ ] ) );
}
/**
* Handle Special:Redirect/page/xxx (by redirecting to index.php?curid=xxx)
*
- * @return string|null Url to redirect to, or null if $mValue is invalid.
+ * @return Status A good status contains the url to redirect to
*/
function dispatchPage() {
$curid = $this->mValue;
if ( !ctype_digit( $curid ) ) {
- return null;
+ // Message: redirect-not-numeric
+ return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
}
$curid = (int)$curid;
if ( $curid === 0 ) {
- return null;
+ // Message: redirect-not-exists
+ return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
}
- return wfAppendQuery( wfScript( 'index' ), [
+ return Status::newGood( wfAppendQuery( wfScript( 'index' ), [
'curid' => $curid
- ] );
+ ] ) );
}
/**
* Handle Special:Redirect/logid/xxx
- * (by redirecting to index.php?title=Special:Log)
+ * (by redirecting to index.php?title=Special:Log&logid=xxx)
*
* @since 1.27
- * @return string|null Url to redirect to, or null if $mValue is invalid.
+ * @return Status A good status contains the url to redirect to
*/
function dispatchLog() {
$logid = $this->mValue;
if ( !ctype_digit( $logid ) ) {
- return null;
+ // Message: redirect-not-numeric
+ return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
}
$logid = (int)$logid;
if ( $logid === 0 ) {
- return null;
- }
-
- $logparams = [
- 'log_id',
- 'log_timestamp',
- 'log_type',
- 'log_user_text',
- ];
-
- $dbr = wfGetDB( DB_REPLICA );
-
- // Gets the nested SQL statement which
- // returns timestamp of the log with the given log ID
- $inner = $dbr->selectSQLText(
- 'logging',
- [ 'log_timestamp' ],
- [ 'log_id' => $logid ]
- );
-
- // Returns all fields mentioned in $logparams of the logs
- // with the same timestamp as the one returned by the statement above
- $logsSameTimestamps = $dbr->select(
- 'logging',
- $logparams,
- [ "log_timestamp = ($inner)" ]
- );
- if ( $logsSameTimestamps->numRows() === 0 ) {
- return null;
- }
-
- // Stores the row with the same log ID as the one given
- $rowMain = [];
- foreach ( $logsSameTimestamps as $row ) {
- if ( (int)$row->log_id === $logid ) {
- $rowMain = $row;
- }
- }
-
- array_shift( $logparams );
-
- // Stores all the rows with the same values in each column
- // as $rowMain
- foreach ( $logparams as $cond ) {
- $matchedRows = [];
- foreach ( $logsSameTimestamps as $row ) {
- if ( $row->$cond === $rowMain->$cond ) {
- $matchedRows[] = $row;
- }
- }
- if ( count( $matchedRows ) === 1 ) {
- break;
- }
- $logsSameTimestamps = $matchedRows;
- }
- $query = [ 'title' => 'Special:Log', 'limit' => count( $matchedRows ) ];
-
- // A map of database field names from table 'logging' to the values of $logparams
- $keys = [
- 'log_timestamp' => 'offset',
- 'log_type' => 'type',
- 'log_user_text' => 'user'
- ];
-
- foreach ( $logparams as $logKey ) {
- $query[$keys[$logKey]] = $matchedRows[0]->$logKey;
+ // Message: redirect-not-exists
+ return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
}
- $query['offset'] = $query['offset'] + 1;
- $url = $query;
-
- return wfAppendQuery( wfScript( 'index' ), $url );
+ $query = [ 'title' => 'Special:Log', 'logid' => $logid ];
+ return Status::newGood( wfAppendQuery( wfScript( 'index' ), $query ) );
}
/**
* or do nothing (if $mValue wasn't set) allowing the form to be
* displayed.
*
- * @return bool True if a redirect was successfully handled.
+ * @return Status|bool True if a redirect was successfully handled.
*/
function dispatch() {
// the various namespaces supported by Special:Redirect
switch ( $this->mType ) {
case 'user':
- $url = $this->dispatchUser();
+ $status = $this->dispatchUser();
break;
case 'file':
- $url = $this->dispatchFile();
+ $status = $this->dispatchFile();
break;
case 'revision':
- $url = $this->dispatchRevision();
+ $status = $this->dispatchRevision();
break;
case 'page':
- $url = $this->dispatchPage();
+ $status = $this->dispatchPage();
break;
case 'logid':
- $url = $this->dispatchLog();
+ $status = $this->dispatchLog();
break;
default:
- $url = null;
+ $status = null;
break;
}
- if ( $url ) {
- $this->getOutput()->redirect( $url );
+ if ( $status && $status->isGood() ) {
+ // These urls can sometimes be linked from prominent places,
+ // so varnish cache.
+ $value = $status->getValue();
+ if ( is_array( $value ) ) {
+ list( $url, $code ) = $value;
+ } else {
+ $url = $value;
+ $code = 301;
+ }
+ if ( $code === 301 ) {
+ $this->getOutput()->setCdnMaxage( 60 * 60 );
+ } else {
+ $this->getOutput()->setCdnMaxage( 10 );
+ }
+ $this->getOutput()->redirect( $url, $code );
return true;
}
if ( !is_null( $this->mValue ) ) {
$this->getOutput()->setStatusCode( 404 );
- // Message: redirect-not-exists
- $msg = $this->getMessagePrefix() . '-not-exists';
- return Status::newFatal( $msg );
+ return $status;
}
return false;