MediaWiki  1.34.0
SpecialRenameuser.php
Go to the documentation of this file.
1 <?php
2 
4 
10  public function __construct() {
11  parent::__construct( 'Renameuser', 'renameuser' );
12  }
13 
14  public function doesWrites() {
15  return true;
16  }
17 
27  public function execute( $par ) {
28  global $wgCapitalLinks;
29  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
30 
31  $this->setHeaders();
32  $this->addHelpLink( 'Help:Renameuser' );
33 
34  $out = $this->getOutput();
35  $out->addWikiMsg( 'renameuser-summary' );
36 
37  $user = $this->getUser();
38  if ( !$user->isAllowed( 'renameuser' ) ) {
39  throw new PermissionsError( 'renameuser' );
40  }
41 
42  if ( wfReadOnly() ) {
43  throw new ReadOnlyError;
44  }
45 
46  if ( $user->isBlocked() ) {
47  throw new UserBlockedError( $this->getUser()->mBlock );
48  }
49 
51 
52  $request = $this->getRequest();
53  $showBlockLog = $request->getBool( 'submit-showBlockLog' );
54  $usernames = explode( '/', $par, 2 ); // this works as "/" is not valid in usernames
55  $oldnamePar = trim( str_replace( '_', ' ', $request->getText( 'oldusername', $usernames[0] ) ) );
56  $oldusername = Title::makeTitle( NS_USER, $oldnamePar );
57  $newnamePar = $usernames[1] ?? null;
58  $newnamePar = trim( str_replace( '_', ' ', $request->getText( 'newusername', $newnamePar ) ) );
59  // Force uppercase of newusername, otherwise wikis
60  // with wgCapitalLinks=false can create lc usernames
61  $newusername = Title::makeTitleSafe( NS_USER, $contLang->ucfirst( $newnamePar ) );
62  $oun = is_object( $oldusername ) ? $oldusername->getText() : '';
63  $nun = is_object( $newusername ) ? $newusername->getText() : '';
64  $token = $user->getEditToken();
65  $reason = $request->getText( 'reason' );
66 
67  $move_checked = $request->getBool( 'movepages', !$request->wasPosted() );
68  $suppress_checked = $request->getCheck( 'suppressredirect' );
69 
70  $warnings = [];
71  if ( $oun && $nun && !$request->getCheck( 'confirmaction' ) ) {
72  Hooks::run( 'RenameUserWarning', [ $oun, $nun, &$warnings ] );
73  }
74 
75  $out->addHTML(
76  Xml::openElement( 'form', [
77  'method' => 'post',
78  'action' => $this->getPageTitle()->getLocalURL(),
79  'id' => 'renameuser'
80  ] ) .
81  Xml::openElement( 'fieldset' ) .
82  Xml::element( 'legend', null, $this->msg( 'renameuser' )->text() ) .
83  Xml::openElement( 'table', [ 'id' => 'mw-renameuser-table' ] ) .
84  "<tr>
85  <td class='mw-label'>" .
86  Xml::label( $this->msg( 'renameuserold' )->text(), 'oldusername' ) .
87  "</td>
88  <td class='mw-input'>" .
89  Xml::input( 'oldusername', 20, $oun, [ 'type' => 'text', 'tabindex' => '1' ] ) . ' ' .
90  "</td>
91  </tr>
92  <tr>
93  <td class='mw-label'>" .
94  Xml::label( $this->msg( 'renameusernew' )->text(), 'newusername' ) .
95  "</td>
96  <td class='mw-input'>" .
97  Xml::input( 'newusername', 20, $nun, [ 'type' => 'text', 'tabindex' => '2' ] ) .
98  "</td>
99  </tr>
100  <tr>
101  <td class='mw-label'>" .
102  Xml::label( $this->msg( 'renameuserreason' )->text(), 'reason' ) .
103  "</td>
104  <td class='mw-input'>" .
105  Xml::input(
106  'reason',
107  40,
108  $reason,
109  [ 'type' => 'text', 'tabindex' => '3', 'maxlength' => 255 ]
110  ) .
111  '</td>
112  </tr>'
113  );
114  if ( $user->isAllowed( 'move' ) ) {
115  $out->addHTML( "
116  <tr>
117  <td>&#160;
118  </td>
119  <td class='mw-input'>" .
120  Xml::checkLabel( $this->msg( 'renameusermove' )->text(), 'movepages', 'movepages',
121  $move_checked, [ 'tabindex' => '4' ] ) .
122  '</td>
123  </tr>'
124  );
125 
126  if ( $user->isAllowed( 'suppressredirect' ) ) {
127  $out->addHTML( "
128  <tr>
129  <td>&#160;
130  </td>
131  <td class='mw-input'>" .
133  $this->msg( 'renameusersuppress' )->text(),
134  'suppressredirect',
135  'suppressredirect',
136  $suppress_checked,
137  [ 'tabindex' => '5' ]
138  ) .
139  '</td>
140  </tr>'
141  );
142  }
143  }
144  if ( $warnings ) {
145  $warningsHtml = [];
146  foreach ( $warnings as $warning ) {
147  $warningsHtml[] = is_array( $warning ) ?
148  $this->msg( $warning[0] )->rawParams( array_slice( $warning, 1 ) )->escaped() :
149  $this->msg( $warning )->escaped();
150  }
151 
152  $out->addHTML( "
153  <tr>
154  <td class='mw-label'>" . $this->msg( 'renameuserwarnings' )->escaped() . "
155  </td>
156  <td class='mw-input'>" .
157  '<ul class="error"><li>' .
158  implode( '</li><li>', $warningsHtml ) . '</li></ul>' .
159  '</td>
160  </tr>'
161  );
162  $out->addHTML( "
163  <tr>
164  <td>&#160;
165  </td>
166  <td class='mw-input'>" .
168  $this->msg( 'renameuserconfirm' )->text(),
169  'confirmaction',
170  'confirmaction',
171  false,
172  [ 'tabindex' => '6' ]
173  ) .
174  '</td>
175  </tr>'
176  );
177  }
178  $out->addHTML( "
179  <tr>
180  <td>&#160;
181  </td>
182  <td class='mw-submit'>" .
184  $this->msg( 'renameusersubmit' )->text(),
185  [
186  'name' => 'submit',
187  'tabindex' => '7',
188  'id' => 'submit'
189  ]
190  ) .
191  ' ' .
193  $this->msg( 'renameuser-submit-blocklog' )->text(),
194  [
195  'name' => 'submit-showBlockLog',
196  'id' => 'submit-showBlockLog',
197  'tabindex' => '8'
198  ]
199  ) .
200  '</td>
201  </tr>' .
202  Xml::closeElement( 'table' ) .
203  Xml::closeElement( 'fieldset' ) .
204  Html::hidden( 'token', $token ) .
205  Xml::closeElement( 'form' ) . "\n"
206  );
207 
208  // Show block log if requested
209  if ( $showBlockLog && is_object( $oldusername ) ) {
210  $this->showLogExtract( $oldusername, 'block', $out );
211 
212  return;
213  }
214 
215  if ( $request->getText( 'token' ) === '' ) {
216  # They probably haven't even submitted the form, so don't go further.
217  return;
218  } elseif ( $warnings ) {
219  # Let user read warnings
220  return;
221  } elseif ( !$request->wasPosted() || !$user->matchEditToken( $request->getVal( 'token' ) ) ) {
222  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>", 'renameuser-error-request' );
223 
224  return;
225  } elseif ( !is_object( $oldusername ) ) {
226  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
227  [ 'renameusererrorinvalid', $request->getText( 'oldusername' ) ] );
228 
229  return;
230  } elseif ( !is_object( $newusername ) ) {
231  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
232  [ 'renameusererrorinvalid', $request->getText( 'newusername' ) ] );
233 
234  return;
235  } elseif ( $oldusername->getText() === $newusername->getText() ) {
236  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>", 'renameuser-error-same-user' );
237 
238  return;
239  }
240 
241  // Suppress username validation of old username
242  $olduser = User::newFromName( $oldusername->getText(), false );
243  $newuser = User::newFromName( $newusername->getText(), 'creatable' );
244 
245  // It won't be an object if for instance "|" is supplied as a value
246  if ( !is_object( $olduser ) ) {
247  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
248  [ 'renameusererrorinvalid', $oldusername->getText() ] );
249 
250  return;
251  }
252  if ( !is_object( $newuser ) || !User::isCreatableName( $newuser->getName() ) ) {
253  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
254  [ 'renameusererrorinvalid', $newusername->getText() ] );
255 
256  return;
257  }
258 
259  // Check for the existence of lowercase oldusername in database.
260  // Until r19631 it was possible to rename a user to a name with first character as lowercase
261  if ( $oldusername->getText() !== $contLang->ucfirst( $oldusername->getText() ) ) {
262  // oldusername was entered as lowercase -> check for existence in table 'user'
263  $dbr = wfGetDB( DB_REPLICA );
264  $uid = $dbr->selectField( 'user', 'user_id',
265  [ 'user_name' => $oldusername->getText() ],
266  __METHOD__ );
267  if ( $uid === false ) {
268  if ( !$wgCapitalLinks ) {
269  $uid = 0; // We are on a lowercase wiki but lowercase username does not exists
270  } else {
271  // We are on a standard uppercase wiki, use normal
272  $uid = $olduser->idForName();
273  $oldusername = Title::makeTitleSafe( NS_USER, $olduser->getName() );
274  }
275  }
276  } else {
277  // oldusername was entered as upperase -> standard procedure
278  $uid = $olduser->idForName();
279  }
280 
281  if ( $uid === 0 ) {
282  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
283  [ 'renameusererrordoesnotexist', $oldusername->getText() ] );
284 
285  return;
286  }
287 
288  if ( $newuser->idForName() !== 0 ) {
289  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
290  [ 'renameusererrorexists', $newusername->getText() ] );
291 
292  return;
293  }
294 
295  // Give other affected extensions a chance to validate or abort
296  if ( !Hooks::run(
297  'RenameUserAbort',
298  [ $uid, $oldusername->getText(), $newusername->getText() ]
299  ) ) {
300  return;
301  }
302 
303  // Do the heavy lifting...
304  $rename = new RenameuserSQL(
305  $oldusername->getText(),
306  $newusername->getText(),
307  $uid,
308  $this->getUser(),
309  [ 'reason' => $reason ]
310  );
311  if ( !$rename->rename() ) {
312  return;
313  }
314 
315  // If this user is renaming his/herself, make sure that MovePage::move()
316  // doesn't make a bunch of null move edits under the old name!
317  if ( $user->getId() === $uid ) {
318  $user->setName( $newusername->getText() );
319  }
320 
321  // Move any user pages
322  if ( $request->getCheck( 'movepages' ) && $user->isAllowed( 'move' ) ) {
323  $dbr = wfGetDB( DB_REPLICA );
324 
325  $pages = $dbr->select(
326  'page',
327  [ 'page_namespace', 'page_title' ],
328  [
329  'page_namespace' => [ NS_USER, NS_USER_TALK ],
330  $dbr->makeList( [
331  'page_title ' . $dbr->buildLike( $oldusername->getDBkey() . '/', $dbr->anyString() ),
332  'page_title = ' . $dbr->addQuotes( $oldusername->getDBkey() ),
333  ], LIST_OR ),
334  ],
335  __METHOD__
336  );
337 
338  $suppressRedirect = false;
339 
340  if ( $request->getCheck( 'suppressredirect' ) && $user->isAllowed( 'suppressredirect' ) ) {
341  $suppressRedirect = true;
342  }
343 
344  $output = '';
345  $linkRenderer = $this->getLinkRenderer();
346  foreach ( $pages as $row ) {
347  $oldPage = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
348  $newPage = Title::makeTitleSafe( $row->page_namespace,
349  preg_replace( '!^[^/]+!', $newusername->getDBkey(), $row->page_title ) );
350 
351  $movePage = new MovePage( $oldPage, $newPage );
352  $validMoveStatus = $movePage->isValidMove();
353 
354  # Do not autodelete or anything, title must not exist
355  if ( $newPage->exists() && !$validMoveStatus->isOK() ) {
356  $link = $linkRenderer->makeKnownLink( $newPage );
357  $output .= Html::rawElement(
358  'li',
359  [ 'class' => 'mw-renameuser-pe' ],
360  $this->msg( 'renameuser-page-exists' )->rawParams( $link )->escaped()
361  );
362  } else {
363  $logReason = $this->msg(
364  'renameuser-move-log', $oldusername->getText(), $newusername->getText()
365  )->inContentLanguage()->text();
366 
367  $moveStatus = $movePage->move( $user, $logReason, !$suppressRedirect );
368 
369  if ( $moveStatus->isOK() ) {
370  # oldPage is not known in case of redirect suppression
371  $oldLink = $linkRenderer->makeLink( $oldPage, null, [], [ 'redirect' => 'no' ] );
372 
373  # newPage is always known because the move was successful
374  $newLink = $linkRenderer->makeKnownLink( $newPage );
375 
376  $output .= Html::rawElement(
377  'li',
378  [ 'class' => 'mw-renameuser-pm' ],
379  $this->msg( 'renameuser-page-moved' )->rawParams( $oldLink, $newLink )->escaped()
380  );
381  } else {
382  $oldLink = $linkRenderer->makeKnownLink( $oldPage );
383  $newLink = $linkRenderer->makeLink( $newPage );
384  $output .= Html::rawElement(
385  'li', [ 'class' => 'mw-renameuser-pu' ],
386  $this->msg( 'renameuser-page-unmoved' )->rawParams( $oldLink, $newLink )->escaped()
387  );
388  }
389  }
390  }
391  if ( $output ) {
392  $out->addHTML( Html::rawElement( 'ul', [], $output ) );
393  }
394  }
395 
396  // Output success message stuff :)
397  $out->wrapWikiMsg( "<div class=\"successbox\">$1</div><br style=\"clear:both\" />",
398  [ 'renameusersuccess', $oldusername->getText(), $newusername->getText() ] );
399  }
400 
406  protected function showLogExtract( $username, $type, &$out ) {
407  # Show relevant lines from the logs:
408  $logPage = new LogPage( $type );
409  $out->addHTML( Xml::element( 'h2', null, $logPage->getName()->text() ) . "\n" );
410  LogEventsList::showLogExtract( $out, $type, $username->getPrefixedText() );
411  }
412 
421  public function prefixSearchSubpages( $search, $limit, $offset ) {
422  $user = User::newFromName( $search );
423  if ( !$user ) {
424  // No prefix suggestion for invalid user
425  return [];
426  }
427  // Autocomplete subpage as user list - public to allow caching
428  return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
429  }
430 
431  protected function getGroupName() {
432  return 'users';
433  }
434 }
ReadOnlyError
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
Definition: ReadOnlyError.php:28
SpecialPage\getPageTitle
getPageTitle( $subpage=false)
Get a self-referential title object.
Definition: SpecialPage.php:672
SpecialPage\msg
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:792
UserBlockedError
Show an error when the user tries to do something whilst blocked.
Definition: UserBlockedError.php:29
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:719
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:117
SpecialRenameuser\doesWrites
doesWrites()
Indicates whether this special page may perform database writes.
Definition: SpecialRenameuser.php:14
Xml\label
static label( $label, $id, $attribs=[])
Convenience function to build an HTML form label.
Definition: Xml.php:358
SpecialRenameuser\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialRenameuser.php:431
UserNamePrefixSearch\search
static search( $audience, $search, $limit, $offset=0)
Do a prefix search of user names and return a list of matching user names.
Definition: UserNamePrefixSearch.php:41
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1171
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:515
SpecialPage\useTransactionalTimeLimit
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: SpecialPage.php:894
PermissionsError
Show an error when a user tries to do something they do not have the necessary permissions for.
Definition: PermissionsError.php:30
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:108
$dbr
$dbr
Definition: testCompression.php:50
SpecialPage\addHelpLink
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition: SpecialPage.php:828
LIST_OR
const LIST_OR
Definition: Defines.php:42
RenameuserSQL
Class which performs the actual renaming of users.
Definition: RenameuserSQL.php:8
MovePage
Handles the backend logic of moving a page from one title to another.
Definition: MovePage.php:36
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2575
LogPage
Class to simplify the use of log pages.
Definition: LogPage.php:33
Xml\element
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:41
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
Definition: SpecialPage.php:537
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:729
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:586
$output
$output
Definition: SyntaxHighlight.php:335
LogEventsList\showLogExtract
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Definition: LogEventsList.php:624
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:613
NS_USER_TALK
const NS_USER_TALK
Definition: Defines.php:63
SpecialPage
Parent class for all special pages.
Definition: SpecialPage.php:37
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:709
SpecialRenameuser
Special page that allows authorised users to rename user accounts.
Definition: SpecialRenameuser.php:9
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:904
SpecialRenameuser\prefixSearchSubpages
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Definition: SpecialRenameuser.php:421
Xml\closeElement
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:117
$wgCapitalLinks
$wgCapitalLinks
Set this to false to avoid forcing the first letter of links to capitals.
Definition: DefaultSettings.php:4006
NS_USER
const NS_USER
Definition: Defines.php:62
SpecialRenameuser\showLogExtract
showLogExtract( $username, $type, &$out)
Definition: SpecialRenameuser.php:406
Xml\input
static input( $name, $size=false, $value=false, $attribs=[])
Convenience function to build an HTML text input field.
Definition: Xml.php:274
SpecialPage\$linkRenderer
MediaWiki Linker LinkRenderer null $linkRenderer
Definition: SpecialPage.php:67
SpecialRenameuser\execute
execute( $par)
Show the special page.
Definition: SpecialRenameuser.php:27
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
User\isCreatableName
static isCreatableName( $name)
Usernames which fail to pass this function will be blocked from new account registrations,...
Definition: User.php:1041
Xml\submitButton
static submitButton( $value, $attribs=[])
Convenience function to build an HTML submit button When $wgUseMediaWikiUIEverywhere is true it will ...
Definition: Xml.php:459
SpecialRenameuser\__construct
__construct()
Definition: SpecialRenameuser.php:10
Xml\checkLabel
static checkLabel( $label, $name, $id, $checked=false, $attribs=[])
Convenience function to build an HTML checkbox with a label.
Definition: Xml.php:419
$type
$type
Definition: testCompression.php:48