MediaWiki REL1_30
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
29 $out = $this->getOutput();
30 $out->addWikiMsg( 'renameuser-summary' );
31
32 $user = $this->getUser();
33 if ( !$user->isAllowed( 'renameuser' ) ) {
34 throw new PermissionsError( 'renameuser' );
35 }
36
37 if ( wfReadOnly() ) {
38 throw new ReadOnlyError;
39 }
40
41 if ( $user->isBlocked() ) {
42 throw new UserBlockedError( $this->getUser()->mBlock );
43 }
44
46
47 $request = $this->getRequest();
48 $showBlockLog = $request->getBool( 'submit-showBlockLog' );
49 $usernames = explode( '/', $par, 2 ); // this works as "/" is not valid in usernames
50 $oldnamePar = trim( str_replace( '_', ' ', $request->getText( 'oldusername', $usernames[0] ) ) );
51 $oldusername = Title::makeTitle( NS_USER, $oldnamePar );
52 $newnamePar = isset( $usernames[1] ) ? $usernames[1] : null;
53 $newnamePar = trim( str_replace( '_', ' ', $request->getText( 'newusername', $newnamePar ) ) );
54 // Force uppercase of newusername, otherwise wikis
55 // with wgCapitalLinks=false can create lc usernames
56 $newusername = Title::makeTitleSafe( NS_USER, $wgContLang->ucfirst( $newnamePar ) );
57 $oun = is_object( $oldusername ) ? $oldusername->getText() : '';
58 $nun = is_object( $newusername ) ? $newusername->getText() : '';
59 $token = $user->getEditToken();
60 $reason = $request->getText( 'reason' );
61
62 $move_checked = $request->getBool( 'movepages', !$request->wasPosted() );
63 $suppress_checked = $request->getCheck( 'suppressredirect' );
64
65 $warnings = [];
66 if ( $oun && $nun && !$request->getCheck( 'confirmaction' ) ) {
67 Hooks::run( 'RenameUserWarning', [ $oun, $nun, &$warnings ] );
68 }
69
70 $out->addHTML(
71 Xml::openElement( 'form', [
72 'method' => 'post',
73 'action' => $this->getPageTitle()->getLocalURL(),
74 'id' => 'renameuser'
75 ] ) .
76 Xml::openElement( 'fieldset' ) .
77 Xml::element( 'legend', null, $this->msg( 'renameuser' )->text() ) .
78 Xml::openElement( 'table', [ 'id' => 'mw-renameuser-table' ] ) .
79 "<tr>
80 <td class='mw-label'>" .
81 Xml::label( $this->msg( 'renameuserold' )->text(), 'oldusername' ) .
82 "</td>
83 <td class='mw-input'>" .
84 Xml::input( 'oldusername', 20, $oun, [ 'type' => 'text', 'tabindex' => '1' ] ) . ' ' .
85 "</td>
86 </tr>
87 <tr>
88 <td class='mw-label'>" .
89 Xml::label( $this->msg( 'renameusernew' )->text(), 'newusername' ) .
90 "</td>
91 <td class='mw-input'>" .
92 Xml::input( 'newusername', 20, $nun, [ 'type' => 'text', 'tabindex' => '2' ] ) .
93 "</td>
94 </tr>
95 <tr>
96 <td class='mw-label'>" .
97 Xml::label( $this->msg( 'renameuserreason' )->text(), 'reason' ) .
98 "</td>
99 <td class='mw-input'>" .
100 Xml::input(
101 'reason',
102 40,
103 $reason,
104 [ 'type' => 'text', 'tabindex' => '3', 'maxlength' => 255 ]
105 ) .
106 '</td>
107 </tr>'
108 );
109 if ( $user->isAllowed( 'move' ) ) {
110 $out->addHTML( "
111 <tr>
112 <td>&#160;
113 </td>
114 <td class='mw-input'>" .
115 Xml::checkLabel( $this->msg( 'renameusermove' )->text(), 'movepages', 'movepages',
116 $move_checked, [ 'tabindex' => '4' ] ) .
117 '</td>
118 </tr>'
119 );
120
121 if ( $user->isAllowed( 'suppressredirect' ) ) {
122 $out->addHTML( "
123 <tr>
124 <td>&#160;
125 </td>
126 <td class='mw-input'>" .
127 Xml::checkLabel(
128 $this->msg( 'renameusersuppress' )->text(),
129 'suppressredirect',
130 'suppressredirect',
131 $suppress_checked,
132 [ 'tabindex' => '5' ]
133 ) .
134 '</td>
135 </tr>'
136 );
137 }
138 }
139 if ( $warnings ) {
140 $warningsHtml = [];
141 foreach ( $warnings as $warning ) {
142 $warningsHtml[] = is_array( $warning ) ?
143 $this->msg( $warning[0] )->rawParams( array_slice( $warning, 1 ) )->escaped() :
144 $this->msg( $warning )->escaped();
145 }
146
147 $out->addHTML( "
148 <tr>
149 <td class='mw-label'>" . $this->msg( 'renameuserwarnings' )->escaped() . "
150 </td>
151 <td class='mw-input'>" .
152 '<ul class="error"><li>' .
153 implode( '</li><li>', $warningsHtml ) . '</li></ul>' .
154 '</td>
155 </tr>'
156 );
157 $out->addHTML( "
158 <tr>
159 <td>&#160;
160 </td>
161 <td class='mw-input'>" .
162 Xml::checkLabel(
163 $this->msg( 'renameuserconfirm' )->text(),
164 'confirmaction',
165 'confirmaction',
166 false,
167 [ 'tabindex' => '6' ]
168 ) .
169 '</td>
170 </tr>'
171 );
172 }
173 $out->addHTML( "
174 <tr>
175 <td>&#160;
176 </td>
177 <td class='mw-submit'>" .
178 Xml::submitButton(
179 $this->msg( 'renameusersubmit' )->text(),
180 [
181 'name' => 'submit',
182 'tabindex' => '7',
183 'id' => 'submit'
184 ]
185 ) .
186 ' ' .
187 Xml::submitButton(
188 $this->msg( 'renameuser-submit-blocklog' )->text(),
189 [
190 'name' => 'submit-showBlockLog',
191 'id' => 'submit-showBlockLog',
192 'tabindex' => '8'
193 ]
194 ) .
195 '</td>
196 </tr>' .
197 Xml::closeElement( 'table' ) .
198 Xml::closeElement( 'fieldset' ) .
199 Html::hidden( 'token', $token ) .
200 Xml::closeElement( 'form' ) . "\n"
201 );
202
203 // Show block log if requested
204 if ( $showBlockLog && is_object( $oldusername ) ) {
205 $this->showLogExtract( $oldusername, 'block', $out );
206
207 return;
208 }
209
210 if ( $request->getText( 'token' ) === '' ) {
211 # They probably haven't even submitted the form, so don't go further.
212 return;
213 } elseif ( $warnings ) {
214 # Let user read warnings
215 return;
216 } elseif ( !$request->wasPosted() || !$user->matchEditToken( $request->getVal( 'token' ) ) ) {
217 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>", 'renameuser-error-request' );
218
219 return;
220 } elseif ( !is_object( $oldusername ) ) {
221 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
222 [ 'renameusererrorinvalid', $request->getText( 'oldusername' ) ] );
223
224 return;
225 } elseif ( !is_object( $newusername ) ) {
226 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
227 [ 'renameusererrorinvalid', $request->getText( 'newusername' ) ] );
228
229 return;
230 } elseif ( $oldusername->getText() === $newusername->getText() ) {
231 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>", 'renameuser-error-same-user' );
232
233 return;
234 }
235
236 // Suppress username validation of old username
237 $olduser = User::newFromName( $oldusername->getText(), false );
238 $newuser = User::newFromName( $newusername->getText(), 'creatable' );
239
240 // It won't be an object if for instance "|" is supplied as a value
241 if ( !is_object( $olduser ) ) {
242 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
243 [ 'renameusererrorinvalid', $oldusername->getText() ] );
244
245 return;
246 }
247 if ( !is_object( $newuser ) || !User::isCreatableName( $newuser->getName() ) ) {
248 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
249 [ 'renameusererrorinvalid', $newusername->getText() ] );
250
251 return;
252 }
253
254 // Check for the existence of lowercase oldusername in database.
255 // Until r19631 it was possible to rename a user to a name with first character as lowercase
256 if ( $oldusername->getText() !== $wgContLang->ucfirst( $oldusername->getText() ) ) {
257 // oldusername was entered as lowercase -> check for existence in table 'user'
258 $dbr = wfGetDB( DB_SLAVE );
259 $uid = $dbr->selectField( 'user', 'user_id',
260 [ 'user_name' => $oldusername->getText() ],
261 __METHOD__ );
262 if ( $uid === false ) {
263 if ( !$wgCapitalLinks ) {
264 $uid = 0; // We are on a lowercase wiki but lowercase username does not exists
265 } else {
266 // We are on a standard uppercase wiki, use normal
267 $uid = $olduser->idForName();
268 $oldusername = Title::makeTitleSafe( NS_USER, $olduser->getName() );
269 }
270 }
271 } else {
272 // oldusername was entered as upperase -> standard procedure
273 $uid = $olduser->idForName();
274 }
275
276 if ( $uid === 0 ) {
277 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
278 [ 'renameusererrordoesnotexist', $oldusername->getText() ] );
279
280 return;
281 }
282
283 if ( $newuser->idForName() !== 0 ) {
284 $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
285 [ 'renameusererrorexists', $newusername->getText() ] );
286
287 return;
288 }
289
290 // Give other affected extensions a chance to validate or abort
291 if ( !Hooks::run(
292 'RenameUserAbort',
293 [ $uid, $oldusername->getText(), $newusername->getText() ]
294 ) ) {
295 return;
296 }
297
298 // Do the heavy lifting...
299 $rename = new RenameuserSQL(
300 $oldusername->getText(),
301 $newusername->getText(),
302 $uid,
303 $this->getUser(),
304 [ 'reason' => $reason ]
305 );
306 if ( !$rename->rename() ) {
307 return;
308 }
309
310 // If this user is renaming his/herself, make sure that Title::moveTo()
311 // doesn't make a bunch of null move edits under the old name!
312 if ( $user->getId() === $uid ) {
313 $user->setName( $newusername->getText() );
314 }
315
316 // Move any user pages
317 if ( $request->getCheck( 'movepages' ) && $user->isAllowed( 'move' ) ) {
318 $dbr = wfGetDB( DB_SLAVE );
319
320 $pages = $dbr->select(
321 'page',
322 [ 'page_namespace', 'page_title' ],
323 [
324 'page_namespace IN (' . NS_USER . ',' . NS_USER_TALK . ')',
325 '(page_title ' . $dbr->buildLike( $oldusername->getDBkey() . '/', $dbr->anyString() ) .
326 ' OR page_title = ' . $dbr->addQuotes( $oldusername->getDBkey() ) . ')'
327 ],
328 __METHOD__
329 );
330
331 $suppressRedirect = false;
332
333 if ( $request->getCheck( 'suppressredirect' ) && $user->isAllowed( 'suppressredirect' ) ) {
334 $suppressRedirect = true;
335 }
336
337 $output = '';
338 foreach ( $pages as $row ) {
339 $oldPage = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
340 $newPage = Title::makeTitleSafe( $row->page_namespace,
341 preg_replace( '!^[^/]+!', $newusername->getDBkey(), $row->page_title ) );
342 # Do not autodelete or anything, title must not exist
343 if ( $newPage->exists() && !$oldPage->isValidMoveTarget( $newPage ) ) {
344 $link = Linker::linkKnown( $newPage );
345 $output .= Html::rawElement(
346 'li',
347 [ 'class' => 'mw-renameuser-pe' ],
348 $this->msg( 'renameuser-page-exists' )->rawParams( $link )->escaped()
349 );
350 } else {
351 $success = $oldPage->moveTo(
352 $newPage,
353 false,
354 $this->msg(
355 'renameuser-move-log',
356 $oldusername->getText(),
357 $newusername->getText() )->inContentLanguage()->text(),
358 !$suppressRedirect
359 );
360 if ( $success === true ) {
361 # oldPage is not known in case of redirect suppression
362 $oldLink = Linker::link( $oldPage, null, [], [ 'redirect' => 'no' ] );
363
364 # newPage is always known because the move was successful
365 $newLink = Linker::linkKnown( $newPage );
366
367 $output .= Html::rawElement(
368 'li',
369 [ 'class' => 'mw-renameuser-pm' ],
370 $this->msg( 'renameuser-page-moved' )->rawParams( $oldLink, $newLink )->escaped()
371 );
372 } else {
373 $oldLink = Linker::linkKnown( $oldPage );
374 $newLink = Linker::link( $newPage );
375 $output .= Html::rawElement(
376 'li', [ 'class' => 'mw-renameuser-pu' ],
377 $this->msg( 'renameuser-page-unmoved' )->rawParams( $oldLink, $newLink )->escaped()
378 );
379 }
380 }
381 }
382 if ( $output ) {
383 $out->addHTML( Html::rawElement( 'ul', [], $output ) );
384 }
385 }
386
387 // Output success message stuff :)
388 $out->wrapWikiMsg( "<div class=\"successbox\">$1</div><br style=\"clear:both\" />",
389 [ 'renameusersuccess', $oldusername->getText(), $newusername->getText() ] );
390 }
391
397 protected function showLogExtract( $username, $type, &$out ) {
398 # Show relevant lines from the logs:
399 $logPage = new LogPage( $type );
400 $out->addHTML( Xml::element( 'h2', null, $logPage->getName()->text() ) . "\n" );
401 LogEventsList::showLogExtract( $out, $type, $username->getPrefixedText() );
402 }
403
412 public function prefixSearchSubpages( $search, $limit, $offset ) {
413 if ( !class_exists( 'UserNamePrefixSearch' ) ) { // check for version 1.27
414 return [];
415 }
416 $user = User::newFromName( $search );
417 if ( !$user ) {
418 // No prefix suggestion for invalid user
419 return [];
420 }
421 // Autocomplete subpage as user list - public to allow caching
422 return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
423 }
424
425 protected function getGroupName() {
426 return 'users';
427 }
428}
$wgCapitalLinks
Set this to false to avoid forcing the first letter of links to capitals.
const DB_SLAVE
Definition Defines.php:37
wfReadOnly()
Check whether the wiki is in read-only mode.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
static link( $target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
Definition Linker.php:107
static linkKnown( $target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to 'known'.
Definition Linker.php:164
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.
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.
if(! $regexes) $dbr
Definition cleanup.php:94
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:2775
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:2225
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:862
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition hooks.txt:2989
this hook is for auditing only or null if authentication failed before getting that far $username
Definition hooks.txt:783
const NS_USER_TALK
Definition Defines.php:68