MediaWiki  master
SpecialRedirect.php
Go to the documentation of this file.
1 <?php
26 
35 
43  protected $mType;
44 
52  protected $mValue;
53 
55  private $repoGroup;
56 
58  private $userFactory;
59 
64  public function __construct(
65  RepoGroup $repoGroup,
66  UserFactory $userFactory
67  ) {
68  parent::__construct( 'Redirect' );
69  $this->mType = null;
70  $this->mValue = null;
71 
72  $this->repoGroup = $repoGroup;
73  $this->userFactory = $userFactory;
74  }
75 
80  public function setParameter( $subpage ) {
81  // parse $subpage to pull out the parts
82  $parts = $subpage !== null ? explode( '/', $subpage, 2 ) : [];
83  $this->mType = $parts[0] ?? null;
84  $this->mValue = $parts[1] ?? null;
85  }
86 
92  public function dispatchUser() {
93  if ( !ctype_digit( $this->mValue ) ) {
94  // Message: redirect-not-numeric
95  return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
96  }
97  $user = $this->userFactory->newFromId( (int)$this->mValue );
98  $user->load(); // Make sure the id is validated by loading the user
99  if ( $user->isAnon() ) {
100  // Message: redirect-not-exists
101  return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
102  }
103  if ( $user->isHidden() && !$this->getAuthority()->isAllowed( 'hideuser' ) ) {
104  throw new PermissionsError( null, [ 'badaccess-group0' ] );
105  }
106 
107  return Status::newGood( [
108  $user->getUserPage()->getFullURL( '', false, PROTO_CURRENT ), 302
109  ] );
110  }
111 
117  public function dispatchFile() {
118  try {
119  $title = Title::newFromTextThrow( $this->mValue, NS_FILE );
120  if ( $title && !$title->inNamespace( NS_FILE ) ) {
121  // If the given value contains a namespace enforce file namespace
122  $title = Title::newFromTextThrow( Title::makeName( NS_FILE, $this->mValue ) );
123  }
124  } catch ( MalformedTitleException $e ) {
125  return Status::newFatal( $e->getMessageObject() );
126  }
127  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable False positive
128  $file = $this->repoGroup->findFile( $title );
129 
130  if ( !$file || !$file->exists() ) {
131  // Message: redirect-not-exists
132  return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
133  }
134  // Default behavior: Use the direct link to the file.
135  $url = $file->getUrl();
136  $request = $this->getRequest();
137  $width = $request->getInt( 'width', -1 );
138  $height = $request->getInt( 'height', -1 );
139 
140  // If a width is requested...
141  if ( $width != -1 ) {
142  $mto = $file->transform( [ 'width' => $width, 'height' => $height ] );
143  // ... and we can
144  if ( $mto && !$mto->isError() ) {
145  // ... change the URL to point to a thumbnail.
146  // Note: This url is more temporary as can change
147  // if file is reuploaded and has different aspect ratio.
148  $url = [ $mto->getUrl(), $height === -1 ? 301 : 302 ];
149  }
150  }
151 
152  return Status::newGood( $url );
153  }
154 
161  public function dispatchRevision() {
162  $oldid = $this->mValue;
163  if ( !ctype_digit( $oldid ) ) {
164  // Message: redirect-not-numeric
165  return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
166  }
167  $oldid = (int)$oldid;
168  if ( $oldid === 0 ) {
169  // Message: redirect-not-exists
170  return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
171  }
172 
173  return Status::newGood( wfAppendQuery( wfScript( 'index' ), [
174  'oldid' => $oldid
175  ] ) );
176  }
177 
183  public function dispatchPage() {
184  $curid = $this->mValue;
185  if ( !ctype_digit( $curid ) ) {
186  // Message: redirect-not-numeric
187  return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
188  }
189  $curid = (int)$curid;
190  if ( $curid === 0 ) {
191  // Message: redirect-not-exists
192  return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
193  }
194 
195  return Status::newGood( wfAppendQuery( wfScript( 'index' ), [
196  'curid' => $curid
197  ] ) );
198  }
199 
207  public function dispatchLog() {
208  $logid = $this->mValue;
209  if ( !ctype_digit( $logid ) ) {
210  // Message: redirect-not-numeric
211  return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
212  }
213  $logid = (int)$logid;
214  if ( $logid === 0 ) {
215  // Message: redirect-not-exists
216  return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
217  }
218  $query = [ 'title' => 'Special:Log', 'logid' => $logid ];
219  return Status::newGood( wfAppendQuery( wfScript( 'index' ), $query ) );
220  }
221 
230  private function dispatch() {
231  // the various namespaces supported by Special:Redirect
232  switch ( $this->mType ) {
233  case 'user':
234  $status = $this->dispatchUser();
235  break;
236  case 'file':
237  $status = $this->dispatchFile();
238  break;
239  case 'revision':
240  $status = $this->dispatchRevision();
241  break;
242  case 'page':
243  $status = $this->dispatchPage();
244  break;
245  case 'logid':
246  $status = $this->dispatchLog();
247  break;
248  default:
249  $status = null;
250  break;
251  }
252  if ( $status && $status->isGood() ) {
253  // These urls can sometimes be linked from prominent places,
254  // so varnish cache.
255  $value = $status->getValue();
256  if ( is_array( $value ) ) {
257  [ $url, $code ] = $value;
258  } else {
259  $url = $value;
260  $code = 301;
261  }
262  if ( $code === 301 ) {
263  $this->getOutput()->setCdnMaxage( 60 * 60 );
264  } else {
265  $this->getOutput()->setCdnMaxage( 10 );
266  }
267  $this->getOutput()->redirect( $url, $code );
268 
269  return true;
270  }
271  if ( $this->mValue !== null ) {
272  $this->getOutput()->setStatusCode( 404 );
273 
274  // @phan-suppress-next-line PhanTypeMismatchReturnNullable Null of $status seems unreachable
275  return $status;
276  }
277 
278  return false;
279  }
280 
281  protected function getFormFields() {
282  $mp = $this->getMessagePrefix();
283  $ns = [
284  // subpage => message
285  // Messages: redirect-user, redirect-page, redirect-revision,
286  // redirect-file, redirect-logid
287  'user' => $mp . '-user',
288  'page' => $mp . '-page',
289  'revision' => $mp . '-revision',
290  'file' => $mp . '-file',
291  'logid' => $mp . '-logid',
292  ];
293  $a = [];
294  $a['type'] = [
295  'type' => 'select',
296  'label-message' => $mp . '-lookup', // Message: redirect-lookup
297  'options' => [],
298  'default' => current( array_keys( $ns ) ),
299  ];
300  foreach ( $ns as $n => $m ) {
301  $m = $this->msg( $m )->text();
302  $a['type']['options'][$m] = $n;
303  }
304  $a['value'] = [
305  'type' => 'text',
306  'label-message' => $mp . '-value' // Message: redirect-value
307  ];
308  // set the defaults according to the parsed subpage path
309  if ( !empty( $this->mType ) ) {
310  $a['type']['default'] = $this->mType;
311  }
312  if ( !empty( $this->mValue ) ) {
313  $a['value']['default'] = $this->mValue;
314  }
315 
316  return $a;
317  }
318 
319  public function onSubmit( array $data ) {
320  if ( !empty( $data['type'] ) && !empty( $data['value'] ) ) {
321  $this->setParameter( $data['type'] . '/' . $data['value'] );
322  }
323 
324  /* if this returns false, will show the form */
325  return $this->dispatch();
326  }
327 
328  public function onSuccess() {
329  /* do nothing, we redirect in $this->dispatch if successful. */
330  }
331 
332  protected function alterForm( HTMLForm $form ) {
333  // tweak label on submit button
334  // Message: redirect-submit
335  $form->setSubmitTextMsg( $this->getMessagePrefix() . '-submit' );
336  }
337 
338  protected function getDisplayFormat() {
339  return 'ooui';
340  }
341 
347  protected function getSubpagesForPrefixSearch() {
348  return [
349  'file',
350  'page',
351  'revision',
352  'user',
353  'logid',
354  ];
355  }
356 
360  public function requiresPost() {
361  return false;
362  }
363 
364  protected function getGroupName() {
365  return 'redirects';
366  }
367 }
const NS_FILE
Definition: Defines.php:70
const PROTO_CURRENT
Definition: Defines.php:198
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
Special page which uses an HTMLForm to handle processing.
getMessagePrefix()
Get message prefix for HTMLForm.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:155
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
Definition: HTMLForm.php:1637
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Represents a title within MediaWiki.
Definition: Title.php:82
Creates User objects.
Definition: UserFactory.php:42
Show an error when a user tries to do something they do not have the necessary permissions for.
Prioritized list of file repositories.
Definition: RepoGroup.php:30
getOutput()
Get the OutputPage being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getRequest()
Get the WebRequest being used for this instance.
A special page that redirects to: the user for a numeric user id, the file for a given filename,...
getSubpagesForPrefixSearch()
Return an array of subpages that this special page will accept.
setParameter( $subpage)
Set $mType and $mValue based on parsed value of $subpage.
onSubmit(array $data)
Process the form on submission.
getDisplayFormat()
Get display format for the form.
dispatchLog()
Handle Special:Redirect/logid/xxx (by redirecting to index.php?title=Special:Log&logid=xxx)
getFormFields()
Get an HTMLForm descriptor array.
onSuccess()
Do something exciting on successful processing of the form, most likely to show a confirmation messag...
dispatchUser()
Handle Special:Redirect/user/xxxx (by redirecting to User:YYYY)
string null $mValue
The identifier/value for the redirect (which id, which file)
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
dispatchRevision()
Handle Special:Redirect/revision/xxx (by redirecting to index.php?oldid=xxx)
dispatchPage()
Handle Special:Redirect/page/xxx (by redirecting to index.php?curid=xxx)
dispatchFile()
Handle Special:Redirect/file/xxxx.
__construct(RepoGroup $repoGroup, UserFactory $userFactory)
string null $mType
The type of the redirect (user/file/revision)
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:73
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:85
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42