800604876f47531f718fca98303222c380d3411d
[lhc/web/wiklou.git] / includes / specials / SpecialRedirect.php
1 <?php
2 /**
3 * Implements Special:Redirect
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup SpecialPage
22 */
23
24 /**
25 * A special page that redirects to: the user for a numeric user id,
26 * the file for a given filename, or the page for a given revision id.
27 *
28 * @ingroup SpecialPage
29 * @since 1.22
30 */
31 class SpecialRedirect extends FormSpecialPage {
32
33 /**
34 * The type of the redirect (user/file/revision)
35 *
36 * Example value: `'user'`
37 *
38 * @var string $mType
39 */
40 protected $mType;
41
42 /**
43 * The identifier/value for the redirect (which id, which file)
44 *
45 * Example value: `'42'`
46 *
47 * @var string $mValue
48 */
49 protected $mValue;
50
51 function __construct() {
52 parent::__construct( 'Redirect' );
53 $this->mType = null;
54 $this->mValue = null;
55 }
56
57 /**
58 * Set $mType and $mValue based on parsed value of $subpage.
59 * @param string $subpage
60 */
61 function setParameter( $subpage ) {
62 // parse $subpage to pull out the parts
63 $parts = explode( '/', $subpage, 2 );
64 $this->mType = count( $parts ) > 0 ? $parts[0] : null;
65 $this->mValue = count( $parts ) > 1 ? $parts[1] : null;
66 }
67
68 /**
69 * Handle Special:Redirect/user/xxxx (by redirecting to User:YYYY)
70 *
71 * @return string|null Url to redirect to, or null if $mValue is invalid.
72 */
73 function dispatchUser() {
74 if ( !ctype_digit( $this->mValue ) ) {
75 return null;
76 }
77 $user = User::newFromId( (int)$this->mValue );
78 $username = $user->getName(); // load User as side-effect
79 if ( $user->isAnon() ) {
80 return null;
81 }
82 if ( $user->isHidden() && !MediaWikiServices::getInstance()->getPermissionManager()
83 ->userHasRight( $this->getUser(), 'hideuser' )
84 ) {
85 throw new PermissionsError( null, [ 'badaccess-group0' ] );
86 }
87 $userpage = Title::makeTitle( NS_USER, $username );
88
89 return $userpage->getFullURL( '', false, PROTO_CURRENT );
90 }
91
92 /**
93 * Handle Special:Redirect/file/xxxx
94 *
95 * @return string|null Url to redirect to, or null if $mValue is not found.
96 */
97 function dispatchFile() {
98 $title = Title::makeTitleSafe( NS_FILE, $this->mValue );
99
100 if ( !$title instanceof Title ) {
101 return null;
102 }
103 $file = wfFindFile( $title );
104
105 if ( !$file || !$file->exists() ) {
106 return null;
107 }
108 // Default behavior: Use the direct link to the file.
109 $url = $file->getUrl();
110 $request = $this->getRequest();
111 $width = $request->getInt( 'width', -1 );
112 $height = $request->getInt( 'height', -1 );
113
114 // If a width is requested...
115 if ( $width != -1 ) {
116 $mto = $file->transform( [ 'width' => $width, 'height' => $height ] );
117 // ... and we can
118 if ( $mto && !$mto->isError() ) {
119 // ... change the URL to point to a thumbnail.
120 $url = $mto->getUrl();
121 }
122 }
123
124 return $url;
125 }
126
127 /**
128 * Handle Special:Redirect/revision/xxx
129 * (by redirecting to index.php?oldid=xxx)
130 *
131 * @return string|null Url to redirect to, or null if $mValue is invalid.
132 */
133 function dispatchRevision() {
134 $oldid = $this->mValue;
135 if ( !ctype_digit( $oldid ) ) {
136 return null;
137 }
138 $oldid = (int)$oldid;
139 if ( $oldid === 0 ) {
140 return null;
141 }
142
143 return wfAppendQuery( wfScript( 'index' ), [
144 'oldid' => $oldid
145 ] );
146 }
147
148 /**
149 * Handle Special:Redirect/page/xxx (by redirecting to index.php?curid=xxx)
150 *
151 * @return string|null Url to redirect to, or null if $mValue is invalid.
152 */
153 function dispatchPage() {
154 $curid = $this->mValue;
155 if ( !ctype_digit( $curid ) ) {
156 return null;
157 }
158 $curid = (int)$curid;
159 if ( $curid === 0 ) {
160 return null;
161 }
162
163 return wfAppendQuery( wfScript( 'index' ), [
164 'curid' => $curid
165 ] );
166 }
167
168 /**
169 * Handle Special:Redirect/logid/xxx
170 * (by redirecting to index.php?title=Special:Log&logid=xxx)
171 *
172 * @since 1.27
173 * @return string|null Url to redirect to, or null if $mValue is invalid.
174 */
175 function dispatchLog() {
176 $logid = $this->mValue;
177 if ( !ctype_digit( $logid ) ) {
178 return null;
179 }
180 $logid = (int)$logid;
181 if ( $logid === 0 ) {
182 return null;
183 }
184 $query = [ 'title' => 'Special:Log', 'logid' => $logid ];
185 return wfAppendQuery( wfScript( 'index' ), $query );
186 }
187
188 /**
189 * Use appropriate dispatch* method to obtain a redirection URL,
190 * and either: redirect, set a 404 error code and error message,
191 * or do nothing (if $mValue wasn't set) allowing the form to be
192 * displayed.
193 *
194 * @return bool True if a redirect was successfully handled.
195 */
196 function dispatch() {
197 // the various namespaces supported by Special:Redirect
198 switch ( $this->mType ) {
199 case 'user':
200 $url = $this->dispatchUser();
201 break;
202 case 'file':
203 $url = $this->dispatchFile();
204 break;
205 case 'revision':
206 $url = $this->dispatchRevision();
207 break;
208 case 'page':
209 $url = $this->dispatchPage();
210 break;
211 case 'logid':
212 $url = $this->dispatchLog();
213 break;
214 default:
215 $url = null;
216 break;
217 }
218 if ( $url ) {
219 $this->getOutput()->redirect( $url );
220
221 return true;
222 }
223 if ( !is_null( $this->mValue ) ) {
224 $this->getOutput()->setStatusCode( 404 );
225 // Message: redirect-not-exists
226 $msg = $this->getMessagePrefix() . '-not-exists';
227
228 return Status::newFatal( $msg );
229 }
230
231 return false;
232 }
233
234 protected function getFormFields() {
235 $mp = $this->getMessagePrefix();
236 $ns = [
237 // subpage => message
238 // Messages: redirect-user, redirect-page, redirect-revision,
239 // redirect-file, redirect-logid
240 'user' => $mp . '-user',
241 'page' => $mp . '-page',
242 'revision' => $mp . '-revision',
243 'file' => $mp . '-file',
244 'logid' => $mp . '-logid',
245 ];
246 $a = [];
247 $a['type'] = [
248 'type' => 'select',
249 'label-message' => $mp . '-lookup', // Message: redirect-lookup
250 'options' => [],
251 'default' => current( array_keys( $ns ) ),
252 ];
253 foreach ( $ns as $n => $m ) {
254 $m = $this->msg( $m )->text();
255 $a['type']['options'][$m] = $n;
256 }
257 $a['value'] = [
258 'type' => 'text',
259 'label-message' => $mp . '-value' // Message: redirect-value
260 ];
261 // set the defaults according to the parsed subpage path
262 if ( !empty( $this->mType ) ) {
263 $a['type']['default'] = $this->mType;
264 }
265 if ( !empty( $this->mValue ) ) {
266 $a['value']['default'] = $this->mValue;
267 }
268
269 return $a;
270 }
271
272 public function onSubmit( array $data ) {
273 if ( !empty( $data['type'] ) && !empty( $data['value'] ) ) {
274 $this->setParameter( $data['type'] . '/' . $data['value'] );
275 }
276
277 /* if this returns false, will show the form */
278 return $this->dispatch();
279 }
280
281 public function onSuccess() {
282 /* do nothing, we redirect in $this->dispatch if successful. */
283 }
284
285 protected function alterForm( HTMLForm $form ) {
286 /* display summary at top of page */
287 $this->outputHeader();
288 // tweak label on submit button
289 // Message: redirect-submit
290 $form->setSubmitTextMsg( $this->getMessagePrefix() . '-submit' );
291 /* submit form every time */
292 $form->setMethod( 'get' );
293 }
294
295 protected function getDisplayFormat() {
296 return 'ooui';
297 }
298
299 /**
300 * Return an array of subpages that this special page will accept.
301 *
302 * @return string[] subpages
303 */
304 protected function getSubpagesForPrefixSearch() {
305 return [
306 'file',
307 'page',
308 'revision',
309 'user',
310 'logid',
311 ];
312 }
313
314 /**
315 * @return bool
316 */
317 public function requiresWrite() {
318 return false;
319 }
320
321 /**
322 * @return bool
323 */
324 public function requiresUnblock() {
325 return false;
326 }
327
328 protected function getGroupName() {
329 return 'redirects';
330 }
331 }