MediaWiki  1.33.0
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 
25  public function execute( $par ) {
27 
28  $this->setHeaders();
29  $this->addHelpLink( 'Help:Renameuser' );
30 
31  $out = $this->getOutput();
32  $out->addWikiMsg( 'renameuser-summary' );
33 
34  $user = $this->getUser();
35  if ( !$user->isAllowed( 'renameuser' ) ) {
36  throw new PermissionsError( 'renameuser' );
37  }
38 
39  if ( wfReadOnly() ) {
40  throw new ReadOnlyError;
41  }
42 
43  if ( $user->isBlocked() ) {
44  throw new UserBlockedError( $this->getUser()->mBlock );
45  }
46 
48 
49  $request = $this->getRequest();
50  $showBlockLog = $request->getBool( 'submit-showBlockLog' );
51  $usernames = explode( '/', $par, 2 ); // this works as "/" is not valid in usernames
52  $oldnamePar = trim( str_replace( '_', ' ', $request->getText( 'oldusername', $usernames[0] ) ) );
53  $oldusername = Title::makeTitle( NS_USER, $oldnamePar );
54  $newnamePar = $usernames[1] ?? null;
55  $newnamePar = trim( str_replace( '_', ' ', $request->getText( 'newusername', $newnamePar ) ) );
56  // Force uppercase of newusername, otherwise wikis
57  // with wgCapitalLinks=false can create lc usernames
58  $newusername = Title::makeTitleSafe( NS_USER, $wgContLang->ucfirst( $newnamePar ) );
59  $oun = is_object( $oldusername ) ? $oldusername->getText() : '';
60  $nun = is_object( $newusername ) ? $newusername->getText() : '';
61  $token = $user->getEditToken();
62  $reason = $request->getText( 'reason' );
63 
64  $move_checked = $request->getBool( 'movepages', !$request->wasPosted() );
65  $suppress_checked = $request->getCheck( 'suppressredirect' );
66 
67  $warnings = [];
68  if ( $oun && $nun && !$request->getCheck( 'confirmaction' ) ) {
69  Hooks::run( 'RenameUserWarning', [ $oun, $nun, &$warnings ] );
70  }
71 
72  $out->addHTML(
73  Xml::openElement( 'form', [
74  'method' => 'post',
75  'action' => $this->getPageTitle()->getLocalURL(),
76  'id' => 'renameuser'
77  ] ) .
78  Xml::openElement( 'fieldset' ) .
79  Xml::element( 'legend', null, $this->msg( 'renameuser' )->text() ) .
80  Xml::openElement( 'table', [ 'id' => 'mw-renameuser-table' ] ) .
81  "<tr>
82  <td class='mw-label'>" .
83  Xml::label( $this->msg( 'renameuserold' )->text(), 'oldusername' ) .
84  "</td>
85  <td class='mw-input'>" .
86  Xml::input( 'oldusername', 20, $oun, [ 'type' => 'text', 'tabindex' => '1' ] ) . ' ' .
87  "</td>
88  </tr>
89  <tr>
90  <td class='mw-label'>" .
91  Xml::label( $this->msg( 'renameusernew' )->text(), 'newusername' ) .
92  "</td>
93  <td class='mw-input'>" .
94  Xml::input( 'newusername', 20, $nun, [ 'type' => 'text', 'tabindex' => '2' ] ) .
95  "</td>
96  </tr>
97  <tr>
98  <td class='mw-label'>" .
99  Xml::label( $this->msg( 'renameuserreason' )->text(), 'reason' ) .
100  "</td>
101  <td class='mw-input'>" .
102  Xml::input(
103  'reason',
104  40,
105  $reason,
106  [ 'type' => 'text', 'tabindex' => '3', 'maxlength' => 255 ]
107  ) .
108  '</td>
109  </tr>'
110  );
111  if ( $user->isAllowed( 'move' ) ) {
112  $out->addHTML( "
113  <tr>
114  <td>&#160;
115  </td>
116  <td class='mw-input'>" .
117  Xml::checkLabel( $this->msg( 'renameusermove' )->text(), 'movepages', 'movepages',
118  $move_checked, [ 'tabindex' => '4' ] ) .
119  '</td>
120  </tr>'
121  );
122 
123  if ( $user->isAllowed( 'suppressredirect' ) ) {
124  $out->addHTML( "
125  <tr>
126  <td>&#160;
127  </td>
128  <td class='mw-input'>" .
130  $this->msg( 'renameusersuppress' )->text(),
131  'suppressredirect',
132  'suppressredirect',
133  $suppress_checked,
134  [ 'tabindex' => '5' ]
135  ) .
136  '</td>
137  </tr>'
138  );
139  }
140  }
141  if ( $warnings ) {
142  $warningsHtml = [];
143  foreach ( $warnings as $warning ) {
144  $warningsHtml[] = is_array( $warning ) ?
145  $this->msg( $warning[0] )->rawParams( array_slice( $warning, 1 ) )->escaped() :
146  $this->msg( $warning )->escaped();
147  }
148 
149  $out->addHTML( "
150  <tr>
151  <td class='mw-label'>" . $this->msg( 'renameuserwarnings' )->escaped() . "
152  </td>
153  <td class='mw-input'>" .
154  '<ul class="error"><li>' .
155  implode( '</li><li>', $warningsHtml ) . '</li></ul>' .
156  '</td>
157  </tr>'
158  );
159  $out->addHTML( "
160  <tr>
161  <td>&#160;
162  </td>
163  <td class='mw-input'>" .
165  $this->msg( 'renameuserconfirm' )->text(),
166  'confirmaction',
167  'confirmaction',
168  false,
169  [ 'tabindex' => '6' ]
170  ) .
171  '</td>
172  </tr>'
173  );
174  }
175  $out->addHTML( "
176  <tr>
177  <td>&#160;
178  </td>
179  <td class='mw-submit'>" .
181  $this->msg( 'renameusersubmit' )->text(),
182  [
183  'name' => 'submit',
184  'tabindex' => '7',
185  'id' => 'submit'
186  ]
187  ) .
188  ' ' .
190  $this->msg( 'renameuser-submit-blocklog' )->text(),
191  [
192  'name' => 'submit-showBlockLog',
193  'id' => 'submit-showBlockLog',
194  'tabindex' => '8'
195  ]
196  ) .
197  '</td>
198  </tr>' .
199  Xml::closeElement( 'table' ) .
200  Xml::closeElement( 'fieldset' ) .
201  Html::hidden( 'token', $token ) .
202  Xml::closeElement( 'form' ) . "\n"
203  );
204 
205  // Show block log if requested
206  if ( $showBlockLog && is_object( $oldusername ) ) {
207  $this->showLogExtract( $oldusername, 'block', $out );
208 
209  return;
210  }
211 
212  if ( $request->getText( 'token' ) === '' ) {
213  # They probably haven't even submitted the form, so don't go further.
214  return;
215  } elseif ( $warnings ) {
216  # Let user read warnings
217  return;
218  } elseif ( !$request->wasPosted() || !$user->matchEditToken( $request->getVal( 'token' ) ) ) {
219  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>", 'renameuser-error-request' );
220 
221  return;
222  } elseif ( !is_object( $oldusername ) ) {
223  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
224  [ 'renameusererrorinvalid', $request->getText( 'oldusername' ) ] );
225 
226  return;
227  } elseif ( !is_object( $newusername ) ) {
228  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
229  [ 'renameusererrorinvalid', $request->getText( 'newusername' ) ] );
230 
231  return;
232  } elseif ( $oldusername->getText() === $newusername->getText() ) {
233  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>", 'renameuser-error-same-user' );
234 
235  return;
236  }
237 
238  // Suppress username validation of old username
239  $olduser = User::newFromName( $oldusername->getText(), false );
240  $newuser = User::newFromName( $newusername->getText(), 'creatable' );
241 
242  // It won't be an object if for instance "|" is supplied as a value
243  if ( !is_object( $olduser ) ) {
244  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
245  [ 'renameusererrorinvalid', $oldusername->getText() ] );
246 
247  return;
248  }
249  if ( !is_object( $newuser ) || !User::isCreatableName( $newuser->getName() ) ) {
250  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
251  [ 'renameusererrorinvalid', $newusername->getText() ] );
252 
253  return;
254  }
255 
256  // Check for the existence of lowercase oldusername in database.
257  // Until r19631 it was possible to rename a user to a name with first character as lowercase
258  if ( $oldusername->getText() !== $wgContLang->ucfirst( $oldusername->getText() ) ) {
259  // oldusername was entered as lowercase -> check for existence in table 'user'
260  $dbr = wfGetDB( DB_REPLICA );
261  $uid = $dbr->selectField( 'user', 'user_id',
262  [ 'user_name' => $oldusername->getText() ],
263  __METHOD__ );
264  if ( $uid === false ) {
265  if ( !$wgCapitalLinks ) {
266  $uid = 0; // We are on a lowercase wiki but lowercase username does not exists
267  } else {
268  // We are on a standard uppercase wiki, use normal
269  $uid = $olduser->idForName();
270  $oldusername = Title::makeTitleSafe( NS_USER, $olduser->getName() );
271  }
272  }
273  } else {
274  // oldusername was entered as upperase -> standard procedure
275  $uid = $olduser->idForName();
276  }
277 
278  if ( $uid === 0 ) {
279  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
280  [ 'renameusererrordoesnotexist', $oldusername->getText() ] );
281 
282  return;
283  }
284 
285  if ( $newuser->idForName() !== 0 ) {
286  $out->wrapWikiMsg( "<div class=\"errorbox\">$1</div>",
287  [ 'renameusererrorexists', $newusername->getText() ] );
288 
289  return;
290  }
291 
292  // Give other affected extensions a chance to validate or abort
293  if ( !Hooks::run(
294  'RenameUserAbort',
295  [ $uid, $oldusername->getText(), $newusername->getText() ]
296  ) ) {
297  return;
298  }
299 
300  // Do the heavy lifting...
301  $rename = new RenameuserSQL(
302  $oldusername->getText(),
303  $newusername->getText(),
304  $uid,
305  $this->getUser(),
306  [ 'reason' => $reason ]
307  );
308  if ( !$rename->rename() ) {
309  return;
310  }
311 
312  // If this user is renaming his/herself, make sure that MovePage::move()
313  // doesn't make a bunch of null move edits under the old name!
314  if ( $user->getId() === $uid ) {
315  $user->setName( $newusername->getText() );
316  }
317 
318  // Move any user pages
319  if ( $request->getCheck( 'movepages' ) && $user->isAllowed( 'move' ) ) {
320  $dbr = wfGetDB( DB_REPLICA );
321 
322  $pages = $dbr->select(
323  'page',
324  [ 'page_namespace', 'page_title' ],
325  [
326  'page_namespace' => [ NS_USER, NS_USER_TALK ],
327  $dbr->makeList( [
328  'page_title ' . $dbr->buildLike( $oldusername->getDBkey() . '/', $dbr->anyString() ),
329  'page_title = ' . $dbr->addQuotes( $oldusername->getDBkey() ),
330  ], LIST_OR ),
331  ],
332  __METHOD__
333  );
334 
335  $suppressRedirect = false;
336 
337  if ( $request->getCheck( 'suppressredirect' ) && $user->isAllowed( 'suppressredirect' ) ) {
338  $suppressRedirect = true;
339  }
340 
341  $output = '';
342  $linkRenderer = $this->getLinkRenderer();
343  foreach ( $pages as $row ) {
344  $oldPage = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
345  $newPage = Title::makeTitleSafe( $row->page_namespace,
346  preg_replace( '!^[^/]+!', $newusername->getDBkey(), $row->page_title ) );
347 
348  $movePage = new MovePage( $oldPage, $newPage );
349  $validMoveStatus = $movePage->isValidMove();
350 
351  # Do not autodelete or anything, title must not exist
352  if ( $newPage->exists() && !$validMoveStatus->isOK() ) {
353  $link = $linkRenderer->makeKnownLink( $newPage );
354  $output .= Html::rawElement(
355  'li',
356  [ 'class' => 'mw-renameuser-pe' ],
357  $this->msg( 'renameuser-page-exists' )->rawParams( $link )->escaped()
358  );
359  } else {
360  $logReason = $this->msg(
361  'renameuser-move-log', $oldusername->getText(), $newusername->getText()
362  )->inContentLanguage()->text();
363 
364  $moveStatus = $movePage->move( $user, $logReason, !$suppressRedirect );
365 
366  if ( $moveStatus->isOK() ) {
367  # oldPage is not known in case of redirect suppression
368  $oldLink = $linkRenderer->makeLink( $oldPage, null, [], [ 'redirect' => 'no' ] );
369 
370  # newPage is always known because the move was successful
371  $newLink = $linkRenderer->makeKnownLink( $newPage );
372 
373  $output .= Html::rawElement(
374  'li',
375  [ 'class' => 'mw-renameuser-pm' ],
376  $this->msg( 'renameuser-page-moved' )->rawParams( $oldLink, $newLink )->escaped()
377  );
378  } else {
379  $oldLink = $linkRenderer->makeKnownLink( $oldPage );
380  $newLink = $linkRenderer->makeLink( $newPage );
381  $output .= Html::rawElement(
382  'li', [ 'class' => 'mw-renameuser-pu' ],
383  $this->msg( 'renameuser-page-unmoved' )->rawParams( $oldLink, $newLink )->escaped()
384  );
385  }
386  }
387  }
388  if ( $output ) {
389  $out->addHTML( Html::rawElement( 'ul', [], $output ) );
390  }
391  }
392 
393  // Output success message stuff :)
394  $out->wrapWikiMsg( "<div class=\"successbox\">$1</div><br style=\"clear:both\" />",
395  [ 'renameusersuccess', $oldusername->getText(), $newusername->getText() ] );
396  }
397 
403  protected function showLogExtract( $username, $type, &$out ) {
404  # Show relevant lines from the logs:
405  $logPage = new LogPage( $type );
406  $out->addHTML( Xml::element( 'h2', null, $logPage->getName()->text() ) . "\n" );
407  LogEventsList::showLogExtract( $out, $type, $username->getPrefixedText() );
408  }
409 
418  public function prefixSearchSubpages( $search, $limit, $offset ) {
419  $user = User::newFromName( $search );
420  if ( !$user ) {
421  // No prefix suggestion for invalid user
422  return [];
423  }
424  // Autocomplete subpage as user list - public to allow caching
425  return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
426  }
427 
428  protected function getGroupName() {
429  return 'users';
430  }
431 }
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:678
$user
return true to allow those checks to and false if checking is done & $user
Definition: hooks.txt:1476
SpecialPage\msg
msg( $key)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:796
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
UserBlockedError
Show an error when the user tries to do something whilst blocked.
Definition: UserBlockedError.php:27
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:725
SpecialRenameuser\doesWrites
doesWrites()
Indicates whether this special page may perform database writes.
Definition: SpecialRenameuser.php:12
Xml\label
static label( $label, $id, $attribs=[])
Convenience function to build an HTML form label.
Definition: Xml.php:358
$out
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not it can be in the form of< username >< more info > e g for bot passwords intended to be added to log contexts Fields it might only if the login was with a bot password 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:780
SpecialRenameuser\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialRenameuser.php:428
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:39
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1197
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:585
SpecialPage\useTransactionalTimeLimit
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: SpecialPage.php:898
PermissionsError
Show an error when a user tries to do something they do not have the necessary permissions for.
Definition: PermissionsError.php:28
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:108
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
$dbr
$dbr
Definition: testCompression.php:50
SpecialPage\addHelpLink
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition: SpecialPage.php:832
LIST_OR
const LIST_OR
Definition: Defines.php:46
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:32
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2636
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:531
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:735
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:576
$output
$output
Definition: SyntaxHighlight.php:334
LogEventsList\showLogExtract
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Definition: LogEventsList.php:627
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
$request
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:2636
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:604
NS_USER_TALK
const NS_USER_TALK
Definition: Defines.php:67
SpecialPage
Parent class for all special pages.
Definition: SpecialPage.php:36
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:715
SpecialRenameuser
Special page that allows authorised users to rename user accounts.
Definition: SpecialRenameuser.php:7
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:908
text
This list may contain false positives That usually means there is additional text with links below the first Each row contains links to the first and second as well as the first line of the second redirect text
Definition: All_system_messages.txt:1267
SpecialRenameuser\prefixSearchSubpages
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Definition: SpecialRenameuser.php:418
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:3992
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
NS_USER
const NS_USER
Definition: Defines.php:66
$link
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:3053
SpecialRenameuser\showLogExtract
showLogExtract( $username, $type, &$out)
Definition: SpecialRenameuser.php:403
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:66
SpecialRenameuser\execute
execute( $par)
Show the special page.
Definition: SpecialRenameuser.php:25
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
$wgContLang
$wgContLang
Definition: Setup.php:790
$username
this hook is for auditing only or null if authentication failed before getting that far $username
Definition: hooks.txt:780
User\isCreatableName
static isCreatableName( $name)
Usernames which fail to pass this function will be blocked from new account registrations,...
Definition: User.php:1117
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:8
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