MediaWiki  1.30.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 
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'>" .
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'>" .
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'>" .
179  $this->msg( 'renameusersubmit' )->text(),
180  [
181  'name' => 'submit',
182  'tabindex' => '7',
183  'id' => 'submit'
184  ]
185  ) .
186  ' ' .
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 );
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 
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 );
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 }
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:628
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:244
SpecialPage\msg
msg( $key)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:746
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:675
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
text
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:12
SpecialRenameuser\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialRenameuser.php:425
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:1324
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:550
Linker\linkKnown
static linkKnown( $target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to 'known'.
Definition: Linker.php:164
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:37
SpecialPage\useTransactionalTimeLimit
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: SpecialPage.php:850
PermissionsError
Show an error when a user tries to do something they do not have the necessary permissions for.
Definition: PermissionsError.php:28
$success
$success
Definition: NoLocalSettings.php:44
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:109
$output
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:2198
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
RenameuserSQL
Class which performs the actual renaming of users.
Definition: RenameuserSQL.php:9
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2856
LogPage
Class to simplify the use of log pages.
Definition: LogPage.php:31
Xml\element
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:39
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
Definition: SpecialPage.php:484
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:685
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:529
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
LogEventsList\showLogExtract
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Definition: LogEventsList.php:594
$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:2581
Html\hidden
static hidden( $name, $value, array $attribs=[])
Convenience function to produce an input element with type=hidden.
Definition: Html.php:725
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:557
NS_USER_TALK
const NS_USER_TALK
Definition: Defines.php:68
SpecialPage
Parent class for all special pages.
Definition: SpecialPage.php:36
Linker\link
static link( $target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
Definition: Linker.php:107
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:665
SpecialRenameuser
Special page that allows authorised users to rename user accounts.
Definition: SpecialRenameuser.php:7
SpecialRenameuser\prefixSearchSubpages
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Definition: SpecialRenameuser.php:412
Xml\closeElement
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:118
$dbr
if(! $regexes) $dbr
Definition: cleanup.php:94
$wgCapitalLinks
$wgCapitalLinks
Set this to false to avoid forcing the first letter of links to capitals.
Definition: DefaultSettings.php:4050
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
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
NS_USER
const NS_USER
Definition: Defines.php:67
$link
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:2981
SpecialRenameuser\showLogExtract
showLogExtract( $username, $type, &$out)
Definition: SpecialRenameuser.php:397
Xml\input
static input( $name, $size=false, $value=false, $attribs=[])
Convenience function to build an HTML text input field.
Definition: Xml.php:274
SpecialRenameuser\execute
execute( $par)
Show the special page.
Definition: SpecialRenameuser.php:24
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:203
$username
this hook is for auditing only or null if authentication failed before getting that far $username
Definition: hooks.txt:781
User\isCreatableName
static isCreatableName( $name)
Usernames which fail to pass this function will be blocked from new account registrations,...
Definition: User.php:975
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
$wgContLang
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 content language as $wgContLang
Definition: design.txt:56
$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 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:781
$type
$type
Definition: testCompression.php:48