MediaWiki REL1_39
SpecialRedirect.php
Go to the documentation of this file.
1<?php
25
34
42 protected $mType;
43
51 protected $mValue;
52
54 private $repoGroup;
55
57 private $userFactory;
58
63 public function __construct(
64 RepoGroup $repoGroup,
65 UserFactory $userFactory
66 ) {
67 parent::__construct( 'Redirect' );
68 $this->mType = null;
69 $this->mValue = null;
70
71 $this->repoGroup = $repoGroup;
72 $this->userFactory = $userFactory;
73 }
74
79 public function setParameter( $subpage ) {
80 // parse $subpage to pull out the parts
81 $parts = $subpage !== null ? explode( '/', $subpage, 2 ) : [];
82 $this->mType = $parts[0] ?? null;
83 $this->mValue = $parts[1] ?? null;
84 }
85
91 public function dispatchUser() {
92 if ( !ctype_digit( $this->mValue ) ) {
93 // Message: redirect-not-numeric
94 return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
95 }
96 $user = $this->userFactory->newFromId( (int)$this->mValue );
97 $user->load(); // Make sure the id is validated by loading the user
98 if ( $user->isAnon() ) {
99 // Message: redirect-not-exists
100 return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
101 }
102 if ( $user->isHidden() && !$this->getAuthority()->isAllowed( 'hideuser' ) ) {
103 throw new PermissionsError( null, [ 'badaccess-group0' ] );
104 }
105
106 return Status::newGood( [
107 $user->getUserPage()->getFullURL( '', false, PROTO_CURRENT ), 302
108 ] );
109 }
110
116 public function dispatchFile() {
117 try {
118 $title = Title::newFromTextThrow( $this->mValue, NS_FILE );
119 if ( $title && !$title->inNamespace( NS_FILE ) ) {
120 // If the given value contains a namespace enforce file namespace
121 $title = Title::newFromTextThrow( Title::makeName( NS_FILE, $this->mValue ) );
122 }
123 } catch ( MalformedTitleException $e ) {
124 return Status::newFatal( $e->getMessageObject() );
125 }
126 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable False positive
127 $file = $this->repoGroup->findFile( $title );
128
129 if ( !$file || !$file->exists() ) {
130 // Message: redirect-not-exists
131 return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
132 }
133 // Default behavior: Use the direct link to the file.
134 $url = $file->getUrl();
135 $request = $this->getRequest();
136 $width = $request->getInt( 'width', -1 );
137 $height = $request->getInt( 'height', -1 );
138
139 // If a width is requested...
140 if ( $width != -1 ) {
141 $mto = $file->transform( [ 'width' => $width, 'height' => $height ] );
142 // ... and we can
143 if ( $mto && !$mto->isError() ) {
144 // ... change the URL to point to a thumbnail.
145 // Note: This url is more temporary as can change
146 // if file is reuploaded and has different aspect ratio.
147 $url = [ $mto->getUrl(), $height === -1 ? 301 : 302 ];
148 }
149 }
150
151 return Status::newGood( $url );
152 }
153
160 public function dispatchRevision() {
161 $oldid = $this->mValue;
162 if ( !ctype_digit( $oldid ) ) {
163 // Message: redirect-not-numeric
164 return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
165 }
166 $oldid = (int)$oldid;
167 if ( $oldid === 0 ) {
168 // Message: redirect-not-exists
169 return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
170 }
171
172 return Status::newGood( wfAppendQuery( wfScript( 'index' ), [
173 'oldid' => $oldid
174 ] ) );
175 }
176
182 public function dispatchPage() {
183 $curid = $this->mValue;
184 if ( !ctype_digit( $curid ) ) {
185 // Message: redirect-not-numeric
186 return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
187 }
188 $curid = (int)$curid;
189 if ( $curid === 0 ) {
190 // Message: redirect-not-exists
191 return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
192 }
193
194 return Status::newGood( wfAppendQuery( wfScript( 'index' ), [
195 'curid' => $curid
196 ] ) );
197 }
198
206 public function dispatchLog() {
207 $logid = $this->mValue;
208 if ( !ctype_digit( $logid ) ) {
209 // Message: redirect-not-numeric
210 return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
211 }
212 $logid = (int)$logid;
213 if ( $logid === 0 ) {
214 // Message: redirect-not-exists
215 return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
216 }
217 $query = [ 'title' => 'Special:Log', 'logid' => $logid ];
218 return Status::newGood( wfAppendQuery( wfScript( 'index' ), $query ) );
219 }
220
229 private function dispatch() {
230 // the various namespaces supported by Special:Redirect
231 switch ( $this->mType ) {
232 case 'user':
233 $status = $this->dispatchUser();
234 break;
235 case 'file':
236 $status = $this->dispatchFile();
237 break;
238 case 'revision':
239 $status = $this->dispatchRevision();
240 break;
241 case 'page':
242 $status = $this->dispatchPage();
243 break;
244 case 'logid':
245 $status = $this->dispatchLog();
246 break;
247 default:
248 $status = null;
249 break;
250 }
251 if ( $status && $status->isGood() ) {
252 // These urls can sometimes be linked from prominent places,
253 // so varnish cache.
254 $value = $status->getValue();
255 if ( is_array( $value ) ) {
256 list( $url, $code ) = $value;
257 } else {
258 $url = $value;
259 $code = 301;
260 }
261 if ( $code === 301 ) {
262 $this->getOutput()->setCdnMaxage( 60 * 60 );
263 } else {
264 $this->getOutput()->setCdnMaxage( 10 );
265 }
266 $this->getOutput()->redirect( $url, $code );
267
268 return true;
269 }
270 if ( $this->mValue !== null ) {
271 $this->getOutput()->setStatusCode( 404 );
272
273 // @phan-suppress-next-line PhanTypeMismatchReturnNullable Null of $status seems unreachable
274 return $status;
275 }
276
277 return false;
278 }
279
280 protected function getFormFields() {
281 $mp = $this->getMessagePrefix();
282 $ns = [
283 // subpage => message
284 // Messages: redirect-user, redirect-page, redirect-revision,
285 // redirect-file, redirect-logid
286 'user' => $mp . '-user',
287 'page' => $mp . '-page',
288 'revision' => $mp . '-revision',
289 'file' => $mp . '-file',
290 'logid' => $mp . '-logid',
291 ];
292 $a = [];
293 $a['type'] = [
294 'type' => 'select',
295 'label-message' => $mp . '-lookup', // Message: redirect-lookup
296 'options' => [],
297 'default' => current( array_keys( $ns ) ),
298 ];
299 foreach ( $ns as $n => $m ) {
300 $m = $this->msg( $m )->text();
301 $a['type']['options'][$m] = $n;
302 }
303 $a['value'] = [
304 'type' => 'text',
305 'label-message' => $mp . '-value' // Message: redirect-value
306 ];
307 // set the defaults according to the parsed subpage path
308 if ( !empty( $this->mType ) ) {
309 $a['type']['default'] = $this->mType;
310 }
311 if ( !empty( $this->mValue ) ) {
312 $a['value']['default'] = $this->mValue;
313 }
314
315 return $a;
316 }
317
318 public function onSubmit( array $data ) {
319 if ( !empty( $data['type'] ) && !empty( $data['value'] ) ) {
320 $this->setParameter( $data['type'] . '/' . $data['value'] );
321 }
322
323 /* if this returns false, will show the form */
324 return $this->dispatch();
325 }
326
327 public function onSuccess() {
328 /* do nothing, we redirect in $this->dispatch if successful. */
329 }
330
331 protected function alterForm( HTMLForm $form ) {
332 /* display summary at top of page */
333 $this->outputHeader();
334 // tweak label on submit button
335 // Message: redirect-submit
336 $form->setSubmitTextMsg( $this->getMessagePrefix() . '-submit' );
337 /* submit form every time */
338 $form->setMethod( 'get' );
339 }
340
341 protected function getDisplayFormat() {
342 return 'ooui';
343 }
344
350 protected function getSubpagesForPrefixSearch() {
351 return [
352 'file',
353 'page',
354 'revision',
355 'user',
356 'logid',
357 ];
358 }
359
363 public function requiresWrite() {
364 return false;
365 }
366
370 public function requiresUnblock() {
371 return false;
372 }
373
374 protected function getGroupName() {
375 return 'redirects';
376 }
377}
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:150
setMethod( $method='post')
Set the method used to submit the form.
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Creates User objects.
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:29
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
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 POST 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)
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition router.php:42