MediaWiki  master
LoginSignupSpecialPage.php
Go to the documentation of this file.
1 <?php
30 
37  protected $mReturnTo;
38  protected $mPosted;
39  protected $mAction;
40  protected $mLanguage;
41  protected $mReturnToQuery;
42  protected $mToken;
43  protected $mStickHTTPS;
44  protected $mFromHTTP;
45  protected $mEntryError = '';
46  protected $mEntryErrorType = 'error';
47 
48  protected $mLoaded = false;
49  protected $mLoadedRequest = false;
50  protected $mSecureLoginUrl;
51 
53  protected $securityLevel;
54 
59  protected $targetUser;
60 
62  protected $authForm;
63 
65  protected $fakeTemplate;
66 
67  abstract protected function isSignup();
68 
75  abstract protected function successfulAction( $direct = false, $extraMessages = null );
76 
82  abstract protected function logAuthResult( $success, $status = null );
83 
84  public function __construct( $name ) {
86  parent::__construct( $name );
87 
88  // Override UseMediaWikiEverywhere to true, to force login and create form to use mw ui
89  $wgUseMediaWikiUIEverywhere = true;
90  }
91 
92  protected function setRequest( array $data, $wasPosted = null ) {
93  parent::setRequest( $data, $wasPosted );
94  $this->mLoadedRequest = false;
95  }
96 
101  private function loadRequestParameters( $subPage ) {
102  if ( $this->mLoadedRequest ) {
103  return;
104  }
105  $this->mLoadedRequest = true;
106  $request = $this->getRequest();
107 
108  $this->mPosted = $request->wasPosted();
109  $this->mIsReturn = $subPage === 'return';
110  $this->mAction = $request->getVal( 'action' );
111  $this->mFromHTTP = $request->getBool( 'fromhttp', false )
112  || $request->getBool( 'wpFromhttp', false );
113  $this->mStickHTTPS = ( !$this->mFromHTTP && $request->getProtocol() === 'https' )
114  || $request->getBool( 'wpForceHttps', false );
115  $this->mLanguage = $request->getText( 'uselang' );
116  $this->mReturnTo = $request->getVal( 'returnto', '' );
117  $this->mReturnToQuery = $request->getVal( 'returntoquery', '' );
118  }
119 
125  protected function load( $subPage ) {
127 
129  if ( $this->mLoaded ) {
130  return;
131  }
132  $this->mLoaded = true;
133  $request = $this->getRequest();
134 
135  $securityLevel = $this->getRequest()->getText( 'force' );
136  if (
137  $securityLevel && AuthManager::singleton()->securitySensitiveOperationStatus(
138  $securityLevel ) === AuthManager::SEC_REAUTH
139  ) {
140  $this->securityLevel = $securityLevel;
141  }
142 
143  $this->loadAuth( $subPage );
144 
145  $this->mToken = $request->getVal( $this->getTokenName() );
146 
147  // Show an error or warning passed on from a previous page
148  $entryError = $this->msg( $request->getVal( 'error', '' ) );
149  $entryWarning = $this->msg( $request->getVal( 'warning', '' ) );
150  // bc: provide login link as a parameter for messages where the translation
151  // was not updated
152  $loginreqlink = Linker::linkKnown(
153  $this->getPageTitle(),
154  $this->msg( 'loginreqlink' )->escaped(),
155  [],
156  [
157  'returnto' => $this->mReturnTo,
158  'returntoquery' => $this->mReturnToQuery,
159  'uselang' => $this->mLanguage,
160  'fromhttp' => $wgSecureLogin && $this->mFromHTTP ? '1' : null,
161  ]
162  );
163 
164  // Only show valid error or warning messages.
165  if ( $entryError->exists()
166  && in_array( $entryError->getKey(), LoginHelper::getValidErrorMessages(), true )
167  ) {
168  $this->mEntryErrorType = 'error';
169  $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
170 
171  } elseif ( $entryWarning->exists()
172  && in_array( $entryWarning->getKey(), LoginHelper::getValidErrorMessages(), true )
173  ) {
174  $this->mEntryErrorType = 'warning';
175  $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
176  }
177 
178  # 1. When switching accounts, it sucks to get automatically logged out
179  # 2. Do not return to PasswordReset after a successful password change
180  # but goto Wiki start page (Main_Page) instead ( bug 33997 )
181  $returnToTitle = Title::newFromText( $this->mReturnTo );
182  if ( is_object( $returnToTitle )
183  && ( $returnToTitle->isSpecial( 'Userlogout' )
184  || $returnToTitle->isSpecial( 'PasswordReset' ) )
185  ) {
186  $this->mReturnTo = '';
187  $this->mReturnToQuery = '';
188  }
189  }
190 
191  protected function getPreservedParams( $withToken = false ) {
193 
194  $params = parent::getPreservedParams( $withToken );
195  $params += [
196  'returnto' => $this->mReturnTo ?: null,
197  'returntoquery' => $this->mReturnToQuery ?: null,
198  ];
199  if ( $wgSecureLogin && !$this->isSignup() ) {
200  $params['fromhttp'] = $this->mFromHTTP ? '1' : null;
201  }
202  return $params;
203  }
204 
205  protected function beforeExecute( $subPage ) {
206  // finish initializing the class before processing the request - T135924
208  return parent::beforeExecute( $subPage );
209  }
210 
214  public function execute( $subPage ) {
215  $authManager = AuthManager::singleton();
216  $session = SessionManager::getGlobalSession();
217 
218  // Session data is used for various things in the authentication process, so we must make
219  // sure a session cookie or some equivalent mechanism is set.
220  $session->persist();
221 
222  $this->load( $subPage );
223  $this->setHeaders();
224  $this->checkPermissions();
225 
226  // Make sure it's possible to log in
227  if ( !$this->isSignup() && !$session->canSetUser() ) {
228  throw new ErrorPageError( 'cannotloginnow-title', 'cannotloginnow-text', [
229  $session->getProvider()->describe( RequestContext::getMain()->getLanguage() )
230  ] );
231  }
232 
233  /*
234  * In the case where the user is already logged in, and was redirected to
235  * the login form from a page that requires login, do not show the login
236  * page. The use case scenario for this is when a user opens a large number
237  * of tabs, is redirected to the login page on all of them, and then logs
238  * in on one, expecting all the others to work properly.
239  *
240  * However, do show the form if it was visited intentionally (no 'returnto'
241  * is present). People who often switch between several accounts have grown
242  * accustomed to this behavior.
243  *
244  * Also make an exception when force=<level> is set in the URL, which means the user must
245  * reauthenticate for security reasons.
246  */
247  if ( !$this->isSignup() && !$this->mPosted && !$this->securityLevel &&
248  ( $this->mReturnTo !== '' || $this->mReturnToQuery !== '' ) &&
249  $this->getUser()->isLoggedIn()
250  ) {
251  $this->successfulAction();
252  }
253 
254  // If logging in and not on HTTPS, either redirect to it or offer a link.
256  if ( $this->getRequest()->getProtocol() !== 'https' ) {
257  $title = $this->getFullTitle();
258  $query = $this->getPreservedParams( false ) + [
259  'title' => null,
260  ( $this->mEntryErrorType === 'error' ? 'error'
261  : 'warning' ) => $this->mEntryError,
262  ] + $this->getRequest()->getQueryValues();
263  $url = $title->getFullURL( $query, false, PROTO_HTTPS );
264  if ( $wgSecureLogin && !$this->mFromHTTP &&
265  wfCanIPUseHTTPS( $this->getRequest()->getIP() )
266  ) {
267  // Avoid infinite redirect
268  $url = wfAppendQuery( $url, 'fromhttp=1' );
269  $this->getOutput()->redirect( $url );
270  // Since we only do this redir to change proto, always vary
271  $this->getOutput()->addVaryHeader( 'X-Forwarded-Proto' );
272 
273  return;
274  } else {
275  // A wiki without HTTPS login support should set $wgServer to
276  // http://somehost, in which case the secure URL generated
277  // above won't actually start with https://
278  if ( substr( $url, 0, 8 ) === 'https://' ) {
279  $this->mSecureLoginUrl = $url;
280  }
281  }
282  }
283 
284  if ( !$this->isActionAllowed( $this->authAction ) ) {
285  // FIXME how do we explain this to the user? can we handle session loss better?
286  // messages used: authpage-cannot-login, authpage-cannot-login-continue,
287  // authpage-cannot-create, authpage-cannot-create-continue
288  $this->mainLoginForm( [], 'authpage-cannot-' . $this->authAction );
289  return;
290  }
291 
292  $status = $this->trySubmit();
293 
294  if ( !$status || !$status->isGood() ) {
295  $this->mainLoginForm( $this->authRequests, $status ? $status->getMessage() : '', 'error' );
296  return;
297  }
298 
300  $response = $status->getValue();
301 
302  $returnToUrl = $this->getPageTitle( 'return' )
303  ->getFullURL( $this->getPreservedParams( true ), false, PROTO_HTTPS );
304  switch ( $response->status ) {
305  case AuthenticationResponse::PASS:
306  $this->logAuthResult( true );
307  $this->proxyAccountCreation = $this->isSignup() && !$this->getUser()->isAnon();
308  $this->targetUser = User::newFromName( $response->username );
309 
310  if (
311  !$this->proxyAccountCreation
312  && $response->loginRequest
313  && $authManager->canAuthenticateNow()
314  ) {
315  // successful registration; log the user in instantly
316  $response2 = $authManager->beginAuthentication( [ $response->loginRequest ],
317  $returnToUrl );
318  if ( $response2->status !== AuthenticationResponse::PASS ) {
319  LoggerFactory::getInstance( 'login' )
320  ->error( 'Could not log in after account creation' );
321  $this->successfulAction( true, Status::newFatal( 'createacct-loginerror' ) );
322  break;
323  }
324  }
325 
326  if ( !$this->proxyAccountCreation ) {
327  // Ensure that the context user is the same as the session user.
329  }
330 
331  $this->successfulAction( true );
332  break;
333  case AuthenticationResponse::FAIL:
334  // fall through
335  case AuthenticationResponse::RESTART:
336  unset( $this->authForm );
337  if ( $response->status === AuthenticationResponse::FAIL ) {
338  $action = $this->getDefaultAction( $subPage );
339  $messageType = 'error';
340  } else {
341  $action = $this->getContinueAction( $this->authAction );
342  $messageType = 'warning';
343  }
344  $this->logAuthResult( false, $response->message ? $response->message->getKey() : '-' );
345  $this->loadAuth( $subPage, $action, true );
346  $this->mainLoginForm( $this->authRequests, $response->message, $messageType );
347  break;
348  case AuthenticationResponse::REDIRECT:
349  unset( $this->authForm );
350  $this->getOutput()->redirect( $response->redirectTarget );
351  break;
352  case AuthenticationResponse::UI:
353  unset( $this->authForm );
354  $this->authAction = $this->isSignup() ? AuthManager::ACTION_CREATE_CONTINUE
355  : AuthManager::ACTION_LOGIN_CONTINUE;
356  $this->authRequests = $response->neededRequests;
357  $this->mainLoginForm( $response->neededRequests, $response->message, 'warning' );
358  break;
359  default:
360  throw new LogicException( 'invalid AuthenticationResponse' );
361  }
362  }
363 
373  protected function showSuccessPage(
374  $type, $title, $msgname, $injected_html, $extraMessages
375  ) {
376  $out = $this->getOutput();
377  $out->setPageTitle( $title );
378  if ( $msgname ) {
379  $out->addWikiMsg( $msgname, wfEscapeWikiText( $this->getUser()->getName() ) );
380  }
381  if ( $extraMessages ) {
382  $extraMessages = Status::wrap( $extraMessages );
383  $out->addWikiText( $extraMessages->getWikiText() );
384  }
385 
386  $out->addHTML( $injected_html );
387 
388  $helper = new LoginHelper( $this->getContext() );
389  $helper->showReturnToPage( $type, $this->mReturnTo, $this->mReturnToQuery, $this->mStickHTTPS );
390  }
391 
407  public function showReturnToPage(
408  $type, $returnTo = '', $returnToQuery = '', $stickHTTPS = false
409  ) {
410  $helper = new LoginHelper( $this->getContext() );
411  $helper->showReturnToPage( $type, $returnTo, $returnToQuery, $stickHTTPS );
412  }
413 
419  protected function setSessionUserForCurrentRequest() {
421 
423  $localContext = $this->getContext();
424  if ( $context !== $localContext ) {
425  // remove AuthManagerSpecialPage context hack
426  $this->setContext( $context );
427  }
428 
429  $user = $context->getRequest()->getSession()->getUser();
430 
431  $wgUser = $user;
432  $context->setUser( $user );
433 
434  $code = $this->getRequest()->getVal( 'uselang', $user->getOption( 'language' ) );
435  $userLang = Language::factory( $code );
436  $wgLang = $userLang;
437  $context->setLanguage( $userLang );
438  }
439 
454  protected function mainLoginForm( array $requests, $msg = '', $msgtype = 'error' ) {
455  $titleObj = $this->getPageTitle();
456  $user = $this->getUser();
457  $out = $this->getOutput();
458 
459  // FIXME how to handle empty $requests - restart, or no form, just an error message?
460  // no form would be better for no session type errors, restart is better when can* fails.
461  if ( !$requests ) {
462  $this->authAction = $this->getDefaultAction( $this->subPage );
463  $this->authForm = null;
464  $requests = AuthManager::singleton()->getAuthenticationRequests( $this->authAction, $user );
465  }
466 
467  // Generic styles and scripts for both login and signup form
468  $out->addModuleStyles( [
469  'mediawiki.ui',
470  'mediawiki.ui.button',
471  'mediawiki.ui.checkbox',
472  'mediawiki.ui.input',
473  'mediawiki.special.userlogin.common.styles'
474  ] );
475  if ( $this->isSignup() ) {
476  // XXX hack pending RL or JS parse() support for complex content messages T27349
477  $out->addJsConfigVars( 'wgCreateacctImgcaptchaHelp',
478  $this->msg( 'createacct-imgcaptcha-help' )->parse() );
479 
480  // Additional styles and scripts for signup form
481  $out->addModules( [
482  'mediawiki.special.userlogin.signup.js'
483  ] );
484  $out->addModuleStyles( [
485  'mediawiki.special.userlogin.signup.styles'
486  ] );
487  } else {
488  // Additional styles for login form
489  $out->addModuleStyles( [
490  'mediawiki.special.userlogin.login.styles'
491  ] );
492  }
493  $out->disallowUserJs(); // just in case...
494 
495  $form = $this->getAuthForm( $requests, $this->authAction, $msg, $msgtype );
496  $form->prepareForm();
497  $formHtml = $form->getHTML( $msg ? Status::newFatal( $msg ) : false );
498 
499  $out->addHTML( $this->getPageHtml( $formHtml ) );
500  }
501 
508  protected function getPageHtml( $formHtml ) {
510 
511  $loginPrompt = $this->isSignup() ? '' : Html::rawElement( 'div',
512  [ 'id' => 'userloginprompt' ], $this->msg( 'loginprompt' )->parseAsBlock() );
513  $languageLinks = $wgLoginLanguageSelector ? $this->makeLanguageSelector() : '';
514  $signupStartMsg = $this->msg( 'signupstart' );
515  $signupStart = ( $this->isSignup() && !$signupStartMsg->isDisabled() )
516  ? Html::rawElement( 'div', [ 'id' => 'signupstart' ], $signupStartMsg->parseAsBlock() ) : '';
517  if ( $languageLinks ) {
518  $languageLinks = Html::rawElement( 'div', [ 'id' => 'languagelinks' ],
519  Html::rawElement( 'p', [], $languageLinks )
520  );
521  }
522 
523  $benefitsContainer = '';
524  if ( $this->isSignup() && $this->showExtraInformation() ) {
525  // messages used:
526  // createacct-benefit-icon1 createacct-benefit-head1 createacct-benefit-body1
527  // createacct-benefit-icon2 createacct-benefit-head2 createacct-benefit-body2
528  // createacct-benefit-icon3 createacct-benefit-head3 createacct-benefit-body3
529  $benefitCount = 3;
530  $benefitList = '';
531  for ( $benefitIdx = 1; $benefitIdx <= $benefitCount; $benefitIdx++ ) {
532  $headUnescaped = $this->msg( "createacct-benefit-head$benefitIdx" )->text();
533  $iconClass = $this->msg( "createacct-benefit-icon$benefitIdx" )->escaped();
534  $benefitList .= Html::rawElement( 'div', [ 'class' => "mw-number-text $iconClass" ],
535  Html::rawElement( 'h3', [],
536  $this->msg( "createacct-benefit-head$benefitIdx" )->escaped()
537  )
538  . Html::rawElement( 'p', [],
539  $this->msg( "createacct-benefit-body$benefitIdx" )->params( $headUnescaped )->escaped()
540  )
541  );
542  }
543  $benefitsContainer = Html::rawElement( 'div', [ 'class' => 'mw-createacct-benefits-container' ],
544  Html::rawElement( 'h2', [], $this->msg( 'createacct-benefit-heading' )->escaped() )
545  . Html::rawElement( 'div', [ 'class' => 'mw-createacct-benefits-list' ],
546  $benefitList
547  )
548  );
549  }
550 
551  $html = Html::rawElement( 'div', [ 'class' => 'mw-ui-container' ],
552  $loginPrompt
553  . $languageLinks
554  . $signupStart
555  . Html::rawElement( 'div', [ 'id' => 'userloginForm' ],
556  $formHtml
557  )
558  . $benefitsContainer
559  );
560 
561  return $html;
562  }
563 
572  protected function getAuthForm( array $requests, $action, $msg = '', $msgType = 'error' ) {
574  // FIXME merge this with parent
575 
576  if ( isset( $this->authForm ) ) {
577  return $this->authForm;
578  }
579 
580  $usingHTTPS = $this->getRequest()->getProtocol() === 'https';
581 
582  // get basic form description from the auth logic
583  $fieldInfo = AuthenticationRequest::mergeFieldInfo( $requests );
584  $fakeTemplate = $this->getFakeTemplate( $msg, $msgType );
585  $this->fakeTemplate = $fakeTemplate; // FIXME there should be a saner way to pass this to the hook
586  // this will call onAuthChangeFormFields()
587  $formDescriptor = static::fieldInfoToFormDescriptor( $requests, $fieldInfo, $this->authAction );
588  $this->postProcessFormDescriptor( $formDescriptor );
589 
590  $context = $this->getContext();
591  if ( $context->getRequest() !== $this->getRequest() ) {
592  // We have overridden the request, need to make sure the form uses that too.
593  $context = new DerivativeContext( $this->getContext() );
594  $context->setRequest( $this->getRequest() );
595  }
596  $form = HTMLForm::factory( 'vform', $formDescriptor, $context );
597 
598  $form->addHiddenField( 'authAction', $this->authAction );
599  if ( $wgLoginLanguageSelector ) {
600  $form->addHiddenField( 'uselang', $this->mLanguage );
601  }
602  $form->addHiddenField( 'force', $this->securityLevel );
603  $form->addHiddenField( $this->getTokenName(), $this->getToken()->toString() );
604  if ( $wgSecureLogin ) {
605  // If using HTTPS coming from HTTP, then the 'fromhttp' parameter must be preserved
606  if ( !$this->isSignup() ) {
607  $form->addHiddenField( 'wpForceHttps', (int)$this->mStickHTTPS );
608  $form->addHiddenField( 'wpFromhttp', $usingHTTPS );
609  }
610  }
611 
612  // set properties of the form itself
613  $form->setAction( $this->getPageTitle()->getLocalURL( $this->getReturnToQueryStringFragment() ) );
614  $form->setName( 'userlogin' . ( $this->isSignup() ? '2' : '' ) );
615  if ( $this->isSignup() ) {
616  $form->setId( 'userlogin2' );
617  }
618 
619  // add pre/post text
620  // header used by ConfirmEdit, CondfirmAccount, Persona, WikimediaIncubator, SemanticSignup
621  // should be above the error message but HTMLForm doesn't support that
622  $form->addHeaderText( $fakeTemplate->get( 'header' ) );
623 
624  // FIXME the old form used this for error/warning messages which does not play well with
625  // HTMLForm (maybe it could with a subclass?); for now only display it for signups
626  // (where the JS username validation needs it) and alway empty
627  if ( $this->isSignup() ) {
628  // used by the mediawiki.special.userlogin.signup.js module
629  $statusAreaAttribs = [ 'id' => 'mw-createacct-status-area' ];
630  // $statusAreaAttribs += $msg ? [ 'class' => "{$msgType}box" ] : [ 'style' => 'display: none;' ];
631  $form->addHeaderText( Html::element( 'div', $statusAreaAttribs ) );
632  }
633 
634  // header used by MobileFrontend
635  $form->addHeaderText( $fakeTemplate->get( 'formheader' ) );
636 
637  // blank signup footer for site customization
638  if ( $this->isSignup() && $this->showExtraInformation() ) {
639  // Use signupend-https for HTTPS requests if it's not blank, signupend otherwise
640  $signupendMsg = $this->msg( 'signupend' );
641  $signupendHttpsMsg = $this->msg( 'signupend-https' );
642  if ( !$signupendMsg->isDisabled() ) {
643  $signupendText = ( $usingHTTPS && !$signupendHttpsMsg->isBlank() )
644  ? $signupendHttpsMsg ->parse() : $signupendMsg->parse();
645  $form->addPostText( Html::rawElement( 'div', [ 'id' => 'signupend' ], $signupendText ) );
646  }
647  }
648 
649  // warning header for non-standard workflows (e.g. security reauthentication)
650  if ( !$this->isSignup() && $this->getUser()->isLoggedIn() ) {
651  $reauthMessage = $this->securityLevel ? 'userlogin-reauth' : 'userlogin-loggedin';
652  $form->addHeaderText( Html::rawElement( 'div', [ 'class' => 'warningbox' ],
653  $this->msg( $reauthMessage )->params( $this->getUser()->getName() )->parse() ) );
654  }
655 
656  if ( !$this->isSignup() && $this->showExtraInformation() ) {
657  $passwordReset = new PasswordReset( $this->getConfig(), AuthManager::singleton() );
658  if ( $passwordReset->isAllowed( $this->getUser() ) ) {
659  $form->addFooterText( Html::rawElement(
660  'div',
661  [ 'class' => 'mw-ui-vform-field mw-form-related-link-container' ],
662  Linker::link(
663  SpecialPage::getTitleFor( 'PasswordReset' ),
664  $this->msg( 'userlogin-resetpassword-link' )->escaped()
665  )
666  ) );
667  }
668 
669  // Don't show a "create account" link if the user can't.
670  if ( $this->showCreateAccountLink() ) {
671  // link to the other action
672  $linkTitle = $this->getTitleFor( $this->isSignup() ? 'Userlogin' :'CreateAccount' );
673  $linkq = $this->getReturnToQueryStringFragment();
674  // Pass any language selection on to the mode switch link
675  if ( $wgLoginLanguageSelector && $this->mLanguage ) {
676  $linkq .= '&uselang=' . $this->mLanguage;
677  }
678 
679  $loggedIn = $this->getUser()->isLoggedIn();
680  $createOrLoginHtml = Html::rawElement( 'div',
681  [ 'id' => 'mw-createaccount' . ( !$loggedIn ? '-cta' : '' ),
682  'class' => ( $loggedIn ? 'mw-form-related-link-container' : 'mw-ui-vform-field' ) ],
683  ( $loggedIn ? '' : $this->msg( 'userlogin-noaccount' )->escaped() )
684  . Html::element( 'a',
685  [
686  'id' => 'mw-createaccount-join' . ( $loggedIn ? '-loggedin' : '' ),
687  'href' => $linkTitle->getLocalURL( $linkq ),
688  'class' => ( $loggedIn ? '' : 'mw-ui-button' ),
689  'tabindex' => 100,
690  ],
691  $this->msg(
692  ( $this->getUser()->isLoggedIn() ?
693  'userlogin-createanother' :
694  'userlogin-joinproject'
695  ) )->escaped()
696  )
697  );
698  $form->addFooterText( $createOrLoginHtml );
699  }
700  }
701 
702  $form->suppressDefaultSubmit();
703 
704  $this->authForm = $form;
705 
706  return $form;
707  }
708 
715  protected function getFakeTemplate( $msg, $msgType ) {
718 
719  // make a best effort to get the value of fields which used to be fixed in the old login
720  // template but now might or might not exist depending on what providers are used
721  $request = $this->getRequest();
722  $data = (object) [
723  'mUsername' => $request->getText( 'wpName' ),
724  'mPassword' => $request->getText( 'wpPassword' ),
725  'mRetype' => $request->getText( 'wpRetype' ),
726  'mEmail' => $request->getText( 'wpEmail' ),
727  'mRealName' => $request->getText( 'wpRealName' ),
728  'mDomain' => $request->getText( 'wpDomain' ),
729  'mReason' => $request->getText( 'wpReason' ),
730  'mRemember' => $request->getCheck( 'wpRemember' ),
731  ];
732 
733  // Preserves a bunch of logic from the old code that was rewritten in getAuthForm().
734  // There is no code reuse to make this easier to remove .
735  // If an extension tries to change any of these values, they are out of luck - we only
736  // actually use the domain/usedomain/domainnames, extraInput and extrafields keys.
737 
738  $titleObj = $this->getPageTitle();
739  $user = $this->getUser();
740  $template = new FakeAuthTemplate();
741 
742  // Pre-fill username (if not creating an account, bug 44775).
743  if ( $data->mUsername == '' && $this->isSignup() ) {
744  if ( $user->isLoggedIn() ) {
745  $data->mUsername = $user->getName();
746  } else {
747  $data->mUsername = $this->getRequest()->getSession()->suggestLoginUsername();
748  }
749  }
750 
751  if ( $this->isSignup() ) {
752  // Must match number of benefits defined in messages
753  $template->set( 'benefitCount', 3 );
754 
755  $q = 'action=submitlogin&type=signup';
756  $linkq = 'type=login';
757  } else {
758  $q = 'action=submitlogin&type=login';
759  $linkq = 'type=signup';
760  }
761 
762  if ( $this->mReturnTo !== '' ) {
763  $returnto = '&returnto=' . wfUrlencode( $this->mReturnTo );
764  if ( $this->mReturnToQuery !== '' ) {
765  $returnto .= '&returntoquery=' .
766  wfUrlencode( $this->mReturnToQuery );
767  }
768  $q .= $returnto;
769  $linkq .= $returnto;
770  }
771 
772  # Don't show a "create account" link if the user can't.
773  if ( $this->showCreateAccountLink() ) {
774  # Pass any language selection on to the mode switch link
775  if ( $wgLoginLanguageSelector && $this->mLanguage ) {
776  $linkq .= '&uselang=' . $this->mLanguage;
777  }
778  // Supply URL, login template creates the button.
779  $template->set( 'createOrLoginHref', $titleObj->getLocalURL( $linkq ) );
780  } else {
781  $template->set( 'link', '' );
782  }
783 
784  $resetLink = $this->isSignup()
785  ? null
786  : is_array( $wgPasswordResetRoutes )
787  && in_array( true, array_values( $wgPasswordResetRoutes ), true );
788 
789  $template->set( 'header', '' );
790  $template->set( 'formheader', '' );
791  $template->set( 'skin', $this->getSkin() );
792 
793  $template->set( 'name', $data->mUsername );
794  $template->set( 'password', $data->mPassword );
795  $template->set( 'retype', $data->mRetype );
796  $template->set( 'createemailset', false ); // no easy way to get that from AuthManager
797  $template->set( 'email', $data->mEmail );
798  $template->set( 'realname', $data->mRealName );
799  $template->set( 'domain', $data->mDomain );
800  $template->set( 'reason', $data->mReason );
801  $template->set( 'remember', $data->mRemember );
802 
803  $template->set( 'action', $titleObj->getLocalURL( $q ) );
804  $template->set( 'message', $msg );
805  $template->set( 'messagetype', $msgType );
806  $template->set( 'createemail', $wgEnableEmail && $user->isLoggedIn() );
807  $template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs, true ) );
808  $template->set( 'useemail', $wgEnableEmail );
809  $template->set( 'emailrequired', $wgEmailConfirmToEdit );
810  $template->set( 'emailothers', $wgEnableUserEmail );
811  $template->set( 'canreset', $wgAuth->allowPasswordChange() );
812  $template->set( 'resetlink', $resetLink );
813  $template->set( 'canremember', $request->getSession()->getProvider()
814  ->getRememberUserDuration() !== null );
815  $template->set( 'usereason', $user->isLoggedIn() );
816  $template->set( 'cansecurelogin', ( $wgSecureLogin ) );
817  $template->set( 'stickhttps', (int)$this->mStickHTTPS );
818  $template->set( 'loggedin', $user->isLoggedIn() );
819  $template->set( 'loggedinuser', $user->getName() );
820  $template->set( 'token', $this->getToken()->toString() );
821 
822  $action = $this->isSignup() ? 'signup' : 'login';
823  $wgAuth->modifyUITemplate( $template, $action );
824 
825  $oldTemplate = $template;
826  $hookName = $this->isSignup() ? 'UserCreateForm' : 'UserLoginForm';
827  Hooks::run( $hookName, [ &$template ] );
828  if ( $oldTemplate !== $template ) {
829  wfDeprecated( "reference in $hookName hook", '1.27' );
830  }
831 
832  return $template;
833 
834  }
835 
836  public function onAuthChangeFormFields(
837  array $requests, array $fieldInfo, array &$formDescriptor, $action
838  ) {
839  $coreFieldDescriptors = $this->getFieldDefinitions( $this->fakeTemplate );
840  $specialFields = array_merge( [ 'extraInput', 'linkcontainer', 'entryError' ],
841  array_keys( $this->fakeTemplate->getExtraInputDefinitions() ) );
842 
843  // keep the ordering from getCoreFieldDescriptors() where there is no explicit weight
844  foreach ( $coreFieldDescriptors as $fieldName => $coreField ) {
845  $requestField = isset( $formDescriptor[$fieldName] ) ?
846  $formDescriptor[$fieldName] : [];
847 
848  // remove everything that is not in the fieldinfo, is not marked as a supplemental field
849  // to something in the fieldinfo, and is not a generic or B/C field or a submit button
850  if (
851  !isset( $fieldInfo[$fieldName] )
852  && (
853  !isset( $coreField['baseField'] )
854  || !isset( $fieldInfo[$coreField['baseField']] )
855  ) && !in_array( $fieldName, $specialFields, true )
856  && ( !isset( $coreField['type'] ) || $coreField['type'] !== 'submit' )
857  ) {
858  $coreFieldDescriptors[$fieldName] = null;
859  continue;
860  }
861 
862  // core message labels should always take priority
863  if (
864  isset( $coreField['label'] )
865  || isset( $coreField['label-message'] )
866  || isset( $coreField['label-raw'] )
867  ) {
868  unset( $requestField['label'], $requestField['label-message'], $coreField['label-raw'] );
869  }
870 
871  $coreFieldDescriptors[$fieldName] += $requestField;
872  }
873 
874  $formDescriptor = array_filter( $coreFieldDescriptors + $formDescriptor );
875  return true;
876  }
877 
884  protected function showExtraInformation() {
885  return $this->authAction !== $this->getContinueAction( $this->authAction )
887  }
888 
894  protected function getFieldDefinitions( $template ) {
896 
897  $isLoggedIn = $this->getUser()->isLoggedIn();
898  $continuePart = $this->isContinued() ? 'continue-' : '';
899  $anotherPart = $isLoggedIn ? 'another-' : '';
900  $expiration = $this->getRequest()->getSession()->getProvider()
901  ->getRememberUserDuration();
902  $expirationDays = ceil( $expiration / ( 3600 * 24 ) );
903  $secureLoginLink = '';
904  if ( $this->mSecureLoginUrl ) {
905  $secureLoginLink = Html::element( 'a', [
906  'href' => $this->mSecureLoginUrl,
907  'class' => 'mw-ui-flush-right mw-secure',
908  ], $this->msg( 'userlogin-signwithsecure' )->text() );
909  }
910 
911  if ( $this->isSignup() ) {
912  $fieldDefinitions = [
913  'username' => [
914  'label-message' => 'userlogin-yourname',
915  // FIXME help-message does not match old formatting
916  'help-message' => 'createacct-helpusername',
917  'id' => 'wpName2',
918  'placeholder-message' => $isLoggedIn ? 'createacct-another-username-ph'
919  : 'userlogin-yourname-ph',
920  ],
921  'mailpassword' => [
922  // create account without providing password, a temporary one will be mailed
923  'type' => 'check',
924  'label-message' => 'createaccountmail',
925  'name' => 'wpCreateaccountMail',
926  'id' => 'wpCreateaccountMail',
927  ],
928  'password' => [
929  'id' => 'wpPassword2',
930  'placeholder-message' => 'createacct-yourpassword-ph',
931  'hide-if' => [ '===', 'wpCreateaccountMail', '1' ],
932  ],
933  'domain' => [],
934  'retype' => [
935  'baseField' => 'password',
936  'type' => 'password',
937  'label-message' => 'createacct-yourpasswordagain',
938  'id' => 'wpRetype',
939  'cssclass' => 'loginPassword',
940  'size' => 20,
941  'validation-callback' => function ( $value, $alldata ) {
942  if ( empty( $alldata['mailpassword'] ) && !empty( $alldata['password'] ) ) {
943  if ( !$value ) {
944  return $this->msg( 'htmlform-required' );
945  } elseif ( $value !== $alldata['password'] ) {
946  return $this->msg( 'badretype' );
947  }
948  }
949  return true;
950  },
951  'hide-if' => [ '===', 'wpCreateaccountMail', '1' ],
952  'placeholder-message' => 'createacct-yourpasswordagain-ph',
953  ],
954  'email' => [
955  'type' => 'email',
956  'label-message' => $wgEmailConfirmToEdit ? 'createacct-emailrequired'
957  : 'createacct-emailoptional',
958  'id' => 'wpEmail',
959  'cssclass' => 'loginText',
960  'size' => '20',
961  // FIXME will break non-standard providers
962  'required' => $wgEmailConfirmToEdit,
963  'validation-callback' => function ( $value, $alldata ) {
965 
966  // AuthManager will check most of these, but that will make the auth
967  // session fail and this won't, so nicer to do it this way
968  if ( !$value && $wgEmailConfirmToEdit ) {
969  // no point in allowing registration without email when email is
970  // required to edit
971  return $this->msg( 'noemailtitle' );
972  } elseif ( !$value && !empty( $alldata['mailpassword'] ) ) {
973  // cannot send password via email when there is no email address
974  return $this->msg( 'noemailcreate' );
975  } elseif ( $value && !Sanitizer::validateEmail( $value ) ) {
976  return $this->msg( 'invalidemailaddress' );
977  }
978  return true;
979  },
980  'placeholder-message' => 'createacct-' . $anotherPart . 'email-ph',
981  ],
982  'realname' => [
983  'type' => 'text',
984  'help-message' => $isLoggedIn ? 'createacct-another-realname-tip'
985  : 'prefs-help-realname',
986  'label-message' => 'createacct-realname',
987  'cssclass' => 'loginText',
988  'size' => 20,
989  'id' => 'wpRealName',
990  ],
991  'reason' => [
992  // comment for the user creation log
993  'type' => 'text',
994  'label-message' => 'createacct-reason',
995  'cssclass' => 'loginText',
996  'id' => 'wpReason',
997  'size' => '20',
998  'placeholder-message' => 'createacct-reason-ph',
999  ],
1000  'extrainput' => [], // placeholder for fields coming from the template
1001  'createaccount' => [
1002  // submit button
1003  'type' => 'submit',
1004  'default' => $this->msg( 'createacct-' . $anotherPart . $continuePart .
1005  'submit' )->text(),
1006  'name' => 'wpCreateaccount',
1007  'id' => 'wpCreateaccount',
1008  'weight' => 100,
1009  ],
1010  ];
1011  } else {
1012  $fieldDefinitions = [
1013  'username' => [
1014  'label-raw' => $this->msg( 'userlogin-yourname' )->escaped() . $secureLoginLink,
1015  'id' => 'wpName1',
1016  'placeholder-message' => 'userlogin-yourname-ph',
1017  ],
1018  'password' => [
1019  'id' => 'wpPassword1',
1020  'placeholder-message' => 'userlogin-yourpassword-ph',
1021  ],
1022  'domain' => [],
1023  'extrainput' => [],
1024  'rememberMe' => [
1025  // option for saving the user token to a cookie
1026  'type' => 'check',
1027  'name' => 'wpRemember',
1028  'label-message' => $this->msg( 'userlogin-remembermypassword' )
1029  ->numParams( $expirationDays ),
1030  'id' => 'wpRemember',
1031  ],
1032  'loginattempt' => [
1033  // submit button
1034  'type' => 'submit',
1035  'default' => $this->msg( 'pt-login-' . $continuePart . 'button' )->text(),
1036  'id' => 'wpLoginAttempt',
1037  'weight' => 100,
1038  ],
1039  'linkcontainer' => [
1040  // help link
1041  'type' => 'info',
1042  'cssclass' => 'mw-form-related-link-container mw-userlogin-help',
1043  // 'id' => 'mw-userlogin-help', // FIXME HTMLInfoField ignores this
1044  'raw' => true,
1045  'default' => Html::element( 'a', [
1046  'href' => Skin::makeInternalOrExternalUrl( wfMessage( 'helplogin-url' )
1047  ->inContentLanguage()
1048  ->text() ),
1049  ], $this->msg( 'userlogin-helplink2' )->text() ),
1050  'weight' => 200,
1051  ],
1052  // button for ResetPasswordSecondaryAuthenticationProvider
1053  'skipReset' => [
1054  'weight' => 110,
1055  'flags' => [],
1056  ],
1057  ];
1058  }
1059  $fieldDefinitions['username'] += [
1060  'type' => 'text',
1061  'name' => 'wpName',
1062  'cssclass' => 'loginText',
1063  'size' => 20,
1064  // 'required' => true,
1065  ];
1066  $fieldDefinitions['password'] += [
1067  'type' => 'password',
1068  // 'label-message' => 'userlogin-yourpassword', // would override the changepassword label
1069  'name' => 'wpPassword',
1070  'cssclass' => 'loginPassword',
1071  'size' => 20,
1072  // 'required' => true,
1073  ];
1074 
1075  if ( $this->mEntryError ) {
1076  $fieldDefinitions['entryError'] = [
1077  'type' => 'info',
1078  'default' => Html::rawElement( 'div', [ 'class' => $this->mEntryErrorType . 'box', ],
1079  $this->mEntryError ),
1080  'raw' => true,
1081  'rawrow' => true,
1082  'weight' => -100,
1083  ];
1084  }
1085 
1086  if ( !$this->showExtraInformation() ) {
1087  unset( $fieldDefinitions['linkcontainer'] );
1088  }
1089 
1090  $fieldDefinitions = $this->getBCFieldDefinitions( $fieldDefinitions, $template );
1091  $fieldDefinitions = array_filter( $fieldDefinitions );
1092 
1093  return $fieldDefinitions;
1094  }
1095 
1102  protected function getBCFieldDefinitions( $fieldDefinitions, $template ) {
1103  if ( $template->get( 'usedomain', false ) ) {
1104  // TODO probably should be translated to the new domain notation in AuthManager
1105  $fieldDefinitions['domain'] = [
1106  'type' => 'select',
1107  'label-message' => 'yourdomainname',
1108  'options' => array_combine( $template->get( 'domainnames', [] ),
1109  $template->get( 'domainnames', [] ) ),
1110  'default' => $template->get( 'domain', '' ),
1111  'name' => 'wpDomain',
1112  // FIXME id => 'mw-user-domain-section' on the parent div
1113  ];
1114  }
1115 
1116  // poor man's associative array_splice
1117  $extraInputPos = array_search( 'extrainput', array_keys( $fieldDefinitions ), true );
1118  $fieldDefinitions = array_slice( $fieldDefinitions, 0, $extraInputPos, true )
1119  + $template->getExtraInputDefinitions()
1120  + array_slice( $fieldDefinitions, $extraInputPos + 1, null, true );
1121 
1122  return $fieldDefinitions;
1123  }
1124 
1134  protected function hasSessionCookie() {
1136 
1137  return $wgDisableCookieCheck || (
1138  $wgInitialSessionId &&
1139  $this->getRequest()->getSession()->getId() === (string)$wgInitialSessionId
1140  );
1141  }
1142 
1147  protected function getReturnToQueryStringFragment() {
1148  $returnto = '';
1149  if ( $this->mReturnTo !== '' ) {
1150  $returnto = 'returnto=' . wfUrlencode( $this->mReturnTo );
1151  if ( $this->mReturnToQuery !== '' ) {
1152  $returnto .= '&returntoquery=' . wfUrlencode( $this->mReturnToQuery );
1153  }
1154  }
1155  return $returnto;
1156  }
1157 
1163  private function showCreateAccountLink() {
1164  if ( $this->isSignup() ) {
1165  return true;
1166  } elseif ( $this->getUser()->isAllowed( 'createaccount' ) ) {
1167  return true;
1168  } else {
1169  return false;
1170  }
1171  }
1172 
1173  protected function getTokenName() {
1174  return $this->isSignup() ? 'wpCreateaccountToken' : 'wpLoginToken';
1175  }
1176 
1183  protected function makeLanguageSelector() {
1184  $msg = $this->msg( 'loginlanguagelinks' )->inContentLanguage();
1185  if ( $msg->isBlank() ) {
1186  return '';
1187  }
1188  $langs = explode( "\n", $msg->text() );
1189  $links = [];
1190  foreach ( $langs as $lang ) {
1191  $lang = trim( $lang, '* ' );
1192  $parts = explode( '|', $lang );
1193  if ( count( $parts ) >= 2 ) {
1194  $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
1195  }
1196  }
1197 
1198  return count( $links ) > 0 ? $this->msg( 'loginlanguagelabel' )->rawParams(
1199  $this->getLanguage()->pipeList( $links ) )->escaped() : '';
1200  }
1201 
1210  protected function makeLanguageSelectorLink( $text, $lang ) {
1211  if ( $this->getLanguage()->getCode() == $lang ) {
1212  // no link for currently used language
1213  return htmlspecialchars( $text );
1214  }
1215  $query = [ 'uselang' => $lang ];
1216  if ( $this->mReturnTo !== '' ) {
1217  $query['returnto'] = $this->mReturnTo;
1218  $query['returntoquery'] = $this->mReturnToQuery;
1219  }
1220 
1221  $attr = [];
1222  $targetLanguage = Language::factory( $lang );
1223  $attr['lang'] = $attr['hreflang'] = $targetLanguage->getHtmlCode();
1224 
1225  return Linker::linkKnown(
1226  $this->getPageTitle(),
1227  htmlspecialchars( $text ),
1228  $attr,
1229  $query
1230  );
1231  }
1232 
1233  protected function getGroupName() {
1234  return 'login';
1235  }
1236 
1240  protected function postProcessFormDescriptor( &$formDescriptor ) {
1241  // Pre-fill username (if not creating an account, T46775).
1242  if (
1243  isset( $formDescriptor['username'] ) &&
1244  !isset( $formDescriptor['username']['default'] ) &&
1245  !$this->isSignup()
1246  ) {
1247  $user = $this->getUser();
1248  if ( $user->isLoggedIn() ) {
1249  $formDescriptor['username']['default'] = $user->getName();
1250  } else {
1251  $formDescriptor['username']['default'] =
1252  $this->getRequest()->getSession()->suggestLoginUsername();
1253  }
1254  }
1255 
1256  // don't show a submit button if there is nothing to submit (i.e. the only form content
1257  // is other submit buttons, for redirect flows)
1258  if ( !$this->needsSubmitButton( $formDescriptor ) ) {
1259  unset( $formDescriptor['createaccount'], $formDescriptor['loginattempt'] );
1260  }
1261 
1262  if ( !$this->isSignup() ) {
1263  // FIXME HACK don't focus on non-empty field
1264  // maybe there should be an autofocus-if similar to hide-if?
1265  if (
1266  isset( $formDescriptor['username'] )
1267  && empty( $formDescriptor['username']['default'] )
1268  && !$this->getRequest()->getCheck( 'wpName' )
1269  ) {
1270  $formDescriptor['username']['autofocus'] = true;
1271  } elseif ( isset( $formDescriptor['password'] ) ) {
1272  $formDescriptor['password']['autofocus'] = true;
1273  }
1274  }
1275 
1276  $this->addTabIndex( $formDescriptor );
1277  }
1278 }
1279 
1287  public function execute() {
1288  throw new LogicException( 'not used' );
1289  }
1290 
1295  public function addInputItem( $name, $value, $type, $msg, $helptext = false ) {
1296  // use the same indexes as UserCreateForm just in case someone adds an item manually
1297  $this->data['extrainput'][] = [
1298  'name' => $name,
1299  'value' => $value,
1300  'type' => $type,
1301  'msg' => $msg,
1302  'helptext' => $helptext,
1303  ];
1304  }
1305 
1310  public function getExtraInputDefinitions() {
1311  $definitions = [];
1312 
1313  foreach ( $this->get( 'extrainput', [] ) as $field ) {
1314  $definition = [
1315  'type' => $field['type'] === 'checkbox' ? 'check' : $field['type'],
1316  'name' => $field['name'],
1317  'value' => $field['value'],
1318  'id' => $field['name'],
1319  ];
1320  if ( $field['msg'] ) {
1321  $definition['label-message'] = $this->getMsg( $field['msg'] );
1322  }
1323  if ( $field['helptext'] ) {
1324  $definition['help'] = $this->msgWiki( $field['helptext'] );
1325  }
1326 
1327  // the array key doesn't matter much when name is defined explicitly but
1328  // let's try and follow HTMLForm conventions
1329  $name = preg_replace( '/^wp(?=[A-Z])/', '', $field['name'] );
1330  $definitions[$name] = $definition;
1331  }
1332 
1333  if ( $this->haveData( 'extrafields' ) ) {
1334  $definitions['extrafields'] = [
1335  'type' => 'info',
1336  'raw' => true,
1337  'default' => $this->get( 'extrafields' ),
1338  ];
1339  }
1340 
1341  return $definitions;
1342  }
1343 }
1344 
1350 class LoginForm extends SpecialPage {
1352 
1353  public function __construct( $request = null ) {
1355  if ( $wgDisableAuthManager ) {
1356  $this->realLoginForm = new LoginFormPreAuthManager( $request );
1357  } else {
1358  $this->realLoginForm = new LoginFormAuthManager( $request );
1359  }
1360  }
1361 
1362  // proxy everything
1363 
1364  public function __get( $name ) {
1365  return $this->realLoginForm->$name;
1366  }
1367 
1368  public function __set( $name, $value ) {
1369  $this->realLoginForm->$name = $value;
1370  }
1371 
1372  public function __call( $name, $args ) {
1373  return call_user_func_array( [ $this->realLoginForm, $name ], $args );
1374  }
1375 
1376  public static function __callStatic( $name, $args ) {
1378  return call_user_func_array( [ $wgDisableAuthManager ? LoginFormPreAuthManager::class
1380  }
1381 
1382  // all public SpecialPage methods need to be proxied explicitly
1383 
1384  public function getName() {
1385  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1386  }
1387  public function getRestriction() {
1388  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1389  }
1390  public function isListed() {
1391  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1392  }
1393  public function setListed( $listed ) {
1394  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1395  }
1396  public function listed( $x = null ) {
1397  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1398  }
1399  public function isIncludable() {
1400  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1401  }
1402  public function including( $x = null ) {
1403  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1404  }
1405  public function getLocalName() {
1406  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1407  }
1408  public function isExpensive() {
1409  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1410  }
1411  public function isCached() {
1412  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1413  }
1414  public function isRestricted() {
1415  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1416  }
1417  public function userCanExecute( User $user ) {
1418  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1419  }
1420  public function displayRestrictionError() {
1421  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1422  }
1423  public function checkPermissions() {
1424  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1425  }
1426  public function checkReadOnly() {
1427  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1428  }
1429  public function requireLogin(
1430  $reasonMsg = 'exception-nologin-text', $titleMsg = 'exception-nologin'
1431  ) {
1432  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1433  }
1434  public function prefixSearchSubpages( $search, $limit, $offset ) {
1435  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1436  }
1437  public function execute( $subPage ) {
1438  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1439  }
1440  public function getDescription() {
1441  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1442  }
1443  function getTitle( $subpage = false ) {
1444  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1445  }
1446  function getPageTitle( $subpage = false ) {
1447  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1448  }
1449  public function setContext( $context ) {
1450  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1451  }
1452  public function getContext() {
1453  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1454  }
1455  public function getRequest() {
1456  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1457  }
1458  public function getOutput() {
1459  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1460  }
1461  public function getUser() {
1462  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1463  }
1464  public function getSkin() {
1465  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1466  }
1467  public function getLanguage() {
1468  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1469  }
1470  public function getConfig() {
1471  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1472  }
1473  public function getFullTitle() {
1474  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1475  }
1476  public function getFinalGroupName() {
1477  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1478  }
1479  public function doesWrites() {
1480  return call_user_func_array( [ $this->realLoginForm, __FUNCTION__ ], func_get_args() );
1481  }
1482 
1483  // no way to proxy constants and static properties
1484 
1485  const SUCCESS = 0;
1486  const NO_NAME = 1;
1487  const ILLEGAL = 2;
1489  const NOT_EXISTS = 4;
1490  const WRONG_PASS = 5;
1491  const EMPTY_PASS = 6;
1492  const RESET_PASS = 7;
1493  const ABORTED = 8;
1494  const CREATE_BLOCKED = 9;
1495  const THROTTLED = 10;
1496  const USER_BLOCKED = 11;
1497  const NEED_TOKEN = 12;
1498  const WRONG_TOKEN = 13;
1499  const USER_MIGRATED = 14;
1500 
1501  public static $statusCodes = [
1502  self::SUCCESS => 'success',
1503  self::NO_NAME => 'no_name',
1504  self::ILLEGAL => 'illegal',
1505  self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
1506  self::NOT_EXISTS => 'not_exists',
1507  self::WRONG_PASS => 'wrong_pass',
1508  self::EMPTY_PASS => 'empty_pass',
1509  self::RESET_PASS => 'reset_pass',
1510  self::ABORTED => 'aborted',
1511  self::CREATE_BLOCKED => 'create_blocked',
1512  self::THROTTLED => 'throttled',
1513  self::USER_BLOCKED => 'user_blocked',
1514  self::NEED_TOKEN => 'need_token',
1515  self::WRONG_TOKEN => 'wrong_token',
1516  self::USER_MIGRATED => 'user_migrated',
1517  ];
1518 
1519  public static $validErrorMessages = [
1520  'exception-nologin-text',
1521  'watchlistanontext',
1522  'changeemail-no-info',
1523  'resetpass-no-info',
1524  'confirmemail_needlogin',
1525  'prefsnologintext2',
1526  ];
1527 }
1528 
1535  const SUCCESS = 0;
1536  const NO_NAME = 1;
1537  const ILLEGAL = 2;
1539  const NOT_EXISTS = 4;
1540  const WRONG_PASS = 5;
1541  const EMPTY_PASS = 6;
1542  const RESET_PASS = 7;
1543  const ABORTED = 8;
1544  const CREATE_BLOCKED = 9;
1545  const THROTTLED = 10;
1546  const USER_BLOCKED = 11;
1547  const NEED_TOKEN = 12;
1548  const WRONG_TOKEN = 13;
1549  const USER_MIGRATED = 14;
1550 
1551  public static $statusCodes = [
1552  self::SUCCESS => 'success',
1553  self::NO_NAME => 'no_name',
1554  self::ILLEGAL => 'illegal',
1555  self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
1556  self::NOT_EXISTS => 'not_exists',
1557  self::WRONG_PASS => 'wrong_pass',
1558  self::EMPTY_PASS => 'empty_pass',
1559  self::RESET_PASS => 'reset_pass',
1560  self::ABORTED => 'aborted',
1561  self::CREATE_BLOCKED => 'create_blocked',
1562  self::THROTTLED => 'throttled',
1563  self::USER_BLOCKED => 'user_blocked',
1564  self::NEED_TOKEN => 'need_token',
1565  self::WRONG_TOKEN => 'wrong_token',
1566  self::USER_MIGRATED => 'user_migrated',
1567  ];
1568 
1572  public function __construct( $request = null ) {
1573  wfDeprecated( 'LoginForm', '1.27' );
1574  parent::__construct();
1575  }
1576 
1580  public static function getValidErrorMessages() {
1582  }
1583 
1587  public static function incrementLoginThrottle( $username ) {
1588  wfDeprecated( __METHOD__, "1.27" );
1591  $throttler = new Throttler();
1592  return $throttler->increase( $username, $wgRequest->getIP(), __METHOD__ );
1593  }
1594 
1598  public static function incLoginThrottle( $username ) {
1599  wfDeprecated( __METHOD__, "1.27" );
1600  $res = self::incrementLoginThrottle( $username );
1601  return is_array( $res ) ? true : 0;
1602  }
1603 
1607  public static function clearLoginThrottle( $username ) {
1608  wfDeprecated( __METHOD__, "1.27" );
1611  $throttler = new Throttler();
1612  return $throttler->clear( $username, $wgRequest->getIP() );
1613  }
1614 
1618  public static function getLoginToken() {
1619  wfDeprecated( __METHOD__, '1.27' );
1621  return $wgRequest->getSession()->getToken( '', 'login' )->toString();
1622  }
1623 
1627  public static function setLoginToken() {
1628  wfDeprecated( __METHOD__, '1.27' );
1629  }
1630 
1634  public static function clearLoginToken() {
1635  wfDeprecated( __METHOD__, '1.27' );
1637  $wgRequest->getSession()->resetToken( 'login' );
1638  }
1639 
1643  public static function getCreateaccountToken() {
1644  wfDeprecated( __METHOD__, '1.27' );
1646  return $wgRequest->getSession()->getToken( '', 'createaccount' )->toString();
1647  }
1648 
1652  public static function setCreateaccountToken() {
1653  wfDeprecated( __METHOD__, '1.27' );
1654  }
1655 
1659  public static function clearCreateaccountToken() {
1660  wfDeprecated( __METHOD__, '1.27' );
1662  $wgRequest->getSession()->resetToken( 'createaccount' );
1663  }
1664 }
static newFromName($name, $validate= 'valid')
Static factory method for creation from username.
Definition: User.php:522
$wgInitialSessionId
Definition: Setup.php:737
setSessionUserForCurrentRequest()
Replace some globals to make sure the fact that the user has just been logged in is reflected in the ...
getTitle($subpage=false)
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:1816
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:776
the array() calling protocol came about after MediaWiki 1.4rc1.
getAuthForm(array $requests, $action, $msg= '', $msgType= 'error')
Generates a form from the given request.
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1435
wfCanIPUseHTTPS($ip)
Determine whether the client at a given source IP is likely to be able to access the wiki via HTTPS...
static wrap($sv)
Succinct helper method to wrap a StatusValue.
Definition: Status.php:79
A special page subclass for authentication-related special pages.
$context
Definition: load.php:43
getContext()
Gets the context this SpecialPage is executed in.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string & $returnToQuery
Definition: hooks.txt:2376
$success
makeLanguageSelectorLink($text, $lang)
Create a language selector link for a particular language Links back to this page preserving type and...
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
static getTitleFor($name, $subpage=false, $fragment= '')
Get a localised Title object for a specified special page name.
Definition: SpecialPage.php:80
static getCanonicalName($name, $validate= 'valid')
Given unvalidated user input, return a canonical username, or false if the username is invalid...
Definition: User.php:1082
getFakeTemplate($msg, $msgType)
Temporary B/C method to handle extensions using the UserLoginForm/UserCreateForm hooks.
makeLanguageSelector()
Produce a bar of links which allow the user to select another language during login/registration but ...
needsSubmitButton($formDescriptor)
Returns true if the form has fields which take values.
static rawElement($element, $attribs=[], $contents= '')
Returns an HTML element in a string.
Definition: Html.php:210
userCanExecute(User $user)
if(!isset($args[0])) $lang
An IContextSource implementation which will inherit context from another source but allow individual ...
static factory($displayFormat)
Construct a HTMLForm object for given display type.
Definition: HTMLForm.php:272
hasSessionCookie()
Check if a session cookie is present.
requireLogin($reasonMsg= 'exception-nologin-text', $titleMsg= 'exception-nologin')
$wgSecureLogin
This is to let user authenticate using https when they come from http.
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:177
New base template for a skin's template extended from QuickTemplate this class features helper method...
$value
and how to run hooks for an and one after Each event has a preferably in CamelCase For ArticleDelete hook A clump of code and data that should be run when an event happens This can be either a function and a chunk of data
Definition: hooks.txt:6
getToken()
Returns the CSRF token.
This is a value object to hold authentication response data.
mainLoginForm(array $requests, $msg= '', $msgtype= 'error')
msg()
Wrapper around wfMessage that sets the current context.
$wgEmailConfirmToEdit
Should editors be required to have a validated e-mail address before being allowed to edit...
User $targetUser
FIXME another flag for passing data.
get($name, $default=null)
Gets the template data requested.
getOutput()
Get the OutputPage being used for this instance.
$wgAuth $wgAuth
Authentication plugin.
$wgHiddenPrefs
An array of preferences to not show for the user.
wfUrlencode($s)
We want some things to be included as literal characters in our title URLs for prettiness, which urlencode encodes by default.
static newFromText($text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:256
this hook is for auditing only $response
Definition: hooks.txt:776
when a variable name is used in a it is silently declared as a new local masking the global
Definition: design.txt:93
Holds shared logic for login and account creation pages.
static newFatal($message)
Factory function for fatal errors.
Definition: Status.php:89
globals will be eliminated from MediaWiki replaced by an application object which would be passed to constructors Whether that would be an convenient solution remains to be but certainly PHP makes such object oriented programming models easier than they were in previous versions For the time being MediaWiki programmers will have to work in an environment with some global context At the time of globals were initialised on startup by MediaWiki of these were configuration which are documented in DefaultSettings php There is no comprehensive documentation for the remaining however some of the most important ones are listed below They are typically initialised either in index php or in Setup php For a description of the see design txt $wgTitle Title object created from the request URL $wgOut OutputPage object for HTTP response $wgUser User object for the user associated with the current request $wgLang Language object selected by user preferences $wgContLang Language object associated with the wiki being viewed $wgParser Parser object Parser extensions register their hooks here $wgRequest WebRequest object
Definition: globals.txt:25
showExtraInformation()
Show extra information such as password recovery information, link from login to signup, CTA etc? Such information should only be shown on the "landing page", ie.
$wgEnableEmail
Set to true to enable the e-mail basic features: Password reminders, etc.
$wgPasswordResetRoutes
Whether to allow password resets ("enter some identifying data, and we'll send an email with a tempo...
showSuccessPage($type, $title, $msgname, $injected_html, $extraMessages)
Show the success page.
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 $wgLang
Definition: design.txt:56
if($line===false) $args
Definition: cdb.php:64
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 $template
Definition: hooks.txt:776
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:47
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition: hooks.txt:1816
$wgLoginLanguageSelector
Show a bar of language selection links in the user login and user registration forms; edit the "login...
isActionAllowed($action)
Checks whether AuthManager is ready to perform the action.
Parent class for all special pages.
Definition: SpecialPage.php:36
const PROTO_HTTPS
Definition: Defines.php:263
isContinued()
Returns true if this is not the first step of the authentication.
wfEscapeWikiText($text)
Escapes the given text so that it may be output using addWikiText() without any linking, formatting, etc.
getContinueAction($action)
Gets the _CONTINUE version of an action.
static getMain()
Static methods.
getMsg($name)
Get a Message object with its context set.
logAuthResult($success, $status=null)
Logs to the authmanager-stats channel.
addTabIndex(&$formDescriptor)
Adds a sequential tabindex starting from 1 to all form elements.
getExtraInputDefinitions()
Turns addInputItem-style field definitions into HTMLForm field definitions.
wfAppendQuery($url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
An error page which can definitely be safely rendered using the OutputPage.
loadRequestParameters($subPage)
Load basic request parameters for this Special page.
$wgDisableCookieCheck
By default, MediaWiki checks if the client supports cookies during the login process, so that it can display an informative error message if cookies are disabled.
$res
Definition: database.txt:21
getBCFieldDefinitions($fieldDefinitions, $template)
Adds fields provided via the deprecated UserLoginForm / UserCreateForm hooks.
static incLoginThrottle($username)
B/C class to try handling login/signup template modifications even though login/signup does not actua...
$params
Implements Special:UserLogin.
getSkin()
Shortcut to get the skin being used for this instance.
wfDeprecated($function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes! ...
$wgUseMediaWikiUIEverywhere
Temporary variable that applies MediaWiki UI wherever it can be supported.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned after processing after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock()-offset Set to overwrite offset parameter in $wgRequest set to ''to unsetoffset-wrap String Wrap the message in html(usually something like"&lt
prefixSearchSubpages($search, $limit, $offset)
Allows to change the fields on the form that will be generated are created Can be used to omit specific feeds from being outputted You must not use this hook to add use OutputPage::addFeedLink() instead.&$feedLinks conditions will AND in the final query as a Content object as a Content object $title
Definition: hooks.txt:312
static linkKnown($target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to 'known'.
Definition: Linker.php:255
static run($event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
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
This serves as the entry point to the authentication system.
Definition: AuthManager.php:43
$wgEnableUserEmail
Set to true to enable user-to-user e-mail.
Helper functions for the login form that need to be shared with other special pages (such as CentralA...
Definition: LoginHelper.php:8
getPageTitle($subpage=false)
getFieldDefinitions($template)
Create a HTMLForm descriptor for the core login fields.
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
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 modifiable & $code
Definition: hooks.txt:776
loadAuth($subPage, $authAction=null, $reset=false)
Load or initialize $authAction, $authRequests and $subPage.
__call($name, $args)
Helper class for the password reset functionality shared by the web UI and the API.
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 local account $user
Definition: hooks.txt:242
static link($target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
Definition: Linker.php:203
Allows to change the fields on the form that will be generated are created Can be used to omit specific feeds from being outputted You must not use this hook to add use OutputPage::addFeedLink() instead.&$feedLinks conditions will AND in the final query as a Content object as a Content object the(raw HTML) error message to display(added in 1.13) &$status hooks can tweak the array to change how login etc forms should look $requests
Definition: hooks.txt:594
onAuthChangeFormFields(array $requests, array $fieldInfo, array &$formDescriptor, $action)
setRequest(array $data, $wasPosted=null)
showReturnToPage($type, $returnTo= '', $returnToQuery= '', $stickHTTPS=false)
Add a "return to" link or redirect to it.
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
this hook is for auditing only or null if authentication failed before getting that far $username
Definition: hooks.txt:776
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2458
getName()
Get the name of this Special Page.
bool $proxyAccountCreation
True if the user if creating an account for someone else.
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
getPageHtml($formHtml)
Add page elements which are outside the form.
getDefaultAction($subPage)
Get the default action for this special page, if none is given via URL/POST data. ...
getUser()
Shortcut to get the User executing this instance.
LoginForm as a special page has been replaced by SpecialUserLogin and SpecialCreateAccount, but some extensions called its public methods directly, so the class is retained as a B/C wrapper.
static incrementLoginThrottle($username)
$wgDisableAuthManager
Disable AuthManager.
getConfig()
Shortcut to get main config object.
A horrible hack to handle AuthManager's feature flag.
this hook is for auditing only WRONG_PASS
Definition: hooks.txt:1994
static getValidErrorMessages()
Returns an array of all valid error messages.
Definition: LoginHelper.php:36
getLanguage()
Shortcut to get user's language.
load($subPage)
Load data from request.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive $limit
Definition: hooks.txt:1020
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set $status
Definition: hooks.txt:1020
MediaWiki Logger LoggerFactory implements a PSR[0] compatible message logging system Named Psr Log LoggerInterface instances can be obtained from the MediaWiki Logger LoggerFactory::getInstance() static method.MediaWiki\Logger\LoggerFactory expects a class implementing the MediaWiki\Logger\Spi interface to act as a factory for new Psr\Log\LoggerInterface instances.The"Spi"in MediaWiki\Logger\Spi stands for"service provider interface".An SPI is an API intended to be implemented or extended by a third party.This software design pattern is intended to enable framework extension and replaceable components.It is specifically used in the MediaWiki\Logger\LoggerFactory service to allow alternate PSR-3 logging implementations to be easily integrated with MediaWiki.The service provider interface allows the backend logging library to be implemented in multiple ways.The $wgMWLoggerDefaultSpi global provides the classname of the default MediaWiki\Logger\Spi implementation to be loaded at runtime.This can either be the name of a class implementing the MediaWiki\Logger\Spi with a zero argument const ructor or a callable that will return an MediaWiki\Logger\Spi instance.Alternately the MediaWiki\Logger\LoggerFactory MediaWiki Logger LoggerFactory
Definition: logger.txt:5
static makeInternalOrExternalUrl($name)
If url string starts with http, consider as external URL, else internal.
Definition: Skin.php:1098
getFullTitle()
Return the full title, including $par.
static validateEmail($addr)
Does a string look like an e-mail address?
Definition: Sanitizer.php:1941
__construct($request=null)
__set($name, $value)
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
This serves as the entry point to the MediaWiki session handling system.
postProcessFormDescriptor(&$formDescriptor)
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect & $returnTo
Definition: hooks.txt:2376
static factory($code)
Get a cached or new language object for a given language code.
Definition: Language.php:179
static clearLoginThrottle($username)
showCreateAccountLink()
Whether the login/create account form should display a link to the other form (in addition to whateve...
static __callStatic($name, $args)
string $subPage
Subpage of the special page.
getPreservedParams($withToken=false)
static element($element, $attribs=[], $contents= '')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:230
successfulAction($direct=false, $extraMessages=null)
setContext($context)
Sets the context this SpecialPage is executed in.
if(is_null($wgLocalTZoffset)) if(!$wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:663
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string mapping parameter names to values & $type
Definition: hooks.txt:2376
getReturnToQueryStringFragment()
Returns a string that can be appended to the URL (without encoding) to preserve the return target...
addInputItem($name, $value, $type, $msg, $helptext=false)
Extensions (AntiSpoof and TitleBlacklist) call this in response to UserCreateForm hook to add checkbo...
This is a value object for authentication requests.
getPageTitle($subpage=false)
Get a self-referential title object.
$wgUser
Definition: Setup.php:801
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:310
trySubmit()
Attempts to do an authentication step with the submitted data.