27 use GuzzleHttp\Psr7\Header;
37 use Wikimedia\AtEase\AtEase;
73 private const MEDIAWIKI_ANNOUNCE_URL =
74 'https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/';
148 'envCheckModSecurity',
154 'envCheckUploadsDirectory',
155 'envCheckUploadsServerResponse',
176 private const DEFAULT_VAR_NAMES = [
177 MainConfigNames::Sitename,
178 MainConfigNames::PasswordSender,
179 MainConfigNames::LanguageCode,
180 MainConfigNames::Localtimezone,
181 MainConfigNames::RightsIcon,
182 MainConfigNames::RightsText,
183 MainConfigNames::RightsUrl,
184 MainConfigNames::EnableEmail,
185 MainConfigNames::EnableUserEmail,
186 MainConfigNames::EnotifUserTalk,
187 MainConfigNames::EnotifWatchlist,
188 MainConfigNames::EmailAuthentication,
189 MainConfigNames::DBname,
190 MainConfigNames::DBtype,
191 MainConfigNames::Diff3,
192 MainConfigNames::ImageMagickConvertCommand,
193 MainConfigNames::GitBin,
194 MainConfigNames::ScriptPath,
195 MainConfigNames::MetaNamespace,
196 MainConfigNames::DeletedDirectory,
197 MainConfigNames::EnableUploads,
198 MainConfigNames::SecretKey,
199 MainConfigNames::UseInstantCommons,
200 MainConfigNames::UpgradeKey,
201 MainConfigNames::DefaultSkin,
202 MainConfigNames::Pingback,
214 '_Environment' =>
false,
215 '_RaiseMemory' =>
false,
216 '_UpgradeDone' =>
false,
217 '_InstallDone' =>
false,
219 '_InstallPassword' =>
'',
220 '_SameAccount' =>
true,
221 '_CreateDBAccount' =>
false,
222 '_NamespaceType' =>
'site-name',
224 '_AdminPassword' =>
'',
225 '_AdminPasswordConfirm' =>
'',
227 '_Subscribe' =>
false,
228 '_SkipOptional' =>
'continue',
229 '_RightsProfile' =>
'wiki',
230 '_LicenseCode' =>
'none',
234 '_MemCachedServers' =>
'',
235 '_UpgradeKeySupplied' =>
false,
236 '_ExistingDBSettings' =>
false,
237 '_LogoWordmark' =>
'',
238 '_LogoWordmarkWidth' => 119,
239 '_LogoWordmarkHeight' => 18,
241 '_Logo1x' =>
'$wgResourceBasePath/resources/assets/change-your-logo.svg',
242 '_LogoIcon' =>
'$wgResourceBasePath/resources/assets/change-your-logo-icon.svg',
243 '_LogoTagline' =>
'',
244 '_LogoTaglineWidth' => 117,
245 '_LogoTaglineHeight' => 13,
247 'wgAuthenticationTokenVersion' => 1,
256 private $installSteps = [];
271 'apcu' =>
'apcu_fetch',
272 'wincache' =>
'wincache_ucache_get'
283 '*' => [
'edit' => false ]
287 'createaccount' =>
false,
293 'createaccount' =>
false,
307 'url' =>
'https://creativecommons.org/licenses/by/4.0/',
308 'icon' =>
'$wgResourceBasePath/resources/assets/licenses/cc-by.png',
311 'url' =>
'https://creativecommons.org/licenses/by-sa/4.0/',
312 'icon' =>
'$wgResourceBasePath/resources/assets/licenses/cc-by-sa.png',
315 'url' =>
'https://creativecommons.org/licenses/by-nc-sa/4.0/',
316 'icon' =>
'$wgResourceBasePath/resources/assets/licenses/cc-by-nc-sa.png',
319 'url' =>
'https://creativecommons.org/publicdomain/zero/1.0/',
320 'icon' =>
'$wgResourceBasePath/resources/assets/licenses/cc-0.png',
323 'url' =>
'https://www.gnu.org/copyleft/fdl.html',
324 'icon' =>
'$wgResourceBasePath/resources/assets/licenses/gnu-fdl.png',
382 $emptyCache = [
'class' => EmptyBagOStuff::class ];
389 ] + $baseConfig->
get( MainConfigNames::ObjectCaches );
391 $configOverrides->set( MainConfigNames::ObjectCaches,
$objectCaches );
394 $messageDirs = $baseConfig->
get( MainConfigNames::MessagesDirs );
395 $messageDirs[
'MediawikiInstaller'] = __DIR__ .
'/i18n';
397 $configOverrides->set( MainConfigNames::MessagesDirs, $messageDirs );
399 $installerConfig =
new MultiConfig( [ $configOverrides, $baseConfig ] );
402 $configRegistry = $baseConfig->
get( MainConfigNames::ConfigRegistry );
403 $configRegistry[
'main'] =
static function () use ( $installerConfig ) {
404 return $installerConfig;
407 $configOverrides->set( MainConfigNames::ConfigRegistry, $configRegistry );
409 return $installerConfig;
422 $this->settings = $this->getDefaultSettings();
426 $this->compiledDBs = [];
427 foreach ( self::getDBTypes() as
$type ) {
430 if ( !$installer->isCompiled() ) {
433 $this->compiledDBs[] =
$type;
436 $this->parserTitle = Title::newFromText(
'Installer' );
442 private function getDefaultSettings(): array {
447 foreach ( self::DEFAULT_VAR_NAMES as $name ) {
449 $ret[$var] = MainConfigSchema::getDefaultValue( $name );
474 Config $installerConfig =
null,
475 $serviceOverrides = [],
476 bool $disableStorage =
false
482 MediaWikiServices::resetGlobalInstance( $installerConfig );
484 $mwServices = MediaWikiServices::getInstance();
486 if ( $disableStorage ) {
487 $mwServices->disableStorage();
491 $serviceOverrides += [
493 'InterwikiLookup' =>
static function () {
499 return $services->get(
'_DefaultOptionsLookup' );
504 return $services->getDBLoadBalancerFactory()->getMainLB();
509 $lang = $this->getVar(
'_UserLang',
'en' );
511 foreach ( $serviceOverrides as $name => $callback ) {
515 $mwServices->redefineService( $name, $callback );
520 $mwServices->getLocalisationCache()->disableBackend();
526 StubGlobalUser::setUser( $user );
539 $wgObjectCaches = $mwServices->getMainConfig()->get( MainConfigNames::ObjectCaches );
543 $this->setParserLanguage( $mwServices->getLanguageFactory()->getLanguage(
'en' ) );
554 return self::$dbTypes;
573 $this->showMessage(
'config-env-php', PHP_VERSION );
577 $pcreVersion = explode(
' ', PCRE_VERSION, 2 )[0];
578 if ( version_compare( $pcreVersion, self::MINIMUM_PCRE_VERSION,
'<' ) ) {
579 $this->showError(
'config-pcre-old', self::MINIMUM_PCRE_VERSION, $pcreVersion );
582 foreach ( $this->envChecks as $check ) {
583 $status = $this->$check();
584 if ( $status ===
false ) {
590 $this->setVar(
'_Environment', $good );
596 foreach ( $this->envPreps as $prep ) {
607 public function setVar( $name, $value ) {
608 $this->settings[$name] = $value;
621 public function getVar( $name, $default =
null ) {
622 return $this->settings[$name] ?? $default;
631 return $this->compiledDBs;
642 return ucfirst(
$type ) .
'Installer';
654 $type = $this->getVar(
'wgDBtype' );
659 if ( !isset( $this->dbInstallers[
$type] ) ) {
660 $class = self::getDBInstallerClass(
$type );
661 $this->dbInstallers[
$type] =
new $class( $this );
664 return $this->dbInstallers[
$type];
691 $lsExists = @file_exists( $lsFile );
697 if ( !str_ends_with( $lsFile,
'.php' ) ) {
699 'The installer cannot yet handle non-php settings files: ' . $lsFile .
'. ' .
700 'Use `php maintenance/run.php update` to update an existing installation.'
706 foreach ( MainConfigSchema::listDefaultValues(
'wg' ) as $var => $value ) {
726 return get_defined_vars();
739 return str_repeat(
'*', strlen( $realPassword ) );
750 if ( !preg_match(
'/^\*+$/', $value ) ) {
751 $this->setVar( $name, $value );
767 if ( !function_exists(
'posix_getegid' ) || !function_exists(
'posix_getpwuid' ) ) {
768 # I don't know this, this isn't UNIX.
772 # posix_getegid() *not* getmygid() because we want the group of the webserver,
773 # not whoever owns the current script.
774 $gid = posix_getegid();
775 return posix_getpwuid( $gid )[
'name'] ??
null;
794 public function parse( $text, $lineStart =
false ) {
795 $parser = MediaWikiServices::getInstance()->getParser();
798 $out = $parser->parse( $text, $this->parserTitle, $this->parserOptions, $lineStart );
799 $html = $out->getText( [
800 'enableSectionEditLinks' =>
false,
804 }
catch ( Wikimedia\Services\ServiceDisabledException $e ) {
805 $html =
'<!--DB access attempted during parse--> ' . htmlspecialchars( $text );
815 return $this->parserOptions;
821 $this->parserOptions->setExternalLinkTarget(
false );
841 if ( !$status->isOK() ) {
845 $status->value->insert(
849 'ss_total_edits' => 0,
850 'ss_good_articles' => 0,
851 'ss_total_pages' => 0,
853 'ss_active_users' => 0,
870 $dbType = $this->getVar(
'wgDBtype' );
875 foreach ( self::getDBTypes() as $name ) {
876 $allNames[] =
wfMessage(
"config-type-$name" )->text();
879 $databases = $this->getCompiledDBs();
881 $databases = array_flip( $databases );
883 foreach ( array_keys( $databases ) as $db ) {
884 $installer = $this->getDBInstaller( $db );
885 $status = $installer->checkPrerequisites();
886 if ( !$status->isGood() ) {
887 if ( !$this instanceof
WebInstaller && $db === $dbType ) {
893 $this->showStatusMessage( $status );
894 unset( $databases[$db] );
897 $databases = array_flip( $databases );
899 $this->showError(
'config-no-db',
$wgLang->commaList( $allNames ), count( $allNames ) );
914 AtEase::suppressWarnings();
915 $regexd = preg_replace(
'/[\x{0430}-\x{04FF}]/iu',
'',
'-АБВГД-' );
920 $regexprop = preg_replace(
'/\p{Zs}/u',
'',
"-\u{3000}-" );
921 AtEase::restoreWarnings();
922 if ( $regexd !=
'--' || $regexprop !=
'--' ) {
923 $this->showError(
'config-pcre-no-utf8' );
931 if ( preg_match(
'/^b.*c$/',
'bąc' ) === 0 ) {
932 $this->showError(
'config-pcre-invalid-newline' );
945 $limit = ini_get(
'memory_limit' );
947 if ( !$limit || $limit == -1 ) {
953 if ( $n < $this->minMemorySize * 1024 * 1024 ) {
954 $newLimit =
"{$this->minMemorySize}M";
956 if ( ini_set(
"memory_limit", $newLimit ) ===
false ) {
957 $this->showMessage(
'config-memory-bad', $limit );
959 $this->showMessage(
'config-memory-raised', $limit, $newLimit );
960 $this->setVar(
'_RaiseMemory',
true );
972 foreach ( $this->objectCaches as $name => $function ) {
973 if ( function_exists( $function ) ) {
974 $caches[$name] =
true;
979 $this->showMessage(
'config-no-cache-apcu' );
982 $this->setVar(
'_Caches', $caches );
990 if ( self::apacheModulePresent(
'mod_security' )
991 || self::apacheModulePresent(
'mod_security2' ) ) {
992 $this->showMessage(
'config-mod-security' );
1003 $names = [
"gdiff3",
"diff3" ];
1005 $names[] =
'diff3.exe';
1007 $versionInfo = [
'--version',
'GNU diffutils' ];
1012 $this->setVar(
'wgDiff3', $diff3 );
1014 $this->setVar(
'wgDiff3',
false );
1015 $this->showMessage(
'config-diff3-bad' );
1026 $names =
wfIsWindows() ?
'convert.exe' :
'convert';
1027 $versionInfo = [
'-version',
'ImageMagick' ];
1030 $this->setVar(
'wgImageMagickConvertCommand',
'' );
1032 $this->setVar(
'wgImageMagickConvertCommand', $convert );
1033 $this->showMessage(
'config-imagemagick', $convert );
1034 } elseif ( function_exists(
'imagejpeg' ) ) {
1035 $this->showMessage(
'config-gd' );
1037 $this->showMessage(
'config-no-scaling' );
1051 $versionInfo = [
'--version',
'git version' ];
1056 $this->setVar(
'wgGitBin', $git );
1057 $this->showMessage(
'config-git', $git );
1059 $this->setVar(
'wgGitBin',
false );
1060 $this->showMessage(
'config-git-bad' );
1072 $server = $this->envGetDefaultServer();
1073 if ( $server !==
null ) {
1074 $this->showMessage(
'config-using-server', $server );
1087 $this->getVar(
'wgServer' ),
1088 $this->getVar(
'wgScriptPath' )
1100 $dir =
$IP .
'/images/';
1101 $url = $this->getVar(
'wgServer' ) . $this->getVar(
'wgScriptPath' ) .
'/images/';
1102 $safe = !$this->dirIsExecutable( $dir, $url );
1105 $this->showMessage(
'config-uploads-not-safe', $dir );
1112 $url = $this->getVar(
'wgServer' ) . $this->getVar(
'wgScriptPath' ) .
'/images/README';
1113 $httpRequestFactory = MediaWikiServices::getInstance()->getHttpRequestFactory();
1116 $req = $httpRequestFactory->create(
1121 'followRedirects' =>
true
1126 $status = $req->execute();
1127 }
catch ( Exception $e ) {
1132 if ( !$status || !$status->isGood() ) {
1133 $this->showMessage(
'config-uploads-security-requesterror',
'X-Content-Type-Options: nosniff' );
1137 $headerValue = $req->getResponseHeader(
'X-Content-Type-Options' ) ??
'';
1138 $responseList = Header::splitList( $headerValue );
1139 if ( !in_array(
'nosniff', $responseList,
true ) ) {
1140 $this->showMessage(
'config-uploads-security-headers',
'X-Content-Type-Options: nosniff' );
1153 if ( PHP_INT_SIZE == 4 ) {
1154 $this->showMessage(
'config-using-32bit' );
1164 $unicodeVersion = implode(
'.', array_slice( IntlChar::getUnicodeVersion(), 0, 3 ) );
1165 $this->showMessage(
'config-env-icu', INTL_ICU_VERSION, $unicodeVersion );
1172 $server = $this->envGetDefaultServer();
1173 if ( $server !==
null ) {
1174 $this->setVar(
'wgServer', $server );
1189 $IP = dirname( dirname( __DIR__ ) );
1190 $this->setVar(
'IP',
$IP );
1204 "<?php echo 'exec';",
1205 "#!/var/env php\n<?php echo 'exec';",
1212 $httpRequestFactory = MediaWikiServices::getInstance()->getHttpRequestFactory();
1214 AtEase::suppressWarnings();
1216 foreach ( $scriptTypes as
$ext => $contents ) {
1217 foreach ( $contents as
$source ) {
1225 $text = $httpRequestFactory->get(
1230 }
catch ( Exception $e ) {
1235 unlink( $dir .
$file );
1237 if ( $text ==
'exec' ) {
1238 AtEase::restoreWarnings();
1245 AtEase::restoreWarnings();
1257 if ( function_exists(
'apache_get_modules' ) && in_array( $moduleName, apache_get_modules() ) ) {
1262 phpinfo( INFO_MODULES );
1263 $info = ob_get_clean();
1265 return strpos( $info, $moduleName ) !==
false;
1274 $this->parserOptions->setTargetLanguage(
$lang );
1275 $this->parserOptions->setUserLang(
$lang );
1284 return "{$_SERVER['PHP_SELF']}?page=" . urlencode( $page );
1297 switch ( $directory ) {
1299 return $this->findExtensionsByType(
'extension',
'extensions' );
1301 return $this->findExtensionsByType(
'skin',
'skins' );
1303 throw new InvalidArgumentException(
"Invalid extension type" );
1317 if ( $this->getVar(
'IP' ) ===
null ) {
1321 $extDir = $this->getVar(
'IP' ) .
'/' . $directory;
1322 if ( !is_readable( $extDir ) || !is_dir( $extDir ) ) {
1326 $dh = opendir( $extDir );
1329 while ( (
$file = readdir( $dh ) ) !==
false ) {
1331 if ( !is_dir(
"$extDir/$file" ) ||
$file[0] ===
'.' ) {
1334 $extStatus = $this->getExtensionInfo(
$type, $directory,
$file );
1335 if ( $extStatus->isOK() ) {
1336 $exts[
$file] = $extStatus->value;
1337 } elseif ( $extStatus->hasMessage(
'config-extension-not-found' ) ) {
1339 $status->warning(
'config-extension-not-found',
$file );
1341 $status->merge( $extStatus );
1345 uksort( $exts,
'strnatcasecmp' );
1347 $status->value = $exts;
1360 if ( $this->getVar(
'IP' ) ===
null ) {
1361 throw new Exception(
'Cannot find extensions since the IP variable is not yet set' );
1363 if (
$type !==
'extension' &&
$type !==
'skin' ) {
1364 throw new InvalidArgumentException(
"Invalid extension type" );
1366 $absDir = $this->getVar(
'IP' ) .
"/$parentRelPath/$name";
1367 $relDir =
"../$parentRelPath/$name";
1368 if ( !is_dir( $absDir ) ) {
1371 $jsonFile =
$type .
'.json';
1372 $fullJsonFile =
"$absDir/$jsonFile";
1373 $isJson = file_exists( $fullJsonFile );
1377 $fullPhpFile =
"$absDir/$name.php";
1378 $isPhp = file_exists( $fullPhpFile );
1380 if ( !$isJson && !$isPhp ) {
1386 if ( is_dir(
"$absDir/screenshots" ) ) {
1387 $paths = glob(
"$absDir/screenshots/*.png" );
1388 foreach ( $paths as
$path ) {
1389 $info[
'screenshots'][] = str_replace( $absDir, $relDir,
$path );
1394 $jsonStatus = $this->readExtension( $fullJsonFile );
1395 if ( !$jsonStatus->isOK() ) {
1398 $info += $jsonStatus->value;
1412 private function readExtension( $fullJsonFile, $extDeps = [], $skinDeps = [] ) {
1417 $extDir = $this->getVar(
'IP' ) .
'/extensions';
1418 foreach ( $extDeps as $dep ) {
1419 $fname =
"$extDir/$dep/extension.json";
1420 if ( !file_exists( $fname ) ) {
1427 $skinDir = $this->getVar(
'IP' ) .
'/skins';
1428 foreach ( $skinDeps as $dep ) {
1429 $fname =
"$skinDir/$dep/skin.json";
1430 if ( !file_exists( $fname ) ) {
1438 $info = $registry->readFromQueue( $load );
1440 if ( $e->incompatibleCore || $e->incompatibleSkins
1441 || $e->incompatibleExtensions
1446 basename( dirname( $fullJsonFile ) ), $e->getMessage() );
1447 } elseif ( $e->missingExtensions || $e->missingSkins ) {
1450 $status = $this->readExtension(
1452 array_merge( $extDeps, $e->missingExtensions ),
1453 array_merge( $skinDeps, $e->missingSkins )
1455 if ( !$status->isOK() && !$status->hasMessage(
'config-extension-dependency' ) ) {
1457 basename( dirname( $fullJsonFile ) ), $status->getMessage() );
1463 basename( dirname( $fullJsonFile ) ), $e->getMessage() );
1470 foreach ( $info[
'credits'] as $credit ) {
1476 $type = basename( $credit[
'path'] ) ===
'skin.json' ?
'skins' :
'extensions';
1477 $ret[
'requires'][
$type][] = $credit[
'name'];
1479 $credits = array_values( $info[
'credits'] )[0];
1480 if ( isset( $credits[
'url'] ) ) {
1481 $ret[
'url'] = $credits[
'url'];
1483 $ret[
'type'] = $credits[
'type'];
1497 $defaultSkin = $GLOBALS[
'wgDefaultSkin'];
1498 if ( !$skinNames || in_array( $defaultSkin, $skinNames ) ) {
1499 return $defaultSkin;
1501 return $skinNames[0];
1513 define(
'MW_EXTENSIONS_LOADED',
true );
1515 $legacySchemaHooks = $this->getAutoExtensionLegacyHooks();
1516 $data = $this->getAutoExtensionData();
1517 if ( isset( $data[
'globals'][
'wgHooks'][
'LoadExtensionSchemaUpdates'] ) ) {
1518 $legacySchemaHooks = array_merge( $legacySchemaHooks,
1519 $data[
'globals'][
'wgHooks'][
'LoadExtensionSchemaUpdates'] );
1521 $extDeprecatedHooks = $data[
'attributes'][
'DeprecatedHooks'] ?? [];
1525 [
'LoadExtensionSchemaUpdates' => $legacySchemaHooks ],
1526 $data[
'attributes'][
'Hooks'] ?? [],
1529 MediaWikiServices::getInstance()->getObjectFactory()
1543 $exts = $this->getVar(
'_Extensions' );
1544 $installPath = $this->getVar(
'IP' );
1546 foreach ( $exts as $e ) {
1547 if ( file_exists(
"$installPath/extensions/$e/$e.php" ) ) {
1548 $files[] =
"$installPath/extensions/$e/$e.php";
1553 return $this->includeExtensionFiles( $files );
1568 $IP = $this->getVar(
'IP' );
1579 foreach ( MainConfigSchema::listDefaultValues(
'wg' ) as $var => $value ) {
1588 foreach ( $files as
$file ) {
1595 $hooksWeWant =
$wgHooks[
'LoadExtensionSchemaUpdates'] ?? [];
1600 return [
'LoadExtensionSchemaUpdates' => $hooksWeWant ];
1610 $exts = $this->getVar(
'_Extensions' );
1611 $installPath = $this->getVar(
'IP' );
1614 foreach ( $exts as $e ) {
1615 $jsonPath =
"$installPath/extensions/$e/extension.json";
1616 if ( file_exists( $jsonPath ) ) {
1617 $extensionProcessor->extractInfoFromFile( $jsonPath );
1621 $autoload = $extensionProcessor->getExtractedAutoloadInfo();
1622 AutoLoader::loadFiles( $autoload[
'files'] );
1623 AutoLoader::registerClasses( $autoload[
'classes'] );
1624 AutoLoader::registerNamespaces( $autoload[
'namespaces'] );
1626 return $extensionProcessor->getExtractedInfo();
1637 if ( !$this->autoExtensionHookContainer ) {
1638 throw new \Exception( __METHOD__ .
1639 ': includeExtensions() has not been called' );
1641 return $this->autoExtensionHookContainer;
1658 $coreInstallSteps = [
1659 [
'name' =>
'database',
'callback' => [ $installer,
'setupDatabase' ] ],
1660 [
'name' =>
'tables',
'callback' => [ $installer,
'createTables' ] ],
1661 [
'name' =>
'tables-manual',
'callback' => [ $installer,
'createManualTables' ] ],
1662 [
'name' =>
'interwiki',
'callback' => [ $installer,
'populateInterwikiTable' ] ],
1663 [
'name' =>
'stats',
'callback' => [ $this,
'populateSiteStats' ] ],
1664 [
'name' =>
'keys',
'callback' => [ $this,
'generateKeys' ] ],
1665 [
'name' =>
'updates',
'callback' => [ $installer,
'insertUpdateKeys' ] ],
1666 [
'name' =>
'restore-services',
'callback' => [ $this,
'restoreServices' ] ],
1667 [
'name' =>
'sysop',
'callback' => [ $this,
'createSysop' ] ],
1668 [
'name' =>
'mainpage',
'callback' => [ $this,
'createMainpage' ] ],
1673 foreach ( $coreInstallSteps as $step ) {
1674 $this->installSteps[] = $step;
1675 if ( isset( $this->extraInstallSteps[$step[
'name']] ) ) {
1676 $this->installSteps = array_merge(
1677 $this->installSteps,
1678 $this->extraInstallSteps[$step[
'name']]
1684 if ( isset( $this->extraInstallSteps[
'BEGINNING'] ) ) {
1685 $this->installSteps = array_merge(
1686 $this->extraInstallSteps[
'BEGINNING'],
1692 if ( count( $this->getVar(
'_Extensions' ) ) ) {
1693 array_unshift( $this->installSteps,
1694 [
'name' =>
'extensions',
'callback' => [ $this,
'includeExtensions' ] ]
1696 $this->installSteps[] = [
1697 'name' =>
'extension-tables',
1698 'callback' => [ $installer,
'createExtensionTables' ]
1702 return $this->installSteps;
1714 $installResults = [];
1715 $installer = $this->getDBInstaller();
1716 $installer->preInstall();
1717 $steps = $this->getInstallSteps( $installer );
1718 foreach ( $steps as $stepObj ) {
1719 $name = $stepObj[
'name'];
1720 call_user_func_array( $startCB, [ $name ] );
1723 $status = call_user_func( $stepObj[
'callback'], $installer );
1726 call_user_func( $endCB, $name, $status );
1727 $installResults[$name] = $status;
1731 if ( !$status->isOK() ) {
1737 if ( $status->isOK() ) {
1739 'config-install-db-success'
1741 $this->setVar(
'_InstallDone',
true );
1744 return $installResults;
1753 $keys = [
'wgSecretKey' => 64 ];
1754 if ( strval( $this->getVar(
'wgUpgradeKey' ) ) ===
'' ) {
1755 $keys[
'wgUpgradeKey'] = 16;
1758 return $this->doGenerateKeys(
$keys );
1766 $this->resetMediaWikiServices(
null, [
1768 return $services->get(
'UserOptionsManager' );
1781 foreach (
$keys as $name => $length ) {
1783 $this->setVar( $name, $secretKey );
1794 $name = $this->getVar(
'_AdminName' );
1802 if ( $user->idForName() == 0 ) {
1803 $user->addToDatabase();
1805 $password = $this->getVar(
'_AdminPassword' );
1806 $status = $user->changeAuthenticationData( [
1807 'username' => $user->getName(),
1808 'password' => $password,
1809 'retype' => $password,
1811 if ( !$status->isGood() ) {
1813 $name, $status->getWikiText(
false,
false, $this->getVar(
'_UserLang' ) ) );
1816 $userGroupManager = MediaWikiServices::getInstance()->getUserGroupManager();
1817 $userGroupManager->addUserToGroup( $user,
'sysop' );
1818 $userGroupManager->addUserToGroup( $user,
'bureaucrat' );
1819 $userGroupManager->addUserToGroup( $user,
'interface-admin' );
1820 if ( $this->getVar(
'_AdminEmail' ) ) {
1821 $user->setEmail( $this->getVar(
'_AdminEmail' ) );
1823 $user->saveSettings();
1827 $ssUpdate->doUpdate();
1830 if ( $this->getVar(
'_Subscribe' ) && $this->getVar(
'_AdminEmail' ) ) {
1831 return $this->subscribeToMediaWikiAnnounce();
1839 private function subscribeToMediaWikiAnnounce() {
1841 $http = MediaWikiServices::getInstance()->getHttpRequestFactory();
1842 if ( !$http->canMakeRequests() ) {
1843 $status->warning(
'config-install-subscribe-fail',
1844 wfMessage(
'config-install-subscribe-notpossible' ) );
1849 $params = [
'email' => $this->getVar(
'_AdminEmail' ) ];
1850 $req = $http->create( self::MEDIAWIKI_ANNOUNCE_URL .
'anonymous_subscribe',
1851 [
'method' =>
'POST',
'postData' => $params ], __METHOD__ );
1854 $token = str_repeat(
'a', 64 );
1855 $req->setHeader(
'Referer', self::MEDIAWIKI_ANNOUNCE_URL );
1856 $req->setHeader(
'Cookie',
"csrftoken=$token" );
1857 $req->setHeader(
'X-CSRFToken', $token );
1860 $reqStatus = $req->execute();
1861 if ( !$reqStatus->isOK() ) {
1862 $status->warning(
'config-install-subscribe-fail',
1872 $checkReq = $http->create( self::MEDIAWIKI_ANNOUNCE_URL, [], __METHOD__ );
1873 $checkReq->setCookieJar( $req->getCookieJar() );
1874 if ( !$checkReq->execute()->isOK() ) {
1875 $status->warning(
'config-install-subscribe-possiblefail' );
1878 $html = $checkReq->getContent();
1879 if ( strpos( $html,
'Please check your inbox for further instructions' ) !==
false ) {
1881 } elseif ( strpos( $html,
'Member already subscribed' ) !==
false ) {
1882 $status->warning(
'config-install-subscribe-alreadysubscribed' );
1883 } elseif ( strpos( $html,
'Subscription request already pending' ) !==
false ) {
1884 $status->warning(
'config-install-subscribe-alreadypending' );
1886 $status->warning(
'config-install-subscribe-possiblefail' );
1899 $title = Title::newMainPage();
1900 if (
$title->exists() ) {
1901 $status->warning(
'config-install-mainpage-exists' );
1905 $page = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle(
$title );
1907 wfMessage(
'mainpagetext' )->inContentLanguage()->text() .
"\n\n" .
1908 wfMessage(
'mainpagedocfooter' )->inContentLanguage()->text()
1911 $status = $page->doUserEditContent(
1917 }
catch ( Exception $e ) {
1919 $status->fatal(
'config-install-mainpage-failed', $e->getMessage() );
1933 if ( !defined(
'MW_NO_SESSION_HANDLER' ) ) {
1934 define(
'MW_NO_SESSION_HANDLER', 1 );
1940 MainConfigNames::UseDatabaseMessages =>
false,
1943 MainConfigNames::LanguageConverterCacheType =>
CACHE_NONE,
1946 MainConfigNames::ResourceLoaderUseObjectCacheForDeps =>
true,
1949 MainConfigNames::ShowExceptionDetails =>
true,
1950 MainConfigNames::ShowHostnames =>
true,
1953 MainConfigNames::ExternalLinkTarget =>
'_blank',
1956 MainConfigNames::DisableOutputCompression =>
true,
1959 MainConfigNames::CookiePrefix =>
'mw_installer',
1962 MainConfigNames::MaxShellMemory => 0,
1966 MainConfigNames::SessionProviders => [
1968 'class' => InstallerSessionProvider::class,
1979 MainConfigNames::SessionCacheType =>
CACHE_NONE,
1983 MainConfigNames::Server =>
'https://🌻.invalid',
1995 $this->extraInstallSteps[$findStep][] = $callback;
2003 AtEase::suppressWarnings();
2004 set_time_limit( 0 );
2005 AtEase::restoreWarnings();
wfDetectLocalSettingsFile(?string $installationPath=null)
Decide and remember where to load LocalSettings from.
wfIsWindows()
Check if the operating system is Windows.
wfDetectInstallPath()
Decide and remember where mediawiki is installed.
wfShorthandToInteger(?string $string='', int $default=-1)
Converts shorthand byte notation to integer form.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined( 'MEDIAWIKI')) if(ini_get( 'mbstring.func_overload')) if(!defined( 'MW_ENTRY_POINT')) global $IP
Environment checks.
if(!defined( 'MW_NO_SESSION') &&! $wgCommandLineMode) $wgLang
Base class for DBMS-specific installation helper classes.
getConnection()
Connect to the database using the administrative user/password currently defined in the session.
static findInDefaultPaths( $names, $versionInfo=false)
Same as locateExecutable(), but checks in getPossibleBinPaths() by default.
Load extension manifests and aggregate their contents.
Load JSON files, and uses a Processor to extract information.
Accesses configuration settings from $GLOBALS.
A Config instance which stores all settings as a member variable.
envPrepServer()
Environment prep for the server hostname.
parse( $text, $lineStart=false)
Convert wikitext $text to HTML.
array $compiledDBs
List of detected DBs, access using getCompiledDBs().
getExtensionInfo( $type, $parentRelPath, $name)
Title $parserTitle
Cached Title, used by parse().
includeExtensions()
Installs the auto-detected extensions.
createMainpage(DatabaseInstaller $installer)
Insert Main Page with default content.
const MINIMUM_PCRE_VERSION
The oldest version of PCRE we can support.
getDefaultSkin(array $skinNames)
Returns a default value to be used for $wgDefaultSkin: normally the DefaultSkin from config-schema....
envCheckLibicu()
Check and display the libicu and Unicode versions.
getDBInstaller( $type=false)
Get an instance of DatabaseInstaller for the specified DB type.
envCheckDB()
Environment check for DB types.
envCheckUploadsServerResponse()
setVar( $name, $value)
Set a MW configuration variable, or internal installer configuration variable.
array $internalDefaults
Variables that are stored alongside globals, and are used for any configuration of the installation p...
envCheckModSecurity()
Scare user to death if they have mod_security or mod_security2.
getFakePassword( $realPassword)
Get a fake password for sending back to the user in HTML.
envCheckServer()
Environment check to inform user which server we've assumed.
disableTimeLimit()
Disable the time limit for execution.
static apacheModulePresent( $moduleName)
Checks for presence of an Apache module.
array $rightsProfiles
User rights profiles.
addInstallStep( $callback, $findStep='BEGINNING')
Add an installation step following the given step.
getCompiledDBs()
Get a list of DBs supported by current PHP setup.
ParserOptions $parserOptions
Cached ParserOptions, used by parse().
dirIsExecutable( $dir, $url)
Checks if scripts located in the given directory can be executed via the given URL.
envCheckGit()
Search for git.
getDocUrl( $page)
Overridden by WebInstaller to provide lastPage parameters.
static getExistingLocalSettings()
Determine if LocalSettings.php exists.
static getInstallerConfig(Config $baseConfig)
Constructs a Config object that contains configuration settings that should be overwritten for the in...
restoreServices()
Restore services that have been redefined in the early stage of installation.
includeExtensionFiles( $files)
Include the specified extension PHP files.
getAutoExtensionData()
Auto-detect extensions with an extension.json file.
envCheckMemory()
Environment check for available memory.
array $objectCaches
Known object cache types and the functions used to test for their existence.
array $licenses
License types.
static maybeGetWebserverPrimaryGroup()
On POSIX systems return the primary group of the webserver we're running under.
doEnvironmentChecks()
Do initial checks of the PHP environment.
performInstallation( $startCB, $endCB)
Actually perform the installation.
getAutoExtensionLegacyHooks()
Auto-detect extensions with an old style .php registration file, load the extensions,...
envCheck64Bit()
Checks if we're running on 64 bit or not.
generateKeys()
Generate $wgSecretKey.
populateSiteStats(DatabaseInstaller $installer)
Install step which adds a row to the site_stats table with appropriate initial values.
envCheckCache()
Environment check for compiled object cache types.
__construct()
Constructor, always call this from child classes.
int $minMemorySize
Minimum memory size in MiB.
findExtensionsByType( $type='extension', $directory='extensions')
Find extensions or skins, and return an array containing the value for 'Name' for each found extensio...
doGenerateKeys( $keys)
Generate a secret value for variables using a secure generator.
resetMediaWikiServices(Config $installerConfig=null, $serviceOverrides=[], bool $disableStorage=false)
Reset the global service container and associated global state to accommodate different stages of the...
showStatusMessage(Status $status)
Show a message to the installing user by using a Status object.
envCheckPath()
Environment check to inform user which paths we've assumed.
array $envPreps
A list of environment preparation methods called by doEnvironmentPreps().
static overrideConfig(SettingsBuilder $settings)
Override the necessary bits of the config to run an installation.
setPassword( $name, $value)
Set a variable which stores a password, except if the new value is a fake password in which case leav...
envPrepPath()
Environment prep for setting $IP and $wgScriptPath.
static getDBTypes()
Get a list of known DB types.
createSysop()
Create the first user account, grant it sysop, bureaucrat and interface-admin rights.
envCheckPCRE()
Environment check for the PCRE module.
getVar( $name, $default=null)
Get an MW configuration variable, or internal installer configuration variable.
static getDBInstallerClass( $type)
Get the DatabaseInstaller class name for this type.
array $extraInstallSteps
Extra steps for installation, for things like DatabaseInstallers to modify.
HookContainer null $autoExtensionHookContainer
static array $dbTypes
Known database types.
getAutoExtensionHookContainer()
Get the hook container previously populated by includeExtensions().
envCheckDiff3()
Search for GNU diff3.
envGetDefaultServer()
Helper function to be called from envPrepServer()
getInstallSteps(DatabaseInstaller $installer)
Get an array of install steps.
array $dbInstallers
Cached DB installer instances, access using getDBInstaller().
array $envChecks
A list of environment check methods called by doEnvironmentChecks().
envCheckGraphics()
Environment check for ImageMagick and GD.
showMessage( $msg,... $params)
UI interface for displaying a short message The parameters are like parameters to wfMessage().
showError( $msg,... $params)
Same as showMessage(), but for displaying errors.
envCheckUploadsDirectory()
Environment check for the permissions of the uploads directory.
setParserLanguage( $lang)
ParserOptions are constructed before we determined the language, so fix it.
findExtensions( $directory='extensions')
Find extensions or skins in a subdirectory of $IP.
static generateHex( $chars)
Generate a run of cryptographically random data and return it in hexadecimal string format.
A class containing constants representing the names of configuration variables.
This class contains schema declarations for all configuration variables known to MediaWiki core.
Provides a fallback sequence for Config objects.
Set options of the Parser.
static stripOuterParagraph( $html)
Strip outer.
static getMain()
Get the RequestContext object associated with the main request.
static factory(array $deltas)
static newFatal( $message,... $parameters)
Factory function for fatal errors.
static newGood( $value=null)
Factory function for good results.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
static wrap( $sv)
Succinct helper method to wrap a StatusValue.
static newFromName( $name, $validate='valid')
static newFromId( $id)
Static factory method for creation from a given user ID.
static newSystemUser( $name, $options=[])
Static factory method for creation of a "system" user from username.
Class for the core installer web interface.
Content object for wiki text pages.
$wgObjectCaches
Config variable stub for the ObjectCaches setting, for use by phpdoc and IDEs.
$wgStyleDirectory
Config variable stub for the StyleDirectory setting, for use by phpdoc and IDEs.
$wgHooks
Config variable stub for the Hooks setting, for use by phpdoc and IDEs.
$wgLocaltimezone
Config variable stub for the Localtimezone setting, for use by phpdoc and IDEs.
$wgExtensionDirectory
Config variable stub for the ExtensionDirectory setting, for use by phpdoc and IDEs.
$wgExternalLinkTarget
Config variable stub for the ExternalLinkTarget setting, for use by phpdoc and IDEs.
Interface for configuration instances.
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
if(!is_readable( $file)) $ext
if(!isset( $args[0])) $lang