34use Wikimedia\AtEase\AtEase;
70 private const MEDIAWIKI_ANNOUNCE_URL =
71 'https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/';
144 'envCheckModSecurity',
150 'envCheckUploadsDirectory',
152 'envCheckSuhosinMaxValueLength',
173 private const DEFAULT_VAR_NAMES = [
174 MainConfigNames::Sitename,
175 MainConfigNames::PasswordSender,
176 MainConfigNames::LanguageCode,
177 MainConfigNames::Localtimezone,
178 MainConfigNames::RightsIcon,
179 MainConfigNames::RightsText,
180 MainConfigNames::RightsUrl,
181 MainConfigNames::EnableEmail,
182 MainConfigNames::EnableUserEmail,
183 MainConfigNames::EnotifUserTalk,
184 MainConfigNames::EnotifWatchlist,
185 MainConfigNames::EmailAuthentication,
186 MainConfigNames::DBname,
187 MainConfigNames::DBtype,
188 MainConfigNames::Diff3,
189 MainConfigNames::ImageMagickConvertCommand,
190 MainConfigNames::GitBin,
191 MainConfigNames::ScriptPath,
192 MainConfigNames::MetaNamespace,
193 MainConfigNames::DeletedDirectory,
194 MainConfigNames::EnableUploads,
195 MainConfigNames::SecretKey,
196 MainConfigNames::UseInstantCommons,
197 MainConfigNames::UpgradeKey,
198 MainConfigNames::DefaultSkin,
199 MainConfigNames::Pingback,
211 '_Environment' =>
false,
212 '_RaiseMemory' =>
false,
213 '_UpgradeDone' =>
false,
214 '_InstallDone' =>
false,
216 '_InstallPassword' =>
'',
217 '_SameAccount' =>
true,
218 '_CreateDBAccount' =>
false,
219 '_NamespaceType' =>
'site-name',
221 '_AdminPassword' =>
'',
222 '_AdminPasswordConfirm' =>
'',
224 '_Subscribe' =>
false,
225 '_SkipOptional' =>
'continue',
226 '_RightsProfile' =>
'wiki',
227 '_LicenseCode' =>
'none',
231 '_MemCachedServers' =>
'',
232 '_UpgradeKeySupplied' =>
false,
233 '_ExistingDBSettings' =>
false,
234 '_LogoWordmark' =>
'',
235 '_LogoWordmarkWidth' => 119,
236 '_LogoWordmarkHeight' => 18,
238 '_Logo1x' =>
'$wgResourceBasePath/resources/assets/change-your-logo.svg',
239 '_LogoIcon' =>
'$wgResourceBasePath/resources/assets/change-your-logo-icon.svg',
240 '_LogoTagline' =>
'',
241 '_LogoTaglineWidth' => 117,
242 '_LogoTaglineHeight' => 13,
244 'wgAuthenticationTokenVersion' => 1,
253 private $installSteps = [];
268 'apcu' =>
'apcu_fetch',
269 'wincache' =>
'wincache_ucache_get'
280 '*' => [
'edit' => false ]
284 'createaccount' =>
false,
290 'createaccount' =>
false,
304 'url' =>
'https://creativecommons.org/licenses/by/4.0/',
305 'icon' =>
'$wgResourceBasePath/resources/assets/licenses/cc-by.png',
308 'url' =>
'https://creativecommons.org/licenses/by-sa/4.0/',
309 'icon' =>
'$wgResourceBasePath/resources/assets/licenses/cc-by-sa.png',
312 'url' =>
'https://creativecommons.org/licenses/by-nc-sa/4.0/',
313 'icon' =>
'$wgResourceBasePath/resources/assets/licenses/cc-by-nc-sa.png',
316 'url' =>
'https://creativecommons.org/publicdomain/zero/1.0/',
317 'icon' =>
'$wgResourceBasePath/resources/assets/licenses/cc-0.png',
320 'url' =>
'https://www.gnu.org/copyleft/fdl.html',
321 'icon' =>
'$wgResourceBasePath/resources/assets/licenses/gnu-fdl.png',
379 $emptyCache = [
'class' => EmptyBagOStuff::class ];
386 ] + $baseConfig->
get( MainConfigNames::ObjectCaches );
388 $configOverrides->set( MainConfigNames::ObjectCaches,
$objectCaches );
391 $messageDirs = $baseConfig->
get( MainConfigNames::MessagesDirs );
392 $messageDirs[
'MediawikiInstaller'] = __DIR__ .
'/i18n';
394 $configOverrides->set( MainConfigNames::MessagesDirs, $messageDirs );
396 $installerConfig =
new MultiConfig( [ $configOverrides, $baseConfig ] );
399 $configRegistry = $baseConfig->
get( MainConfigNames::ConfigRegistry );
400 $configRegistry[
'main'] =
static function () use ( $installerConfig ) {
401 return $installerConfig;
404 $configOverrides->set( MainConfigNames::ConfigRegistry, $configRegistry );
406 return $installerConfig;
419 MediaWikiServices::disableStorageBackend();
421 $this->settings = $this->getDefaultSettings();
425 $this->compiledDBs = [];
426 foreach ( self::getDBTypes() as
$type ) {
429 if ( !$installer->isCompiled() ) {
432 $this->compiledDBs[] =
$type;
435 $this->parserTitle = Title::newFromText(
'Installer' );
441 private function getDefaultSettings(): array {
446 foreach ( self::DEFAULT_VAR_NAMES as $name ) {
448 $ret[$var] = MainConfigSchema::getDefaultValue( $name );
475 $serviceOverrides += [
477 'InterwikiLookup' =>
static function () {
483 return $services->get(
'_DefaultOptionsLookup' );
487 $lang = $this->getVar(
'_UserLang',
'en' );
490 MediaWikiServices::resetGlobalInstance( $installerConfig );
492 $mwServices = MediaWikiServices::getInstance();
494 foreach ( $serviceOverrides as $name => $callback ) {
498 $mwServices->redefineService( $name, $callback );
503 $mwServices->getLocalisationCache()->disableBackend();
511 RequestContext::getMain()->setUser( $user );
517 RequestContext::getMain()->setLanguage(
$lang );
518 $wgLang = RequestContext::getMain()->getLanguage();
522 $wgObjectCaches = $mwServices->getMainConfig()->get( MainConfigNames::ObjectCaches );
526 $this->setParserLanguage( $mwServices->getLanguageFactory()->getLanguage(
'en' ) );
537 return self::$dbTypes;
556 $this->showMessage(
'config-env-php', PHP_VERSION );
560 $pcreVersion = explode(
' ', PCRE_VERSION, 2 )[0];
561 if ( version_compare( $pcreVersion, self::MINIMUM_PCRE_VERSION,
'<' ) ) {
562 $this->showError(
'config-pcre-old', self::MINIMUM_PCRE_VERSION, $pcreVersion );
565 foreach ( $this->envChecks as $check ) {
566 $status = $this->$check();
567 if ( $status ===
false ) {
573 $this->setVar(
'_Environment', $good );
575 return $good ? Status::newGood() : Status::newFatal(
'config-env-bad' );
579 foreach ( $this->envPreps as $prep ) {
590 public function setVar( $name, $value ) {
591 $this->settings[$name] = $value;
604 public function getVar( $name, $default =
null ) {
605 return $this->settings[$name] ?? $default;
614 return $this->compiledDBs;
625 return ucfirst(
$type ) .
'Installer';
637 $type = $this->getVar(
'wgDBtype' );
642 if ( !isset( $this->dbInstallers[
$type] ) ) {
643 $class = self::getDBInstallerClass(
$type );
644 $this->dbInstallers[
$type] =
new $class( $this );
647 return $this->dbInstallers[
$type];
674 $lsExists = @file_exists( $lsFile );
680 if ( !str_ends_with( $lsFile,
'.php' ) ) {
682 'The installer cannot yet handle non-php settings files: ' . $lsFile .
'. ' .
683 'Use maintenance/update.php to update an existing installation.'
689 foreach ( MainConfigSchema::listDefaultValues(
'wg' ) as $var => $value ) {
709 return get_defined_vars();
722 return str_repeat(
'*', strlen( $realPassword ) );
733 if ( !preg_match(
'/^\*+$/', $value ) ) {
734 $this->setVar( $name, $value );
750 if ( !function_exists(
'posix_getegid' ) || !function_exists(
'posix_getpwuid' ) ) {
751 # I don't know this, this isn't UNIX.
755 # posix_getegid() *not* getmygid() because we want the group of the webserver,
756 # not whoever owns the current script.
757 $gid = posix_getegid();
758 return posix_getpwuid( $gid )[
'name'] ??
null;
777 public function parse( $text, $lineStart =
false ) {
778 $parser = MediaWikiServices::getInstance()->getParser();
781 $out = $parser->parse( $text, $this->parserTitle, $this->parserOptions, $lineStart );
782 $html = $out->getText( [
783 'enableSectionEditLinks' =>
false,
787 }
catch (
Wikimedia\Services\ServiceDisabledException $e ) {
788 $html =
'<!--DB access attempted during parse--> ' . htmlspecialchars( $text );
798 return $this->parserOptions;
802 $this->parserOptions->setExternalLinkTarget(
false );
820 if ( !$status->isOK() ) {
824 $status->value->insert(
828 'ss_total_edits' => 0,
829 'ss_good_articles' => 0,
830 'ss_total_pages' => 0,
832 'ss_active_users' => 0,
839 return Status::newGood();
849 $dbType = $this->getVar(
'wgDBtype' );
854 foreach ( self::getDBTypes() as $name ) {
855 $allNames[] =
wfMessage(
"config-type-$name" )->text();
858 $databases = $this->getCompiledDBs();
860 $databases = array_flip( $databases );
862 foreach ( array_keys( $databases ) as $db ) {
863 $installer = $this->getDBInstaller( $db );
864 $status = $installer->checkPrerequisites();
865 if ( !$status->isGood() ) {
866 if ( !$this instanceof
WebInstaller && $db === $dbType ) {
872 $this->showStatusMessage( $status );
873 unset( $databases[$db] );
876 $databases = array_flip( $databases );
878 $this->showError(
'config-no-db',
$wgLang->commaList( $allNames ), count( $allNames ) );
893 AtEase::suppressWarnings();
894 $regexd = preg_replace(
'/[\x{0430}-\x{04FF}]/iu',
'',
'-АБВГД-' );
899 $regexprop = preg_replace(
'/\p{Zs}/u',
'',
"-\u{3000}-" );
900 AtEase::restoreWarnings();
901 if ( $regexd !=
'--' || $regexprop !=
'--' ) {
902 $this->showError(
'config-pcre-no-utf8' );
910 if ( preg_match(
'/^b.*c$/',
'bąc' ) === 0 ) {
911 $this->showError(
'config-pcre-invalid-newline' );
924 $limit = ini_get(
'memory_limit' );
926 if ( !$limit || $limit == -1 ) {
932 if ( $n < $this->minMemorySize * 1024 * 1024 ) {
933 $newLimit =
"{$this->minMemorySize}M";
935 if ( ini_set(
"memory_limit", $newLimit ) ===
false ) {
936 $this->showMessage(
'config-memory-bad', $limit );
938 $this->showMessage(
'config-memory-raised', $limit, $newLimit );
939 $this->setVar(
'_RaiseMemory',
true );
951 foreach ( $this->objectCaches as $name => $function ) {
952 if ( function_exists( $function ) ) {
953 $caches[$name] =
true;
958 $this->showMessage(
'config-no-cache-apcu' );
961 $this->setVar(
'_Caches', $caches );
969 if ( self::apacheModulePresent(
'mod_security' )
970 || self::apacheModulePresent(
'mod_security2' ) ) {
971 $this->showMessage(
'config-mod-security' );
982 $names = [
"gdiff3",
"diff3" ];
984 $names[] =
'diff3.exe';
986 $versionInfo = [
'--version',
'GNU diffutils' ];
988 $diff3 = ExecutableFinder::findInDefaultPaths( $names, $versionInfo );
991 $this->setVar(
'wgDiff3', $diff3 );
993 $this->setVar(
'wgDiff3',
false );
994 $this->showMessage(
'config-diff3-bad' );
1005 $names =
wfIsWindows() ?
'convert.exe' :
'convert';
1006 $versionInfo = [
'-version',
'ImageMagick' ];
1007 $convert = ExecutableFinder::findInDefaultPaths( $names, $versionInfo );
1009 $this->setVar(
'wgImageMagickConvertCommand',
'' );
1011 $this->setVar(
'wgImageMagickConvertCommand', $convert );
1012 $this->showMessage(
'config-imagemagick', $convert );
1013 } elseif ( function_exists(
'imagejpeg' ) ) {
1014 $this->showMessage(
'config-gd' );
1016 $this->showMessage(
'config-no-scaling' );
1030 $versionInfo = [
'--version',
'git version' ];
1032 $git = ExecutableFinder::findInDefaultPaths( $names, $versionInfo );
1035 $this->setVar(
'wgGitBin', $git );
1036 $this->showMessage(
'config-git', $git );
1038 $this->setVar(
'wgGitBin',
false );
1039 $this->showMessage(
'config-git-bad' );
1051 $server = $this->envGetDefaultServer();
1052 if ( $server !==
null ) {
1053 $this->showMessage(
'config-using-server', $server );
1066 $this->getVar(
'wgServer' ),
1067 $this->getVar(
'wgScriptPath' )
1079 $dir =
$IP .
'/images/';
1080 $url = $this->getVar(
'wgServer' ) . $this->getVar(
'wgScriptPath' ) .
'/images/';
1081 $safe = !$this->dirIsExecutable( $dir, $url );
1084 $this->showMessage(
'config-uploads-not-safe', $dir );
1096 $currentValue = ini_get(
'suhosin.get.max_value_length' );
1097 $minRequired = 2000;
1098 $recommended = 5000;
1099 if ( $currentValue > 0 && $currentValue < $minRequired ) {
1100 $this->showError(
'config-suhosin-max-value-length', $currentValue, $minRequired, $recommended );
1114 if ( PHP_INT_SIZE == 4 ) {
1115 $this->showMessage(
'config-using-32bit' );
1132 $not_normal_c =
"\u{FA6C}";
1133 $normal_c =
"\u{242EE}";
1135 $intl = normalizer_normalize( $not_normal_c, Normalizer::FORM_C );
1137 $this->showMessage(
'config-unicode-using-intl' );
1138 if ( $intl !== $normal_c ) {
1139 $this->showMessage(
'config-unicode-update-warning' );
1147 $server = $this->envGetDefaultServer();
1148 if ( $server !==
null ) {
1149 $this->setVar(
'wgServer', $server );
1164 $IP = dirname( dirname( __DIR__ ) );
1165 $this->setVar(
'IP',
$IP );
1179 "<?php echo 'exec';",
1180 "#!/var/env php\n<?php echo 'exec';",
1187 $httpRequestFactory = MediaWikiServices::getInstance()->getHttpRequestFactory();
1189 AtEase::suppressWarnings();
1191 foreach ( $scriptTypes as
$ext => $contents ) {
1192 foreach ( $contents as
$source ) {
1200 $text = $httpRequestFactory->get(
1205 }
catch ( Exception $e ) {
1210 unlink( $dir .
$file );
1212 if ( $text ==
'exec' ) {
1213 AtEase::restoreWarnings();
1220 AtEase::restoreWarnings();
1232 if ( function_exists(
'apache_get_modules' ) && in_array( $moduleName, apache_get_modules() ) ) {
1237 phpinfo( INFO_MODULES );
1238 $info = ob_get_clean();
1240 return strpos( $info, $moduleName ) !==
false;
1249 $this->parserOptions->setTargetLanguage(
$lang );
1250 $this->parserOptions->setUserLang(
$lang );
1259 return "{$_SERVER['PHP_SELF']}?page=" . urlencode( $page );
1272 switch ( $directory ) {
1274 return $this->findExtensionsByType(
'extension',
'extensions' );
1276 return $this->findExtensionsByType(
'skin',
'skins' );
1278 throw new InvalidArgumentException(
"Invalid extension type" );
1292 if ( $this->getVar(
'IP' ) ===
null ) {
1293 return Status::newGood( [] );
1296 $extDir = $this->getVar(
'IP' ) .
'/' . $directory;
1297 if ( !is_readable( $extDir ) || !is_dir( $extDir ) ) {
1298 return Status::newGood( [] );
1301 $dh = opendir( $extDir );
1304 while ( (
$file = readdir( $dh ) ) !==
false ) {
1306 if ( !is_dir(
"$extDir/$file" ) ||
$file[0] ===
'.' ) {
1309 $extStatus = $this->getExtensionInfo(
$type, $directory,
$file );
1310 if ( $extStatus->isOK() ) {
1311 $exts[
$file] = $extStatus->value;
1312 } elseif ( $extStatus->hasMessage(
'config-extension-not-found' ) ) {
1314 $status->warning(
'config-extension-not-found',
$file );
1316 $status->merge( $extStatus );
1320 uksort( $exts,
'strnatcasecmp' );
1322 $status->value = $exts;
1335 if ( $this->getVar(
'IP' ) ===
null ) {
1336 throw new Exception(
'Cannot find extensions since the IP variable is not yet set' );
1338 if (
$type !==
'extension' &&
$type !==
'skin' ) {
1339 throw new InvalidArgumentException(
"Invalid extension type" );
1341 $absDir = $this->getVar(
'IP' ) .
"/$parentRelPath/$name";
1342 $relDir =
"../$parentRelPath/$name";
1343 if ( !is_dir( $absDir ) ) {
1344 return Status::newFatal(
'config-extension-not-found', $name );
1346 $jsonFile =
$type .
'.json';
1347 $fullJsonFile =
"$absDir/$jsonFile";
1348 $isJson = file_exists( $fullJsonFile );
1352 $fullPhpFile =
"$absDir/$name.php";
1353 $isPhp = file_exists( $fullPhpFile );
1355 if ( !$isJson && !$isPhp ) {
1356 return Status::newFatal(
'config-extension-not-found', $name );
1361 if ( is_dir(
"$absDir/screenshots" ) ) {
1362 $paths = glob(
"$absDir/screenshots/*.png" );
1363 foreach ( $paths as
$path ) {
1364 $info[
'screenshots'][] = str_replace( $absDir, $relDir,
$path );
1369 $jsonStatus = $this->readExtension( $fullJsonFile );
1370 if ( !$jsonStatus->isOK() ) {
1373 $info += $jsonStatus->value;
1376 return Status::newGood( $info );
1387 private function readExtension( $fullJsonFile, $extDeps = [], $skinDeps = [] ) {
1392 $extDir = $this->getVar(
'IP' ) .
'/extensions';
1393 foreach ( $extDeps as $dep ) {
1394 $fname =
"$extDir/$dep/extension.json";
1395 if ( !file_exists( $fname ) ) {
1396 return Status::newFatal(
'config-extension-not-found', $dep );
1402 $skinDir = $this->getVar(
'IP' ) .
'/skins';
1403 foreach ( $skinDeps as $dep ) {
1404 $fname =
"$skinDir/$dep/skin.json";
1405 if ( !file_exists( $fname ) ) {
1413 $info = $registry->readFromQueue( $load );
1415 if ( $e->incompatibleCore || $e->incompatibleSkins
1416 || $e->incompatibleExtensions
1421 basename( dirname( $fullJsonFile ) ), $e->getMessage() );
1422 } elseif ( $e->missingExtensions || $e->missingSkins ) {
1425 $status = $this->readExtension(
1427 array_merge( $extDeps, $e->missingExtensions ),
1428 array_merge( $skinDeps, $e->missingSkins )
1430 if ( !$status->isOK() && !$status->hasMessage(
'config-extension-dependency' ) ) {
1432 basename( dirname( $fullJsonFile ) ), $status->getMessage() );
1438 basename( dirname( $fullJsonFile ) ), $e->getMessage() );
1445 foreach ( $info[
'credits'] as $name => $credit ) {
1451 $type = basename( $credit[
'path'] ) ===
'skin.json' ?
'skins' :
'extensions';
1452 $ret[
'requires'][
$type][] = $credit[
'name'];
1454 $credits = array_values( $info[
'credits'] )[0];
1455 if ( isset( $credits[
'url'] ) ) {
1456 $ret[
'url'] = $credits[
'url'];
1458 $ret[
'type'] = $credits[
'type'];
1472 $defaultSkin = $GLOBALS[
'wgDefaultSkin'];
1473 if ( !$skinNames || in_array( $defaultSkin, $skinNames ) ) {
1474 return $defaultSkin;
1476 return $skinNames[0];
1488 define(
'MW_EXTENSIONS_LOADED',
true );
1490 $legacySchemaHooks = $this->getAutoExtensionLegacyHooks();
1491 $data = $this->getAutoExtensionData();
1492 if ( isset( $data[
'globals'][
'wgHooks'][
'LoadExtensionSchemaUpdates'] ) ) {
1493 $legacySchemaHooks = array_merge( $legacySchemaHooks,
1494 $data[
'globals'][
'wgHooks'][
'LoadExtensionSchemaUpdates'] );
1496 $extDeprecatedHooks = $data[
'attributes'][
'DeprecatedHooks'] ?? [];
1500 [
'LoadExtensionSchemaUpdates' => $legacySchemaHooks ],
1501 $data[
'attributes'][
'Hooks'] ?? [],
1504 MediaWikiServices::getInstance()->getObjectFactory()
1507 return Status::newGood();
1518 $exts = $this->getVar(
'_Extensions' );
1519 $installPath = $this->getVar(
'IP' );
1521 foreach ( $exts as $e ) {
1522 if ( file_exists(
"$installPath/extensions/$e/$e.php" ) ) {
1523 $files[] =
"$installPath/extensions/$e/$e.php";
1528 return $this->includeExtensionFiles( $files );
1543 $IP = $this->getVar(
'IP' );
1554 foreach ( MainConfigSchema::listDefaultValues(
'wg' ) as $var => $value ) {
1563 foreach ( $files as
$file ) {
1570 $hooksWeWant =
$wgHooks[
'LoadExtensionSchemaUpdates'] ?? [];
1575 return [
'LoadExtensionSchemaUpdates' => $hooksWeWant ];
1585 $exts = $this->getVar(
'_Extensions' );
1586 $installPath = $this->getVar(
'IP' );
1589 foreach ( $exts as $e ) {
1590 $jsonPath =
"$installPath/extensions/$e/extension.json";
1591 if ( file_exists( $jsonPath ) ) {
1592 $extensionProcessor->extractInfoFromFile( $jsonPath );
1596 $autoload = $extensionProcessor->getExtractedAutoloadInfo();
1601 return $extensionProcessor->getExtractedInfo();
1612 if ( !$this->autoExtensionHookContainer ) {
1613 throw new \Exception( __METHOD__ .
1614 ': includeExtensions() has not been called' );
1616 return $this->autoExtensionHookContainer;
1633 $coreInstallSteps = [
1634 [
'name' =>
'database',
'callback' => [ $installer,
'setupDatabase' ] ],
1635 [
'name' =>
'tables',
'callback' => [ $installer,
'createTables' ] ],
1636 [
'name' =>
'tables-manual',
'callback' => [ $installer,
'createManualTables' ] ],
1637 [
'name' =>
'interwiki',
'callback' => [ $installer,
'populateInterwikiTable' ] ],
1638 [
'name' =>
'stats',
'callback' => [ $this,
'populateSiteStats' ] ],
1639 [
'name' =>
'keys',
'callback' => [ $this,
'generateKeys' ] ],
1640 [
'name' =>
'updates',
'callback' => [ $installer,
'insertUpdateKeys' ] ],
1641 [
'name' =>
'restore-services',
'callback' => [ $this,
'restoreServices' ] ],
1642 [
'name' =>
'sysop',
'callback' => [ $this,
'createSysop' ] ],
1643 [
'name' =>
'mainpage',
'callback' => [ $this,
'createMainpage' ] ],
1648 foreach ( $coreInstallSteps as $step ) {
1649 $this->installSteps[] = $step;
1650 if ( isset( $this->extraInstallSteps[$step[
'name']] ) ) {
1651 $this->installSteps = array_merge(
1652 $this->installSteps,
1653 $this->extraInstallSteps[$step[
'name']]
1659 if ( isset( $this->extraInstallSteps[
'BEGINNING'] ) ) {
1660 $this->installSteps = array_merge(
1661 $this->extraInstallSteps[
'BEGINNING'],
1667 if ( count( $this->getVar(
'_Extensions' ) ) ) {
1668 array_unshift( $this->installSteps,
1669 [
'name' =>
'extensions',
'callback' => [ $this,
'includeExtensions' ] ]
1671 $this->installSteps[] = [
1672 'name' =>
'extension-tables',
1673 'callback' => [ $installer,
'createExtensionTables' ]
1677 return $this->installSteps;
1689 $installResults = [];
1690 $installer = $this->getDBInstaller();
1691 $installer->preInstall();
1692 $steps = $this->getInstallSteps( $installer );
1693 foreach ( $steps as $stepObj ) {
1694 $name = $stepObj[
'name'];
1695 call_user_func_array( $startCB, [ $name ] );
1698 $status = call_user_func( $stepObj[
'callback'], $installer );
1701 call_user_func( $endCB, $name, $status );
1702 $installResults[$name] = $status;
1706 if ( !$status->isOK() ) {
1712 if ( $status->isOK() ) {
1714 'config-install-db-success'
1716 $this->setVar(
'_InstallDone',
true );
1719 return $installResults;
1728 $keys = [
'wgSecretKey' => 64 ];
1729 if ( strval( $this->getVar(
'wgUpgradeKey' ) ) ===
'' ) {
1730 $keys[
'wgUpgradeKey'] = 16;
1733 return $this->doGenerateKeys(
$keys );
1741 $this->resetMediaWikiServices(
null, [
1743 return $services->get(
'UserOptionsManager' );
1746 return Status::newGood();
1756 foreach (
$keys as $name => $length ) {
1757 $secretKey = MWCryptRand::generateHex( $length );
1758 $this->setVar( $name, $secretKey );
1760 return Status::newGood();
1769 $name = $this->getVar(
'_AdminName' );
1774 return Status::newFatal(
'config-admin-error-user', $name );
1777 if ( $user->idForName() == 0 ) {
1778 $user->addToDatabase();
1780 $password = $this->getVar(
'_AdminPassword' );
1781 $status = $user->changeAuthenticationData( [
1782 'username' => $user->getName(),
1783 'password' => $password,
1784 'retype' => $password,
1786 if ( !$status->isGood() ) {
1787 return Status::newFatal(
'config-admin-error-password',
1788 $name, $status->getWikiText(
false,
false, $this->getVar(
'_UserLang' ) ) );
1791 $userGroupManager = MediaWikiServices::getInstance()->getUserGroupManager();
1792 $userGroupManager->addUserToGroup( $user,
'sysop' );
1793 $userGroupManager->addUserToGroup( $user,
'bureaucrat' );
1794 $userGroupManager->addUserToGroup( $user,
'interface-admin' );
1795 if ( $this->getVar(
'_AdminEmail' ) ) {
1796 $user->setEmail( $this->getVar(
'_AdminEmail' ) );
1798 $user->saveSettings();
1801 $ssUpdate = SiteStatsUpdate::factory( [
'users' => 1 ] );
1802 $ssUpdate->doUpdate();
1805 if ( $this->getVar(
'_Subscribe' ) && $this->getVar(
'_AdminEmail' ) ) {
1806 return $this->subscribeToMediaWikiAnnounce();
1808 return Status::newGood();
1814 private function subscribeToMediaWikiAnnounce() {
1815 $status = Status::newGood();
1816 $http = MediaWikiServices::getInstance()->getHttpRequestFactory();
1817 if ( !$http->canMakeRequests() ) {
1818 $status->warning(
'config-install-subscribe-fail',
1819 wfMessage(
'config-install-subscribe-notpossible' ) );
1824 $params = [
'email' => $this->getVar(
'_AdminEmail' ) ];
1825 $req = $http->create( self::MEDIAWIKI_ANNOUNCE_URL .
'anonymous_subscribe',
1826 [
'method' =>
'POST',
'postData' => $params ], __METHOD__ );
1829 $token = str_repeat(
'a', 64 );
1830 $req->setHeader(
'Referer', self::MEDIAWIKI_ANNOUNCE_URL );
1831 $req->setHeader(
'Cookie',
"csrftoken=$token" );
1832 $req->setHeader(
'X-CSRFToken', $token );
1835 $reqStatus = $req->execute();
1836 if ( !$reqStatus->isOK() ) {
1837 $status->warning(
'config-install-subscribe-fail',
1838 Status::wrap( $reqStatus )->getMessage() );
1847 $checkReq = $http->create( self::MEDIAWIKI_ANNOUNCE_URL, [], __METHOD__ );
1848 $checkReq->setCookieJar( $req->getCookieJar() );
1849 if ( !$checkReq->execute()->isOK() ) {
1850 $status->warning(
'config-install-subscribe-possiblefail' );
1853 $html = $checkReq->getContent();
1854 if ( strpos( $html,
'Please check your inbox for further instructions' ) !==
false ) {
1856 } elseif ( strpos( $html,
'Member already subscribed' ) !==
false ) {
1857 $status->warning(
'config-install-subscribe-alreadysubscribed' );
1858 } elseif ( strpos( $html,
'Subscription request already pending' ) !==
false ) {
1859 $status->warning(
'config-install-subscribe-alreadypending' );
1861 $status->warning(
'config-install-subscribe-possiblefail' );
1873 $status = Status::newGood();
1874 $title = Title::newMainPage();
1875 if (
$title->exists() ) {
1876 $status->warning(
'config-install-mainpage-exists' );
1880 $page = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle(
$title );
1882 wfMessage(
'mainpagetext' )->inContentLanguage()->text() .
"\n\n" .
1883 wfMessage(
'mainpagedocfooter' )->inContentLanguage()->text()
1886 $status = $page->doUserEditContent(
1892 }
catch ( Exception $e ) {
1894 $status->fatal(
'config-install-mainpage-failed', $e->getMessage() );
1908 if ( !defined(
'MW_NO_SESSION_HANDLER' ) ) {
1909 define(
'MW_NO_SESSION_HANDLER', 1 );
1915 MainConfigNames::UseDatabaseMessages =>
false,
1918 MainConfigNames::LanguageConverterCacheType =>
CACHE_NONE,
1921 MainConfigNames::ResourceLoaderUseObjectCacheForDeps =>
true,
1924 MainConfigNames::ShowExceptionDetails =>
true,
1925 MainConfigNames::ShowHostnames =>
true,
1928 MainConfigNames::ExternalLinkTarget =>
'_blank',
1931 MainConfigNames::DisableOutputCompression =>
true,
1934 MainConfigNames::CookiePrefix =>
'mw_installer',
1937 MainConfigNames::MaxShellMemory => 0,
1941 MainConfigNames::SessionProviders => [
1943 'class' => InstallerSessionProvider::class,
1954 MainConfigNames::SessionCacheType =>
CACHE_NONE,
1958 MainConfigNames::Server =>
'https://🌻.invalid',
1970 $this->extraInstallSteps[$findStep][] = $callback;
1978 AtEase::suppressWarnings();
1979 set_time_limit( 0 );
1980 AtEase::restoreWarnings();
wfDetectLocalSettingsFile(?string $installationPath=null)
Decide and remember where to load LocalSettings from.
wfDetectInstallPath()
Decide and remember where mediawiki is installed.
wfShorthandToInteger(?string $string='', int $default=-1)
Converts shorthand byte notation to integer form.
wfIsWindows()
Check if the operating system is Windows.
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
static registerClasses(array $files)
Register a file to load the given class from.
static loadFiles(array $files)
Batch version of loadFile()
static registerNamespaces(array $dirs)
Register a directory to load the classes of a given namespace from, per PSR4.
Base class for DBMS-specific installation helper classes.
getConnection()
Connect to the database using the administrative user/password currently defined in the session.
Copyright (C) 2018 Kunal Mehta legoktm@debian.org
Utility class for loading extension manifests and aggregating their contents.
The Registry loads JSON files, and uses a Processor to extract information from them.
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 the libicu version.
getDBInstaller( $type=false)
Get an instance of DatabaseInstaller for the specified DB type.
envCheckDB()
Environment check for DB types.
envCheckSuhosinMaxValueLength()
Checks if suhosin.get.max_value_length is set, and if so generate a warning because it is incompatibl...
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.
resetMediaWikiServices(Config $installerConfig=null, $serviceOverrides=[])
Reset the global service container and associated global state to accommodate different stages of the...
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.
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.
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 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 setUser( $user)
Reset the stub global user to a different "real" user object, while ensuring that any method calls on...
Represents a title within MediaWiki.
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