MediaWiki REL1_31
SpecialRenameuser.php
Go to the documentation of this file.
1<?php
2
8 public function __construct() {
9 parent::__construct( 'Renameuser', 'renameuser' );
10 }
11
12 public function doesWrites() {
13 return true;
14 }
15
24 public function execute( $par ) {
26
27 $this->setHeaders();
28 $this->addHelpLink( 'Help:Renameuser' );
29
30 $out = $this->getOutput();
31 $out->addWikiMsg( 'renameuser-summary' );
32
33 $user = $this->getUser();
34 if ( !$user->isAllowed( 'renameuser' ) ) {
35 throw new PermissionsError( 'renameuser' );
36 }
37
38 if ( wfReadOnly() ) {
39 throw new ReadOnlyError;
40 }
41
42 if ( $user->isBlocked() ) {
43 throw new UserBlockedError( $this->getUser()->mBlock );
44 }
45
47
48 $request = $this->getRequest();
49 $showBlockLog = $request->getBool( 'submit-showBlockLog' );
50 $usernames = explode( '/', $par, 2 ); // this works as "/" is not valid in usernames
51 $oldnamePar = trim( str_replace( '_', ' ', $request->getText( 'oldusername', $usernames[0] ) ) );
52 $oldusername = Title::makeTitle( NS_USER, $oldnamePar );
53 $newnamePar = isset( $usernames[1] ) ? $usernames[1] : null;
54 $newnamePar = trim( str_replace( '_', ' ', $request->getText( 'newusername', $newnamePar ) ) );
55 // Force uppercase of newusername, otherwise wikis
56 // with wgCapitalLinks=false can create lc usernames
57 $newusername = Title::makeTitleSafe( NS_USER, $wgContLang->ucfirst( $newnamePar ) );
58 $oun = is_object( $oldusername ) ? $oldusername->getText() : '';
59 $nun = is_object( $newusername ) ? $newusername->getText() : '';
60 $token = $user->getEditToken();
61 $reason = $request->getText( 'reason' );
62
63 $move_checked = $request->getBool( 'movepages', !$request->wasPosted() );
64 $suppress_checked = $request->getCheck( 'suppressredirect' );
65
66 $warnings = [];
67 if ( $oun && $nun && !$request->getCheck( 'confirmaction' ) ) {
68 Hooks::run( 'RenameUserWarning', [ $oun, $nun, &$warnings ] );
69 }
70
71 $out->addHTML(
72 Xml::openElement( 'form', [
73 'method' => 'post',
74 'action' => $this->getPageTitle()->getLocalURL(),
75 'id' => 'renameuser'
76 ] ) .
77 Xml::openElement( 'fieldset' ) .
78 Xml::element( 'legend', null, $this->msg( 'renameuser' )->text() ) .
79 Xml::openElement( 'table', [ 'id' => 'mw-renameuser-table' ] ) .
80 "<tr>
81 <td class='mw-label'>" .
82 Xml::label( $this->msg( 'renameuserold' )->text(), 'oldusername' ) .
83 "</td>
84 <td class='mw-input'>" .
85 Xml::input( 'oldusername', 20, $oun, [ 'type' => 'text', 'tabindex' => '1' ] ) . ' ' .
86 "</td>
87 </tr>
88 <tr>
89 <td class='mw-label'>" .
90 Xml::label( $this->msg( 'renameusernew' )->text(), 'newusername' ) .
91 "</td>
92 <td class='mw-input'>" .
93 Xml::input( 'newusername', 20, $nun, [ 'type' => 'text', 'tabindex' => '2' ] ) .
94 "</td>
95 </tr>
96 <tr>
97 <td class='mw-label'>" .
98 Xml::label( $this->msg( 'renameuserreason' )->text(), 'reason' ) .
99 "</td>
100 <td class='mw-input'>" .
101 Xml::input(
102 'reason',
103 40,
104 $reason,
105 [ 'type' => 'text', 'tabindex' => '3', 'maxlength' => 255 ]
106 ) .
107 '</td>
108 </tr>'
109 );
110 if ( $user->isAllowed( 'move' ) ) {
111 $out->addHTML( "
112 <tr>
113 <td>&#160;
114 </td>
115 <td class='mw-input'>" .
116 Xml::checkLabel( $this->msg( 'renameusermove' )->text(), 'movepages', 'movepages',
117 $move_checked, [ 'tabindex' => '4' ] ) .
118 '</td>
119 </tr>'
120 );
121
122 if ( $user->isAllowed( 'suppressredirect' ) ) {
123 $out->addHTML( "
124 <tr>
125 <td>&#160;
126 </td>
127 <td class='mw-input'>" .
128 Xml::checkLabel(
129 $this->msg( 'renameusersuppress' )->text(),
130 'suppressredirect',
131 'suppressredirect',
132 $suppress_checked,
133 [ 'tabindex' => '5' ]
134 ) .
135 '</td>
136 </tr>'
137 );
138 }
139 }
140 if ( $warnings ) {
141 $warningsHtml = [];
142 foreach ( $warnings as $warning ) {
143 $warningsHtml[] = is_array( $warning ) ?
144 $this->msg( $warning[0] )->rawParams( array_slice( $warning, 1 ) )->escaped() :
145 $this->msg( $warning )->escaped();
146 }
147
148 $out->addHTML( "
149 <tr>
150 <td class='mw-label'>" . $this->msg( 'renameuserwarnings' )->escaped() . "
151 </td>
152 <td class='mw-input'>" .
153 '<ul class="error"><li>' .
154 implode( '</li><li>', $warningsHtml ) . '</li></ul>' .
155 '</td>
156 </tr>'
157 );
158 $out->addHTML( "
159 <tr>
160 <td>&#160;
161 </td>
162 <td class='mw-input'>" .
163 Xml::checkLabel(
164 $this->msg( 'renameuserconfirm' )->text(),
165 'confirmaction',
166 'confirmaction',
167 false,
168 [ 'tabindex' => '6' ]
169 ) .
170 '</td>
171 </tr>'
172 );
173 }
174 $out->addHTML( "
175 <tr>
176 <td>&#160;
177 </td>
178 <td class='mw-submit'>" .
179 Xml::submitButton(
180 $this->msg( 'renameusersubmit' )->text(),
181 [
182 'name' => 'submit',
183 'tabindex' => '7',
184 'id' => 'submit'
185 ]
186 ) .
187 ' ' .
188 Xml::submitButton(
189 $this->msg( 'renameuser-submit-blocklog' )->text(),
190 [
191 'name' => 'submit-showBlockLog',
192 'id' => 'submit-showBlockLog',
193 'tabindex' => '8'
194 ]
195 ) .
196 '</td>
197 </tr>' .
198 Xml::closeElement( 'table' ) .
199 Xml::closeElement( 'fieldset' ) .
200 Html::hidden( 'token', $token ) .
201 Xml::closeElement( 'form' ) . "\n"
202 );
203
204 // Show block log if requested
205 if ( $showBlockLog && is_object( $oldusername ) ) {
206 $this->showLogExtract( $oldusername, 'block', $out );
207
208 return;
209 }
210
211 if ( $request->getText( 'token' ) === '' ) {
212 # They probably haven't even submitted the form, so don't go further.
213 return;
214 } elseif ( $warnings ) {
215 # Let user read warnings
216 return;
217 } elseif ( !$request->wasPosted() || !$user->matchEditToken( $request->getVal( 'token' ) ) ) {
218 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>", 'renameuser-error-request' );
219
220 return;
221 } elseif ( !is_object( $oldusername ) ) {
222 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
223 [ 'renameusererrorinvalid', $request->getText( 'oldusername' ) ] );
224
225 return;
226 } elseif ( !is_object( $newusername ) ) {
227 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
228 [ 'renameusererrorinvalid', $request->getText( 'newusername' ) ] );
229
230 return;
231 } elseif ( $oldusername->getText() === $newusername->getText() ) {
232 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>", 'renameuser-error-same-user' );
233
234 return;
235 }
236
237 // Suppress username validation of old username
238 $olduser = User::newFromName( $oldusername->getText(), false );
239 $newuser = User::newFromName( $newusername->getText(), 'creatable' );
240
241 // It won't be an object if for instance "|" is supplied as a value
242 if ( !is_object( $olduser ) ) {
243 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
244 [ 'renameusererrorinvalid', $oldusername->getText() ] );
245
246 return;
247 }
248 if ( !is_object( $newuser ) || !User::isCreatableName( $newuser->getName() ) ) {
249 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
250 [ 'renameusererrorinvalid', $newusername->getText() ] );
251
252 return;
253 }
254
255 // Check for the existence of lowercase oldusername in database.
256 // Until r19631 it was possible to rename a user to a name with first character as lowercase
257 if ( $oldusername->getText() !== $wgContLang->ucfirst( $oldusername->getText() ) ) {
258 // oldusername was entered as lowercase -> check for existence in table 'user'
260 $uid = $dbr->selectField( 'user', 'user_id',
261 [ 'user_name' => $oldusername->getText() ],
262 __METHOD__ );
263 if ( $uid === false ) {
264 if ( !$wgCapitalLinks ) {
265 $uid = 0; // We are on a lowercase wiki but lowercase username does not exists
266 } else {
267 // We are on a standard uppercase wiki, use normal
268 $uid = $olduser->idForName();
269 $oldusername = Title::makeTitleSafe( NS_USER, $olduser->getName() );
270 }
271 }
272 } else {
273 // oldusername was entered as upperase -> standard procedure
274 $uid = $olduser->idForName();
275 }
276
277 if ( $uid === 0 ) {
278 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
279 [ 'renameusererrordoesnotexist', $oldusername->getText() ] );
280
281 return;
282 }
283
284 if ( $newuser->idForName() !== 0 ) {
285 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
286 [ 'renameusererrorexists', $newusername->getText() ] );
287
288 return;
289 }
290
291 // Give other affected extensions a chance to validate or abort
292 if ( !Hooks::run(
293 'RenameUserAbort',
294 [ $uid, $oldusername->getText(), $newusername->getText() ]
295 ) ) {
296 return;
297 }
298
299 // Do the heavy lifting...
300 $rename = new RenameuserSQL(
301 $oldusername->getText(),
302 $newusername->getText(),
303 $uid,
304 $this->getUser(),
305 [ 'reason' => $reason ]
306 );
307 if ( !$rename->rename() ) {
308 return;
309 }
310
311 // If this user is renaming his/herself, make sure that Title::moveTo()
312 // doesn't make a bunch of null move edits under the old name!
313 if ( $user->getId() === $uid ) {
314 $user->setName( $newusername->getText() );
315 }
316
317 // Move any user pages
318 if ( $request->getCheck( 'movepages' ) && $user->isAllowed( 'move' ) ) {
320
321 $pages = $dbr->select(
322 'page',
323 [ 'page_namespace', 'page_title' ],
324 [
325 'page_namespace' => [ NS_USER, NS_USER_TALK ],
326 $dbr->makeList( [
327 'page_title ' . $dbr->buildLike( $oldusername->getDBkey() . '/', $dbr->anyString() ),
328 'page_title = ' . $dbr->addQuotes( $oldusername->getDBkey() ),
329 ], LIST_OR ),
330 ],
331 __METHOD__
332 );
333
334 $suppressRedirect = false;
335
336 if ( $request->getCheck( 'suppressredirect' ) && $user->isAllowed( 'suppressredirect' ) ) {
337 $suppressRedirect = true;
338 }
339
340 $output = '';
342 foreach ( $pages as $row ) {
343 $oldPage = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
344 $newPage = Title::makeTitleSafe( $row->page_namespace,
345 preg_replace( '!^[^/]+!', $newusername->getDBkey(), $row->page_title ) );
346 # Do not autodelete or anything, title must not exist
347 if ( $newPage->exists() && !$oldPage->isValidMoveTarget( $newPage ) ) {
348 $link = $linkRenderer->makeKnownLink( $newPage );
349 $output .= Html::rawElement(
350 'li',
351 [ 'class' => 'mw-renameuser-pe' ],
352 $this->msg( 'renameuser-page-exists' )->rawParams( $link )->escaped()
353 );
354 } else {
355 $success = $oldPage->moveTo(
356 $newPage,
357 false,
358 $this->msg(
359 'renameuser-move-log',
360 $oldusername->getText(),
361 $newusername->getText() )->inContentLanguage()->text(),
362 !$suppressRedirect
363 );
364 if ( $success === true ) {
365 # oldPage is not known in case of redirect suppression
366 $oldLink = $linkRenderer->makeLink( $oldPage, null, [], [ 'redirect' => 'no' ] );
367
368 # newPage is always known because the move was successful
369 $newLink = $linkRenderer->makeKnownLink( $newPage );
370
371 $output .= Html::rawElement(
372 'li',
373 [ 'class' => 'mw-renameuser-pm' ],
374 $this->msg( 'renameuser-page-moved' )->rawParams( $oldLink, $newLink )->escaped()
375 );
376 } else {
377 $oldLink = $linkRenderer->makeKnownLink( $oldPage );
378 $newLink = $linkRenderer->makeLink( $newPage );
379 $output .= Html::rawElement(
380 'li', [ 'class' => 'mw-renameuser-pu' ],
381 $this->msg( 'renameuser-page-unmoved' )->rawParams( $oldLink, $newLink )->escaped()
382 );
383 }
384 }
385 }
386 if ( $output ) {
387 $out->addHTML( Html::rawElement( 'ul', [], $output ) );
388 }
389 }
390
391 // Output success message stuff :)
392 $out->wrapWikiMsg( "<div class=\"successbox\">$1</div><br style=\"clear:both\" />",
393 [ 'renameusersuccess', $oldusername->getText(), $newusername->getText() ] );
394 }
395
401 protected function showLogExtract( $username, $type, &$out ) {
402 # Show relevant lines from the logs:
403 $logPage = new LogPage( $type );
404 $out->addHTML( Xml::element( 'h2', null, $logPage->getName()->text() ) . "\n" );
405 LogEventsList::showLogExtract( $out, $type, $username->getPrefixedText() );
406 }
407
416 public function prefixSearchSubpages( $search, $limit, $offset ) {
417 if ( !class_exists( 'UserNamePrefixSearch' ) ) { // check for version 1.27
418 return [];
419 }
420 $user = User::newFromName( $search );
421 if ( !$user ) {
422 // No prefix suggestion for invalid user
423 return [];
424 }
425 // Autocomplete subpage as user list - public to allow caching
426 return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
427 }
428
429 protected function getGroupName() {
430 return 'users';
431 }
432}
$wgCapitalLinks
Set this to false to avoid forcing the first letter of links to capitals.
wfReadOnly()
Check whether the wiki is in read-only mode.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Class to simplify the use of log pages.
Definition LogPage.php:31
Show an error when a user tries to do something they do not have the necessary permissions for.
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
Class which performs the actual renaming of users.
Parent class for all special pages.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
getUser()
Shortcut to get the User executing this instance.
msg( $key)
Wrapper around wfMessage that sets the current context.
getRequest()
Get the WebRequest being used for this instance.
getPageTitle( $subpage=false)
Get a self-referential title object.
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
MediaWiki Linker LinkRenderer null $linkRenderer
Special page that allows authorised users to rename user accounts.
doesWrites()
Indicates whether this special page may perform database writes.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
execute( $par)
Show the special page.
showLogExtract( $username, $type, &$out)
Show an error when the user tries to do something whilst blocked.
static search( $audience, $search, $limit, $offset=0)
Do a prefix search of user names and return a list of matching user names.
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition User.php:591
static isCreatableName( $name)
Usernames which fail to pass this function will be blocked from new account registrations,...
Definition User.php:1093
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the local content language as $wgContLang
Definition design.txt:57
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition design.txt:18
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on $request
Definition hooks.txt:2806
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title after the basic globals have been set but before ordinary actions take place $output
Definition hooks.txt:2255
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition hooks.txt:864
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition hooks.txt:3021
this hook is for auditing only or null if authentication failed before getting that far $username
Definition hooks.txt:785
const LIST_OR
Definition Defines.php:56
const NS_USER_TALK
Definition Defines.php:77
const DB_REPLICA
Definition defines.php:25