155 parent::__construct();
170 if ( isset(
$session[
'settings'] ) ) {
173 foreach ( $this->settings as $key => $val ) {
174 $GLOBALS[$key] = $val;
180 if ( ( $this->
getVar(
'_InstallDone' ) || $this->
getVar(
'_UpgradeDone' ) )
181 && $this->request->getVal(
'localsettings' )
187 $isCSS = $this->request->getCheck(
'css' );
193 $this->happyPages =
$session[
'happyPages'] ?? [];
195 $this->skippedPages =
$session[
'skippedPages'] ?? [];
200 $pageName = $this->request->getVal(
'page',
'' );
202 if ( in_array( $pageName, $this->otherPages ) ) {
208 if ( !$pageName || !in_array( $pageName, $this->pageSequence ) ) {
209 $pageId = $lowestUnhappy;
211 $pageId = array_search( $pageName, $this->pageSequence );
214 # If necessary, move back to the lowest-numbered unhappy page
215 if ( $pageId > $lowestUnhappy ) {
216 $pageId = $lowestUnhappy;
217 if ( $lowestUnhappy == 0 ) {
218 # Knocked back to start, possible loss of session data.
219 $this->showSessionWarning =
true;
223 $pageName = $this->pageSequence[$pageId];
227 # If a back button was submitted, go back without submitting the form data.
228 if ( $this->request->wasPosted() && $this->request->getBool(
'submit-back' ) ) {
229 if ( $this->request->getVal(
'lastPage' ) ) {
230 $nextPage = $this->request->getVal(
'lastPage' );
231 } elseif ( $pageId !==
false ) {
233 # Skip the skipped pages
234 $nextPageId = $pageId;
238 $nextPage = $this->pageSequence[$nextPageId];
239 }
while ( isset( $this->skippedPages[$nextPage] ) );
241 $nextPage = $this->pageSequence[$lowestUnhappy];
244 $this->output->redirect( $this->
getUrl( [
'page' => $nextPage ] ) );
250 $this->currentPageName = $page->getName();
251 $this->startPageWrapper( $pageName );
253 if ( $page->isSlow() ) {
257 $result = $page->execute();
259 $this->endPageWrapper();
261 if ( $result ==
'skip' ) {
262 # Page skipped without explicit submission.
263 # Skip it when we click "back" so that we don't just go forward again.
264 $this->skippedPages[$pageName] =
true;
265 $result =
'continue';
267 unset( $this->skippedPages[$pageName] );
270 # If it was posted, the page can request a continue to the next page.
271 if ( $result ===
'continue' && !$this->output->headerDone() ) {
272 if ( $pageId !==
false ) {
273 $this->happyPages[$pageId] =
true;
278 if ( $this->request->getVal(
'lastPage' ) ) {
279 $nextPage = $this->request->getVal(
'lastPage' );
280 } elseif ( $pageId !==
false ) {
281 $nextPage = $this->pageSequence[$pageId + 1];
283 $nextPage = $this->pageSequence[$lowestUnhappy];
286 if ( array_search( $nextPage, $this->pageSequence ) > $lowestUnhappy ) {
287 $nextPage = $this->pageSequence[$lowestUnhappy];
290 $this->output->redirect( $this->
getUrl( [
'page' => $nextPage ] ) );
301 if ( count( $this->happyPages ) == 0 ) {
304 return max( array_keys( $this->happyPages ) ) + 1;
315 if (
wfIniGetBool(
'session.auto_start' ) || session_id() ) {
322 if ( $this->request->getProtocol() ===
'https' ) {
323 $options[
'cookie_secure'] =
'1';
326 $this->phpErrors = [];
327 set_error_handler( [ $this,
'errorHandler' ] );
329 session_name(
'mw_installer_session' );
330 session_start( $options );
331 }
catch ( Exception $e ) {
332 restore_error_handler();
335 restore_error_handler();
337 if ( $this->phpErrors ) {
354 $url = $this->request->getFullRequestURL();
355 if ( preg_match(
'!^(.*\?)!',
$url, $m ) ) {
359 if ( preg_match(
'!^(.*)/[^/]*/[^/]*$!',
$url, $m ) ) {
365 return md5( serialize( [
366 'local path' => dirname( __DIR__ ),
373 if ( !( $msg instanceof
Message ) ) {
376 array_map(
'htmlspecialchars',
$params )
379 $text = $msg->useDatabase(
false )->parse();
380 $box = Html::errorBox( $text,
'',
'config-error-box' );
381 $this->output->addHTML( $box );
391 $this->phpErrors[] = $errstr;
400 $this->output->output();
414 $this->happyPages = [];
415 $this->settings = [];
426 $url = $this->request->getRequestURL();
427 # Remove existing query
428 $url = preg_replace(
'/\?.*$/',
'',
$url );
444 $pageClass =
'MediaWiki\\Installer\\WebInstaller' . $pageName;
446 return new $pageClass( $this );
458 return $this->session[$name] ?? $default;
468 $this->session[$name] = $value;
477 return $this->tabIndex++;
486 if ( $this->
getSession(
'test' ) ===
null && !$this->request->wasPosted() ) {
490 RequestContext::getMain()->setLanguage(
$wgLang );
491 $this->
setVar(
'wgLanguageCode', $wgLanguageCode );
492 $this->
setVar(
'_UserLang', $wgLanguageCode );
508 ->getLanguageNameUtils()
509 ->getLanguageNames( LanguageNameUtils::AUTONYMS, LanguageNameUtils::SUPPORTED );
510 $headerLanguages = array_keys( $this->request->getAcceptLang() );
512 foreach ( $headerLanguages as $lang ) {
513 if ( isset( $mwLanguages[$lang] ) ) {
527 $s =
"<div class=\"config-page-wrapper\">\n";
528 $s .=
"<div class=\"config-page\">\n";
529 $s .=
"<div class=\"config-page-list cdx-card\"><span class=\"cdx-card__text\">";
530 $s .=
"<span class=\"cdx-card__text__description\"><ul>\n";
533 foreach ( $this->pageSequence as $id => $pageName ) {
534 $happy = !empty( $this->happyPages[$id] );
535 $s .= $this->getPageListItem(
537 $happy || $lastHappy == $id - 1,
546 $s .=
"</ul><br/><ul>\n";
549 $s .=
"</ul></span></span></div>\n";
559 $this->output->addHTMLNoFlush( $s );
572 $s =
"<li class=\"config-page-list-item\">";
579 $name =
wfMessage(
'config-page-' . strtolower( $pageName ) )->text();
582 $query = [
'page' => $pageName ];
584 if ( !in_array( $pageName, $this->pageSequence ) ) {
591 'href' => $this->
getUrl( $query )
596 $link = htmlspecialchars( $name );
600 $s .=
"<span class=\"config-page-current\">$link</span>";
607 'class' =>
'config-page-disabled'
621 private function endPageWrapper() {
622 $this->output->addHTMLNoFlush(
623 "<div class=\"visualClear\"></div>\n" .
625 "<div class=\"visualClear\"></div>\n" .
637 public function getInfoBox( $text, $icon =
false, $class =
'' ) {
639 HtmlArmor::getHtml( $text ) :
640 $this->
parse( $text,
true );
641 $alt =
wfMessage(
'config-information' )->text();
658 $html = $this->
parse( $text,
true );
660 return "<div class=\"config-help-field-container\">\n" .
661 "<a class=\"config-help-field-hint\" title=\"" .
662 wfMessage(
'config-help-tooltip' )->escaped() .
"\">ℹ️ " .
663 wfMessage(
'config-help' )->escaped() .
"</a>\n" .
664 "<div class=\"config-help-field-content config-help-field-content-hidden " .
665 "cdx-message cdx-message--block cdx-message--notice\" style=\"margin: 10px\">" .
666 "<div class=\"cdx-message__content\">" . $html .
"</div></div>\n" .
671 $html =
'<div class="cdx-message cdx-message--block cdx-message--notice">' .
672 '<span class="cdx-message__icon"></span><div class="cdx-message__content">' .
675 $this->output->addHTML( $html );
680 foreach ( $status->
getMessages(
'error' ) as $msg ) {
683 foreach ( $status->
getMessages(
'warning' ) as $msg ) {
699 public function label( $msg, $forId, $contents, $helpData =
"" ) {
700 if ( strval( $msg ) ==
'' ) {
701 $labelText =
"\u{00A0}";
703 $labelText =
wfMessage( $msg )->escaped();
706 $attributes = [
'class' =>
'config-label' ];
709 $attributes[
'for'] = $forId;
712 return "<div class=\"config-block\">\n" .
713 " <div class=\"config-block-label\">\n" .
720 " <div class=\"config-block-elements\">\n" .
742 if ( !isset(
$params[
'controlName'] ) ) {
746 if ( !isset(
$params[
'value'] ) ) {
750 if ( !isset(
$params[
'attribs'] ) ) {
753 if ( !isset(
$params[
'help'] ) ) {
760 "<div class=\"cdx-text-input\">" .
766 'id' =>
$params[
'controlName'],
767 'class' =>
'cdx-text-input__input',
790 if ( !isset(
$params[
'controlName'] ) ) {
794 if ( !isset(
$params[
'value'] ) ) {
798 if ( !isset(
$params[
'attribs'] ) ) {
801 if ( !isset(
$params[
'help'] ) ) {
814 'id' =>
$params[
'controlName'],
815 'class' =>
'config-input-text',
840 if ( !isset(
$params[
'value'] ) ) {
844 if ( !isset(
$params[
'attribs'] ) ) {
849 $params[
'attribs'][
'type'] =
'password';
861 private static function addClassAttrib( &$attribs, $class ) {
862 if ( isset( $attribs[
'class'] ) ) {
863 $attribs[
'class'] .=
' ' . $class;
865 $attribs[
'class'] = $class;
886 if ( !isset(
$params[
'controlName'] ) ) {
890 if ( !isset(
$params[
'value'] ) ) {
894 if ( !isset(
$params[
'attribs'] ) ) {
897 if ( !isset(
$params[
'help'] ) ) {
900 if ( !isset(
$params[
'labelAttribs'] ) ) {
904 self::addClassAttrib(
$params[
'attribs'],
'cdx-checkbox__input' );
905 self::addClassAttrib(
$params[
'labelAttribs'],
'cdx-checkbox__label' );
907 return "<div class=\"cdx-checkbox\" style=\"margin-top: 12px; margin-bottom: 2px;\">\n" .
912 'id' =>
$params[
'controlName'],
916 "<span class=\"cdx-checkbox__icon\"></span>" .
920 'for' =>
$params[
'controlName']
950 $label =
$params[
'label'] ??
'';
952 if ( !isset(
$params[
'controlName'] ) ) {
956 if ( !isset(
$params[
'help'] ) ) {
961 foreach ( $items as $item ) {
978 if ( !isset(
$params[
'controlName'] ) ) {
982 if ( !isset(
$params[
'value'] ) ) {
988 foreach (
$params[
'values'] as $value ) {
991 if ( isset(
$params[
'commonAttribs'] ) ) {
992 $itemAttribs =
$params[
'commonAttribs'];
995 if ( isset(
$params[
'itemAttribs'][$value] ) ) {
996 $itemAttribs =
$params[
'itemAttribs'][$value] + $itemAttribs;
999 $checked = $value ==
$params[
'value'];
1000 $id =
$params[
'controlName'] .
'_' . $value;
1001 $itemAttribs[
'id'] = $id;
1003 self::addClassAttrib( $itemAttribs,
'cdx-radio__input' );
1006 '<span class="cdx-radio">' .
1008 "<span class=\"cdx-radio__icon\"></span>\u{00A0}" .
1009 Xml::tags(
'label', [
'for' => $id,
'class' =>
'cdx-radio__label' ], $this->
parse(
1010 isset(
$params[
'itemLabels'] ) ?
1025 if ( !$status->isGood() ) {
1026 $html = $status->getHTML();
1028 if ( $status->isOK() ) {
1029 $box = Html::warningBox( $html,
'config-warning-box' );
1031 $box = Html::errorBox( $html,
'',
'config-error-box' );
1034 $this->output->addHTML( $box );
1051 foreach ( $varNames as $name ) {
1052 $value = $this->request->getVal( $prefix . $name );
1054 if ( $value !==
null && stripos( $name,
'password' ) ===
false ) {
1055 $value = trim( $value );
1057 $newValues[$name] = $value;
1059 if ( $value ===
null ) {
1061 $this->
setVar( $name,
false );
1062 } elseif ( stripos( $name,
'password' ) !==
false ) {
1065 $this->
setVar( $name, $value );
1080 $query = [
'page' => $page ];
1082 if ( in_array( $this->currentPageName, $this->pageSequence ) ) {
1086 return $this->
getUrl( $query );
1098 return Html::rawElement(
'li', [],
1110 $anchor = Html::rawElement(
'a',
1111 [
'href' => $this->
getUrl( [
'localsettings' => 1 ] ) ],
1115 return Html::rawElement(
'div', [
'class' =>
'config-download-link' ], $anchor );
1140 if ( !empty( $_SERVER[
'PHP_SELF'] ) ) {
1141 $path = $_SERVER[
'PHP_SELF'];
1142 } elseif ( !empty( $_SERVER[
'SCRIPT_NAME'] ) ) {
1143 $path = $_SERVER[
'SCRIPT_NAME'];
1145 if (
$path ===
false ) {
1150 return parent::envCheckPath();
1158 if ( !empty( $_SERVER[
'PHP_SELF'] ) ) {
1159 $path = $_SERVER[
'PHP_SELF'];
1160 } elseif ( !empty( $_SERVER[
'SCRIPT_NAME'] ) ) {
1161 $path = $_SERVER[
'SCRIPT_NAME'];
1163 if (
$path !==
false ) {
1164 $scriptPath = preg_replace(
'{^(.*)/(mw-)?config.*$}',
'$1',
$path );
1167 'wgScriptPath' =>
"$scriptPath",
1169 'wgScript' =>
"$scriptPath/index.php",
1170 'wgLoadScript' =>
"$scriptPath/load.php",
1171 'wgStylePath' =>
"$scriptPath/skins",
1172 'wgLocalStylePath' =>
"$scriptPath/skins",
1173 'wgExtensionAssetsPath' =>
"$scriptPath/extensions",
1174 'wgUploadPath' =>
"$scriptPath/images",
1175 'wgResourceBasePath' =>
"$scriptPath",
1185 $assumeProxiesUseDefaultProtocolPorts =
1186 $this->
getVar(
'wgAssumeProxiesUseDefaultProtocolPorts' );
1188 return WebRequest::detectServer( $assumeProxiesUseDefaultProtocolPorts );
1194 private function outputLS() {
1195 $this->request->response()->header(
'Content-type: application/x-httpd-php' );
1196 $this->request->response()->header(
1197 'Content-Disposition: attachment; filename="LocalSettings.php"'
1201 $rightsProfile = $this->rightsProfiles[$this->
getVar(
'_RightsProfile' )];
1202 foreach ( $rightsProfile as $group => $rightsArr ) {
1203 $ls->setGroupRights( $group, $rightsArr );
1205 echo $ls->getText();
1212 $this->request->response()->header(
'Content-type: text/css' );
1213 echo $this->output->getCSS();
1233 protected static function infoBox( $rawHtml, $icon, $alt, $class =
'' ) {
1234 $s = Html::openElement(
'div', [
'class' =>
'mw-installer-box-left' ] ) .
1241 Html::closeElement(
'div' ) .
1242 Html::openElement(
'div', [
'class' =>
'mw-installer-box-right' ] ) .
1244 Html::closeElement(
'div' ) .
1247 return Html::warningBox( $s, $class )
1248 .
Html::element(
'div', [
'style' =>
'clear: left;' ],
' ' );
1268 $dbInstaller->preUpgrade();
1272 ob_start( [ $this,
'outputHandler' ] );
1279 $this->
setVar(
'_UpgradeDone',
true );
1280 }
catch ( Exception $e ) {
1282 echo
"\nAn error occurred:\n";
1283 echo $e->getMessage();
1292 return htmlspecialchars( $string );
const MW_VERSION
The running version of MediaWiki.
wfIniGetBool( $setting)
Safety wrapper around ini_get() for boolean settings.
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined( 'MW_NO_SESSION') &&MW_ENTRY_POINT !=='cli' $wgLang
array $params
The job parameters.
Marks HTML that shouldn't be escaped.
Group all the pieces relevant to the context of a request into one instance.
getMessages(?string $type=null)
Returns a list of error messages, optionally only those of the given type.
$wgLanguageCode
Config variable stub for the LanguageCode setting, for use by phpdoc and IDEs.
const CONN_CREATE_TABLES
A connection with a role suitable for creating tables.