MediaWiki REL1_34
Installer.php
Go to the documentation of this file.
1<?php
30
46abstract class Installer {
47
54 const MINIMUM_PCRE_VERSION = '7.2';
55
59 protected $settings;
60
66 protected $compiledDBs;
67
73 protected $dbInstallers = [];
74
80 protected $minMemorySize = 50;
81
87 protected $parserTitle;
88
94 protected $parserOptions;
95
105 protected static $dbTypes = [
106 'mysql',
107 'postgres',
108 'sqlite',
109 ];
110
122 protected $envChecks = [
123 'envCheckDB',
124 'envCheckBrokenXML',
125 'envCheckPCRE',
126 'envCheckMemory',
127 'envCheckCache',
128 'envCheckModSecurity',
129 'envCheckDiff3',
130 'envCheckGraphics',
131 'envCheckGit',
132 'envCheckServer',
133 'envCheckPath',
134 'envCheckShellLocale',
135 'envCheckUploadsDirectory',
136 'envCheckLibicu',
137 'envCheckSuhosinMaxValueLength',
138 'envCheck64Bit',
139 ];
140
146 protected $envPreps = [
147 'envPrepServer',
148 'envPrepPath',
149 ];
150
158 protected $defaultVarNames = [
159 'wgSitename',
160 'wgPasswordSender',
161 'wgLanguageCode',
162 'wgRightsIcon',
163 'wgRightsText',
164 'wgRightsUrl',
165 'wgEnableEmail',
166 'wgEnableUserEmail',
167 'wgEnotifUserTalk',
168 'wgEnotifWatchlist',
169 'wgEmailAuthentication',
170 'wgDBname',
171 'wgDBtype',
172 'wgDiff3',
173 'wgImageMagickConvertCommand',
174 'wgGitBin',
175 'IP',
176 'wgScriptPath',
177 'wgMetaNamespace',
178 'wgDeletedDirectory',
179 'wgEnableUploads',
180 'wgShellLocale',
181 'wgSecretKey',
182 'wgUseInstantCommons',
183 'wgUpgradeKey',
184 'wgDefaultSkin',
185 'wgPingback',
186 ];
187
195 protected $internalDefaults = [
196 '_UserLang' => 'en',
197 '_Environment' => false,
198 '_RaiseMemory' => false,
199 '_UpgradeDone' => false,
200 '_InstallDone' => false,
201 '_Caches' => [],
202 '_InstallPassword' => '',
203 '_SameAccount' => true,
204 '_CreateDBAccount' => false,
205 '_NamespaceType' => 'site-name',
206 '_AdminName' => '', // will be set later, when the user selects language
207 '_AdminPassword' => '',
208 '_AdminPasswordConfirm' => '',
209 '_AdminEmail' => '',
210 '_Subscribe' => false,
211 '_SkipOptional' => 'continue',
212 '_RightsProfile' => 'wiki',
213 '_LicenseCode' => 'none',
214 '_CCDone' => false,
215 '_Extensions' => [],
216 '_Skins' => [],
217 '_MemCachedServers' => '',
218 '_UpgradeKeySupplied' => false,
219 '_ExistingDBSettings' => false,
220
221 // $wgLogo is probably wrong (T50084); set something that will work.
222 // Single quotes work fine here, as LocalSettingsGenerator outputs this unescaped.
223 'wgLogo' => '$wgResourceBasePath/resources/assets/wiki.png',
224 'wgAuthenticationTokenVersion' => 1,
225 ];
226
232 private $installSteps = [];
233
239 protected $extraInstallSteps = [];
240
246 protected $objectCaches = [
247 'apc' => 'apc_fetch',
248 'apcu' => 'apcu_fetch',
249 'wincache' => 'wincache_ucache_get'
250 ];
251
258 'wiki' => [],
259 'no-anon' => [
260 '*' => [ 'edit' => false ]
261 ],
262 'fishbowl' => [
263 '*' => [
264 'createaccount' => false,
265 'edit' => false,
266 ],
267 ],
268 'private' => [
269 '*' => [
270 'createaccount' => false,
271 'edit' => false,
272 'read' => false,
273 ],
274 ],
275 ];
276
282 public $licenses = [
283 'cc-by' => [
284 'url' => 'https://creativecommons.org/licenses/by/4.0/',
285 'icon' => '$wgResourceBasePath/resources/assets/licenses/cc-by.png',
286 ],
287 'cc-by-sa' => [
288 'url' => 'https://creativecommons.org/licenses/by-sa/4.0/',
289 'icon' => '$wgResourceBasePath/resources/assets/licenses/cc-by-sa.png',
290 ],
291 'cc-by-nc-sa' => [
292 'url' => 'https://creativecommons.org/licenses/by-nc-sa/4.0/',
293 'icon' => '$wgResourceBasePath/resources/assets/licenses/cc-by-nc-sa.png',
294 ],
295 'cc-0' => [
296 'url' => 'https://creativecommons.org/publicdomain/zero/1.0/',
297 'icon' => '$wgResourceBasePath/resources/assets/licenses/cc-0.png',
298 ],
299 'gfdl' => [
300 'url' => 'https://www.gnu.org/copyleft/fdl.html',
301 'icon' => '$wgResourceBasePath/resources/assets/licenses/gnu-fdl.png',
302 ],
303 'none' => [
304 'url' => '',
305 'icon' => '',
306 'text' => ''
307 ],
308 'cc-choose' => [
309 // Details will be filled in by the selector.
310 'url' => '',
311 'icon' => '',
312 'text' => '',
313 ],
314 ];
315
320 'https://lists.wikimedia.org/mailman/subscribe/mediawiki-announce';
321
326 'ca', 'cs', 'da', 'de', 'en', 'es', 'et', 'eu', 'fi', 'fr', 'hr', 'hu',
327 'it', 'ja', 'ko', 'lt', 'nl', 'no', 'pl', 'pt', 'pt-br', 'ro', 'ru',
328 'sl', 'sr', 'sv', 'tr', 'uk'
329 ];
330
339 abstract public function showMessage( $msg, ...$params );
340
346 abstract public function showError( $msg, ...$params );
347
352 abstract public function showStatusMessage( Status $status );
353
364 public static function getInstallerConfig( Config $baseConfig ) {
365 $configOverrides = new HashConfig();
366
367 // disable (problematic) object cache types explicitly, preserving all other (working) ones
368 // bug T113843
369 $emptyCache = [ 'class' => EmptyBagOStuff::class ];
370
371 $objectCaches = [
372 CACHE_NONE => $emptyCache,
373 CACHE_DB => $emptyCache,
374 CACHE_ANYTHING => $emptyCache,
375 CACHE_MEMCACHED => $emptyCache,
376 ] + $baseConfig->get( 'ObjectCaches' );
377
378 $configOverrides->set( 'ObjectCaches', $objectCaches );
379
380 // Load the installer's i18n.
381 $messageDirs = $baseConfig->get( 'MessagesDirs' );
382 $messageDirs['MediawikiInstaller'] = __DIR__ . '/i18n';
383
384 $configOverrides->set( 'MessagesDirs', $messageDirs );
385
386 $installerConfig = new MultiConfig( [ $configOverrides, $baseConfig ] );
387
388 // make sure we use the installer config as the main config
389 $configRegistry = $baseConfig->get( 'ConfigRegistry' );
390 $configRegistry['main'] = function () use ( $installerConfig ) {
391 return $installerConfig;
392 };
393
394 $configOverrides->set( 'ConfigRegistry', $configRegistry );
395
396 return $installerConfig;
397 }
398
402 public function __construct() {
403 global $wgMemc, $wgUser, $wgObjectCaches;
404
405 $defaultConfig = new GlobalVarConfig(); // all the stuff from DefaultSettings.php
406 $installerConfig = self::getInstallerConfig( $defaultConfig );
407
408 // Reset all services and inject config overrides
409 MediaWikiServices::resetGlobalInstance( $installerConfig );
410
411 // Don't attempt to load user language options (T126177)
412 // This will be overridden in the web installer with the user-specified language
413 RequestContext::getMain()->setLanguage( 'en' );
414
415 // Disable all global services, since we don't have any configuration yet!
416 MediaWikiServices::disableStorageBackend();
417
418 $mwServices = MediaWikiServices::getInstance();
419
420 // Disable i18n cache
421 $mwServices->getLocalisationCache()->disableBackend();
422
423 // Clear language cache so the old i18n cache doesn't sneak back in
424 Language::clearCaches();
425
426 // Disable object cache (otherwise CACHE_ANYTHING will try CACHE_DB and
427 // SqlBagOStuff will then throw since we just disabled wfGetDB)
428 $wgObjectCaches = $mwServices->getMainConfig()->get( 'ObjectCaches' );
429 $wgMemc = ObjectCache::getInstance( CACHE_NONE );
430
431 // Disable interwiki lookup, to avoid database access during parses
432 $mwServices->redefineService( 'InterwikiLookup', function () {
433 return new NullInterwikiLookup();
434 } );
435
436 // Having a user with id = 0 safeguards us from DB access via User::loadOptions().
437 $wgUser = User::newFromId( 0 );
438 RequestContext::getMain()->setUser( $wgUser );
439
440 $this->settings = $this->internalDefaults;
441
442 foreach ( $this->defaultVarNames as $var ) {
443 $this->settings[$var] = $GLOBALS[$var];
444 }
445
446 $this->doEnvironmentPreps();
447
448 $this->compiledDBs = [];
449 foreach ( self::getDBTypes() as $type ) {
450 $installer = $this->getDBInstaller( $type );
451
452 if ( !$installer->isCompiled() ) {
453 continue;
454 }
455 $this->compiledDBs[] = $type;
456 }
457
458 $this->parserTitle = Title::newFromText( 'Installer' );
459 $this->parserOptions = new ParserOptions( $wgUser ); // language will be wrong :(
460 $this->parserOptions->setTidy( true );
461 // Don't try to access DB before user language is initialised
462 $this->setParserLanguage( Language::factory( 'en' ) );
463 }
464
470 public static function getDBTypes() {
471 return self::$dbTypes;
472 }
473
487 public function doEnvironmentChecks() {
488 // Php version has already been checked by entry scripts
489 // Show message here for information purposes
490 if ( wfIsHHVM() ) {
491 $this->showMessage( 'config-env-hhvm', HHVM_VERSION );
492 } else {
493 $this->showMessage( 'config-env-php', PHP_VERSION );
494 }
495
496 $good = true;
497 // Must go here because an old version of PCRE can prevent other checks from completing
498 $pcreVersion = explode( ' ', PCRE_VERSION, 2 )[0];
499 if ( version_compare( $pcreVersion, self::MINIMUM_PCRE_VERSION, '<' ) ) {
500 $this->showError( 'config-pcre-old', self::MINIMUM_PCRE_VERSION, $pcreVersion );
501 $good = false;
502 } else {
503 foreach ( $this->envChecks as $check ) {
504 $status = $this->$check();
505 if ( $status === false ) {
506 $good = false;
507 }
508 }
509 }
510
511 $this->setVar( '_Environment', $good );
512
513 return $good ? Status::newGood() : Status::newFatal( 'config-env-bad' );
514 }
515
516 public function doEnvironmentPreps() {
517 foreach ( $this->envPreps as $prep ) {
518 $this->$prep();
519 }
520 }
521
528 public function setVar( $name, $value ) {
529 $this->settings[$name] = $value;
530 }
531
542 public function getVar( $name, $default = null ) {
543 return $this->settings[$name] ?? $default;
544 }
545
551 public function getCompiledDBs() {
552 return $this->compiledDBs;
553 }
554
562 public static function getDBInstallerClass( $type ) {
563 return ucfirst( $type ) . 'Installer';
564 }
565
573 public function getDBInstaller( $type = false ) {
574 if ( !$type ) {
575 $type = $this->getVar( 'wgDBtype' );
576 }
577
578 $type = strtolower( $type );
579
580 if ( !isset( $this->dbInstallers[$type] ) ) {
582 $this->dbInstallers[$type] = new $class( $this );
583 }
584
585 return $this->dbInstallers[$type];
586 }
587
593 public static function getExistingLocalSettings() {
594 global $IP;
595
596 // You might be wondering why this is here. Well if you don't do this
597 // then some poorly-formed extensions try to call their own classes
598 // after immediately registering them. We really need to get extension
599 // registration out of the global scope and into a real format.
600 // @see https://phabricator.wikimedia.org/T69440
601 global $wgAutoloadClasses;
603
604 // LocalSettings.php should not call functions, except wfLoadSkin/wfLoadExtensions
605 // Define the required globals here, to ensure, the functions can do it work correctly.
606 // phpcs:ignore MediaWiki.VariableAnalysis.UnusedGlobalVariables
608
609 Wikimedia\suppressWarnings();
610 $_lsExists = file_exists( "$IP/LocalSettings.php" );
611 Wikimedia\restoreWarnings();
612
613 if ( !$_lsExists ) {
614 return false;
615 }
616 unset( $_lsExists );
617
618 require "$IP/includes/DefaultSettings.php";
619 require "$IP/LocalSettings.php";
620
621 return get_defined_vars();
622 }
623
633 public function getFakePassword( $realPassword ) {
634 return str_repeat( '*', strlen( $realPassword ) );
635 }
636
644 public function setPassword( $name, $value ) {
645 if ( !preg_match( '/^\*+$/', $value ) ) {
646 $this->setVar( $name, $value );
647 }
648 }
649
661 public static function maybeGetWebserverPrimaryGroup() {
662 if ( !function_exists( 'posix_getegid' ) || !function_exists( 'posix_getpwuid' ) ) {
663 # I don't know this, this isn't UNIX.
664 return null;
665 }
666
667 # posix_getegid() *not* getmygid() because we want the group of the webserver,
668 # not whoever owns the current script.
669 $gid = posix_getegid();
670 $group = posix_getpwuid( $gid )['name'];
671
672 return $group;
673 }
674
691 public function parse( $text, $lineStart = false ) {
692 $parser = MediaWikiServices::getInstance()->getParser();
693
694 try {
695 $out = $parser->parse( $text, $this->parserTitle, $this->parserOptions, $lineStart );
696 $html = $out->getText( [
697 'enableSectionEditLinks' => false,
698 'unwrap' => true,
699 ] );
700 $html = Parser::stripOuterParagraph( $html );
701 } catch ( Wikimedia\Services\ServiceDisabledException $e ) {
702 $html = '<!--DB access attempted during parse--> ' . htmlspecialchars( $text );
703 }
704
705 return $html;
706 }
707
711 public function getParserOptions() {
713 }
714
715 public function disableLinkPopups() {
716 $this->parserOptions->setExternalLinkTarget( false );
717 }
718
719 public function restoreLinkPopups() {
721 $this->parserOptions->setExternalLinkTarget( $wgExternalLinkTarget );
722 }
723
732 public function populateSiteStats( DatabaseInstaller $installer ) {
733 $status = $installer->getConnection();
734 if ( !$status->isOK() ) {
735 return $status;
736 }
737 // @phan-suppress-next-line PhanUndeclaredMethod
738 $status->value->insert(
739 'site_stats',
740 [
741 'ss_row_id' => 1,
742 'ss_total_edits' => 0,
743 'ss_good_articles' => 0,
744 'ss_total_pages' => 0,
745 'ss_users' => 0,
746 'ss_active_users' => 0,
747 'ss_images' => 0
748 ],
749 __METHOD__, 'IGNORE'
750 );
751
752 return Status::newGood();
753 }
754
759 protected function envCheckDB() {
760 global $wgLang;
762 $dbType = $this->getVar( 'wgDBtype' );
763
764 $allNames = [];
765
766 // Messages: config-type-mysql, config-type-postgres, config-type-sqlite
767 foreach ( self::getDBTypes() as $name ) {
768 $allNames[] = wfMessage( "config-type-$name" )->text();
769 }
770
771 $databases = $this->getCompiledDBs();
772
773 $databases = array_flip( $databases );
774 $ok = true;
775 foreach ( array_keys( $databases ) as $db ) {
776 $installer = $this->getDBInstaller( $db );
777 $status = $installer->checkPrerequisites();
778 if ( !$status->isGood() ) {
779 if ( !$this instanceof WebInstaller && $db === $dbType ) {
780 // Strictly check the key database type instead of just outputting message
781 // Note: No perform this check run from the web installer, since this method always called by
782 // the welcome page under web installation, so $dbType will always be 'mysql'
783 $ok = false;
784 }
785 $this->showStatusMessage( $status );
786 unset( $databases[$db] );
787 }
788 }
789 $databases = array_flip( $databases );
790 if ( !$databases ) {
791 $this->showError( 'config-no-db', $wgLang->commaList( $allNames ), count( $allNames ) );
792 return false;
793 }
794 return $ok;
795 }
796
801 protected function envCheckBrokenXML() {
802 $test = new PhpXmlBugTester();
803 if ( !$test->ok ) {
804 $this->showError( 'config-brokenlibxml' );
805
806 return false;
807 }
808
809 return true;
810 }
811
820 protected function envCheckPCRE() {
821 Wikimedia\suppressWarnings();
822 $regexd = preg_replace( '/[\x{0430}-\x{04FF}]/iu', '', '-АБВГД-' );
823 // Need to check for \p support too, as PCRE can be compiled
824 // with utf8 support, but not unicode property support.
825 // check that \p{Zs} (space separators) matches
826 // U+3000 (Ideographic space)
827 $regexprop = preg_replace( '/\p{Zs}/u', '', "-\u{3000}-" );
828 Wikimedia\restoreWarnings();
829 if ( $regexd != '--' || $regexprop != '--' ) {
830 $this->showError( 'config-pcre-no-utf8' );
831
832 return false;
833 }
834
835 return true;
836 }
837
842 protected function envCheckMemory() {
843 $limit = ini_get( 'memory_limit' );
844
845 if ( !$limit || $limit == -1 ) {
846 return true;
847 }
848
849 $n = wfShorthandToInteger( $limit );
850
851 if ( $n < $this->minMemorySize * 1024 * 1024 ) {
852 $newLimit = "{$this->minMemorySize}M";
853
854 if ( ini_set( "memory_limit", $newLimit ) === false ) {
855 $this->showMessage( 'config-memory-bad', $limit );
856 } else {
857 $this->showMessage( 'config-memory-raised', $limit, $newLimit );
858 $this->setVar( '_RaiseMemory', true );
859 }
860 }
861
862 return true;
863 }
864
868 protected function envCheckCache() {
869 $caches = [];
870 foreach ( $this->objectCaches as $name => $function ) {
871 if ( function_exists( $function ) ) {
872 $caches[$name] = true;
873 }
874 }
875
876 if ( !$caches ) {
877 $this->showMessage( 'config-no-cache-apcu' );
878 }
879
880 $this->setVar( '_Caches', $caches );
881 }
882
887 protected function envCheckModSecurity() {
888 if ( self::apacheModulePresent( 'mod_security' )
889 || self::apacheModulePresent( 'mod_security2' ) ) {
890 $this->showMessage( 'config-mod-security' );
891 }
892
893 return true;
894 }
895
900 protected function envCheckDiff3() {
901 $names = [ "gdiff3", "diff3" ];
902 if ( wfIsWindows() ) {
903 $names[] = 'diff3.exe';
904 }
905 $versionInfo = [ '--version', 'GNU diffutils' ];
906
907 $diff3 = ExecutableFinder::findInDefaultPaths( $names, $versionInfo );
908
909 if ( $diff3 ) {
910 $this->setVar( 'wgDiff3', $diff3 );
911 } else {
912 $this->setVar( 'wgDiff3', false );
913 $this->showMessage( 'config-diff3-bad' );
914 }
915
916 return true;
917 }
918
923 protected function envCheckGraphics() {
924 $names = wfIsWindows() ? 'convert.exe' : 'convert';
925 $versionInfo = [ '-version', 'ImageMagick' ];
926 $convert = ExecutableFinder::findInDefaultPaths( $names, $versionInfo );
927
928 $this->setVar( 'wgImageMagickConvertCommand', '' );
929 if ( $convert ) {
930 $this->setVar( 'wgImageMagickConvertCommand', $convert );
931 $this->showMessage( 'config-imagemagick', $convert );
932
933 return true;
934 } elseif ( function_exists( 'imagejpeg' ) ) {
935 $this->showMessage( 'config-gd' );
936 } else {
937 $this->showMessage( 'config-no-scaling' );
938 }
939
940 return true;
941 }
942
949 protected function envCheckGit() {
950 $names = wfIsWindows() ? 'git.exe' : 'git';
951 $versionInfo = [ '--version', 'git version' ];
952
953 $git = ExecutableFinder::findInDefaultPaths( $names, $versionInfo );
954
955 if ( $git ) {
956 $this->setVar( 'wgGitBin', $git );
957 $this->showMessage( 'config-git', $git );
958 } else {
959 $this->setVar( 'wgGitBin', false );
960 $this->showMessage( 'config-git-bad' );
961 }
962
963 return true;
964 }
965
971 protected function envCheckServer() {
972 $server = $this->envGetDefaultServer();
973 if ( $server !== null ) {
974 $this->showMessage( 'config-using-server', $server );
975 }
976 return true;
977 }
978
984 protected function envCheckPath() {
985 $this->showMessage(
986 'config-using-uri',
987 $this->getVar( 'wgServer' ),
988 $this->getVar( 'wgScriptPath' )
989 );
990 return true;
991 }
992
997 protected function envCheckShellLocale() {
998 $os = php_uname( 's' );
999 $supported = [ 'Linux', 'SunOS', 'HP-UX', 'Darwin' ]; # Tested these
1000
1001 if ( !in_array( $os, $supported ) ) {
1002 return true;
1003 }
1004
1005 if ( Shell::isDisabled() ) {
1006 return true;
1007 }
1008
1009 # Get a list of available locales.
1010 $result = Shell::command( '/usr/bin/locale', '-a' )
1011 ->execute();
1012
1013 if ( $result->getExitCode() != 0 ) {
1014 return true;
1015 }
1016
1017 $lines = $result->getStdout();
1018 $lines = array_map( 'trim', explode( "\n", $lines ) );
1019 $candidatesByLocale = [];
1020 $candidatesByLang = [];
1021 foreach ( $lines as $line ) {
1022 if ( $line === '' ) {
1023 continue;
1024 }
1025
1026 if ( !preg_match( '/^([a-zA-Z]+)(_[a-zA-Z]+|)\.(utf8|UTF-8)(@[a-zA-Z_]*|)$/i', $line, $m ) ) {
1027 continue;
1028 }
1029
1030 list( , $lang, , , ) = $m;
1031
1032 $candidatesByLocale[$m[0]] = $m;
1033 $candidatesByLang[$lang][] = $m;
1034 }
1035
1036 # Try the current value of LANG.
1037 if ( isset( $candidatesByLocale[getenv( 'LANG' )] ) ) {
1038 $this->setVar( 'wgShellLocale', getenv( 'LANG' ) );
1039
1040 return true;
1041 }
1042
1043 # Try the most common ones.
1044 $commonLocales = [ 'C.UTF-8', 'en_US.UTF-8', 'en_US.utf8', 'de_DE.UTF-8', 'de_DE.utf8' ];
1045 foreach ( $commonLocales as $commonLocale ) {
1046 if ( isset( $candidatesByLocale[$commonLocale] ) ) {
1047 $this->setVar( 'wgShellLocale', $commonLocale );
1048
1049 return true;
1050 }
1051 }
1052
1053 # Is there an available locale in the Wiki's language?
1054 $wikiLang = $this->getVar( 'wgLanguageCode' );
1055
1056 if ( isset( $candidatesByLang[$wikiLang] ) ) {
1057 $m = reset( $candidatesByLang[$wikiLang] );
1058 $this->setVar( 'wgShellLocale', $m[0] );
1059
1060 return true;
1061 }
1062
1063 # Are there any at all?
1064 if ( count( $candidatesByLocale ) ) {
1065 $m = reset( $candidatesByLocale );
1066 $this->setVar( 'wgShellLocale', $m[0] );
1067
1068 return true;
1069 }
1070
1071 # Give up.
1072 return true;
1073 }
1074
1079 protected function envCheckUploadsDirectory() {
1080 global $IP;
1081
1082 $dir = $IP . '/images/';
1083 $url = $this->getVar( 'wgServer' ) . $this->getVar( 'wgScriptPath' ) . '/images/';
1084 $safe = !$this->dirIsExecutable( $dir, $url );
1085
1086 if ( !$safe ) {
1087 $this->showMessage( 'config-uploads-not-safe', $dir );
1088 }
1089
1090 return true;
1091 }
1092
1098 protected function envCheckSuhosinMaxValueLength() {
1099 $currentValue = ini_get( 'suhosin.get.max_value_length' );
1100 $minRequired = 2000;
1101 $recommended = 5000;
1102 if ( $currentValue > 0 && $currentValue < $minRequired ) {
1103 $this->showError( 'config-suhosin-max-value-length', $currentValue, $minRequired, $recommended );
1104 return false;
1105 }
1106
1107 return true;
1108 }
1109
1116 protected function envCheck64Bit() {
1117 if ( PHP_INT_SIZE == 4 ) {
1118 $this->showMessage( 'config-using-32bit' );
1119 }
1120
1121 return true;
1122 }
1123
1127 protected function envCheckLibicu() {
1135 $not_normal_c = "\u{FA6C}";
1136 $normal_c = "\u{242EE}";
1137
1138 $useNormalizer = 'php';
1139 $needsUpdate = false;
1140
1141 if ( function_exists( 'normalizer_normalize' ) ) {
1142 $useNormalizer = 'intl';
1143 $intl = normalizer_normalize( $not_normal_c, Normalizer::FORM_C );
1144 if ( $intl !== $normal_c ) {
1145 $needsUpdate = true;
1146 }
1147 }
1148
1149 // Uses messages 'config-unicode-using-php' and 'config-unicode-using-intl'
1150 if ( $useNormalizer === 'php' ) {
1151 $this->showMessage( 'config-unicode-pure-php-warning' );
1152 } else {
1153 $this->showMessage( 'config-unicode-using-' . $useNormalizer );
1154 if ( $needsUpdate ) {
1155 $this->showMessage( 'config-unicode-update-warning' );
1156 }
1157 }
1158 }
1159
1163 protected function envPrepServer() {
1164 $server = $this->envGetDefaultServer();
1165 if ( $server !== null ) {
1166 $this->setVar( 'wgServer', $server );
1167 }
1168 }
1169
1174 abstract protected function envGetDefaultServer();
1175
1179 protected function envPrepPath() {
1180 global $IP;
1181 $IP = dirname( dirname( __DIR__ ) );
1182 $this->setVar( 'IP', $IP );
1183 }
1184
1193 public function dirIsExecutable( $dir, $url ) {
1194 $scriptTypes = [
1195 'php' => [
1196 "<?php echo 'exec';",
1197 "#!/var/env php\n<?php echo 'exec';",
1198 ],
1199 ];
1200
1201 // it would be good to check other popular languages here, but it'll be slow.
1202
1203 Wikimedia\suppressWarnings();
1204
1205 foreach ( $scriptTypes as $ext => $contents ) {
1206 foreach ( $contents as $source ) {
1207 $file = 'exectest.' . $ext;
1208
1209 if ( !file_put_contents( $dir . $file, $source ) ) {
1210 break;
1211 }
1212
1213 try {
1214 $text = MediaWikiServices::getInstance()->getHttpRequestFactory()->
1215 get( $url . $file, [ 'timeout' => 3 ], __METHOD__ );
1216 } catch ( Exception $e ) {
1217 // HttpRequestFactory::get can throw with allow_url_fopen = false and no curl
1218 // extension.
1219 $text = null;
1220 }
1221 unlink( $dir . $file );
1222
1223 if ( $text == 'exec' ) {
1224 Wikimedia\restoreWarnings();
1225
1226 return $ext;
1227 }
1228 }
1229 }
1230
1231 Wikimedia\restoreWarnings();
1232
1233 return false;
1234 }
1235
1242 public static function apacheModulePresent( $moduleName ) {
1243 if ( function_exists( 'apache_get_modules' ) && in_array( $moduleName, apache_get_modules() ) ) {
1244 return true;
1245 }
1246 // try it the hard way
1247 ob_start();
1248 phpinfo( INFO_MODULES );
1249 $info = ob_get_clean();
1250
1251 return strpos( $info, $moduleName ) !== false;
1252 }
1253
1259 public function setParserLanguage( $lang ) {
1260 $this->parserOptions->setTargetLanguage( $lang );
1261 $this->parserOptions->setUserLang( $lang );
1262 }
1263
1269 protected function getDocUrl( $page ) {
1270 return "{$_SERVER['PHP_SELF']}?page=" . urlencode( $page );
1271 }
1272
1282 public function findExtensions( $directory = 'extensions' ) {
1283 switch ( $directory ) {
1284 case 'extensions':
1285 return $this->findExtensionsByType( 'extension', 'extensions' );
1286 case 'skins':
1287 return $this->findExtensionsByType( 'skin', 'skins' );
1288 default:
1289 throw new InvalidArgumentException( "Invalid extension type" );
1290 }
1291 }
1292
1302 protected function findExtensionsByType( $type = 'extension', $directory = 'extensions' ) {
1303 if ( $this->getVar( 'IP' ) === null ) {
1304 return Status::newGood( [] );
1305 }
1306
1307 $extDir = $this->getVar( 'IP' ) . '/' . $directory;
1308 if ( !is_readable( $extDir ) || !is_dir( $extDir ) ) {
1309 return Status::newGood( [] );
1310 }
1311
1312 $dh = opendir( $extDir );
1313 $exts = [];
1314 $status = new Status;
1315 while ( ( $file = readdir( $dh ) ) !== false ) {
1316 // skip non-dirs and hidden directories
1317 if ( !is_dir( "$extDir/$file" ) || $file[0] === '.' ) {
1318 continue;
1319 }
1320 $extStatus = $this->getExtensionInfo( $type, $directory, $file );
1321 if ( $extStatus->isOK() ) {
1322 $exts[$file] = $extStatus->value;
1323 } elseif ( $extStatus->hasMessage( 'config-extension-not-found' ) ) {
1324 // (T225512) The directory is not actually an extension. Downgrade to warning.
1325 $status->warning( 'config-extension-not-found', $file );
1326 } else {
1327 $status->merge( $extStatus );
1328 }
1329 }
1330 closedir( $dh );
1331 uksort( $exts, 'strnatcasecmp' );
1332
1333 $status->value = $exts;
1334
1335 return $status;
1336 }
1337
1345 protected function getExtensionInfo( $type, $parentRelPath, $name ) {
1346 if ( $this->getVar( 'IP' ) === null ) {
1347 throw new Exception( 'Cannot find extensions since the IP variable is not yet set' );
1348 }
1349 if ( $type !== 'extension' && $type !== 'skin' ) {
1350 throw new InvalidArgumentException( "Invalid extension type" );
1351 }
1352 $absDir = $this->getVar( 'IP' ) . "/$parentRelPath/$name";
1353 $relDir = "../$parentRelPath/$name";
1354 if ( !is_dir( $absDir ) ) {
1355 return Status::newFatal( 'config-extension-not-found', $name );
1356 }
1357 $jsonFile = $type . '.json';
1358 $fullJsonFile = "$absDir/$jsonFile";
1359 $isJson = file_exists( $fullJsonFile );
1360 $isPhp = false;
1361 if ( !$isJson ) {
1362 // Only fallback to PHP file if JSON doesn't exist
1363 $fullPhpFile = "$absDir/$name.php";
1364 $isPhp = file_exists( $fullPhpFile );
1365 }
1366 if ( !$isJson && !$isPhp ) {
1367 return Status::newFatal( 'config-extension-not-found', $name );
1368 }
1369
1370 // Extension exists. Now see if there are screenshots
1371 $info = [];
1372 if ( is_dir( "$absDir/screenshots" ) ) {
1373 $paths = glob( "$absDir/screenshots/*.png" );
1374 foreach ( $paths as $path ) {
1375 $info['screenshots'][] = str_replace( $absDir, $relDir, $path );
1376 }
1377 }
1378
1379 if ( $isJson ) {
1380 $jsonStatus = $this->readExtension( $fullJsonFile );
1381 if ( !$jsonStatus->isOK() ) {
1382 return $jsonStatus;
1383 }
1384 $info += $jsonStatus->value;
1385 }
1386
1387 return Status::newGood( $info );
1388 }
1389
1398 private function readExtension( $fullJsonFile, $extDeps = [], $skinDeps = [] ) {
1399 $load = [
1400 $fullJsonFile => 1
1401 ];
1402 if ( $extDeps ) {
1403 $extDir = $this->getVar( 'IP' ) . '/extensions';
1404 foreach ( $extDeps as $dep ) {
1405 $fname = "$extDir/$dep/extension.json";
1406 if ( !file_exists( $fname ) ) {
1407 return Status::newFatal( 'config-extension-not-found', $dep );
1408 }
1409 $load[$fname] = 1;
1410 }
1411 }
1412 if ( $skinDeps ) {
1413 $skinDir = $this->getVar( 'IP' ) . '/skins';
1414 foreach ( $skinDeps as $dep ) {
1415 $fname = "$skinDir/$dep/skin.json";
1416 if ( !file_exists( $fname ) ) {
1417 return Status::newFatal( 'config-extension-not-found', $dep );
1418 }
1419 $load[$fname] = 1;
1420 }
1421 }
1422 $registry = new ExtensionRegistry();
1423 try {
1424 $info = $registry->readFromQueue( $load );
1425 } catch ( ExtensionDependencyError $e ) {
1426 if ( $e->incompatibleCore || $e->incompatibleSkins
1427 || $e->incompatibleExtensions
1428 ) {
1429 // If something is incompatible with a dependency, we have no real
1430 // option besides skipping it
1431 return Status::newFatal( 'config-extension-dependency',
1432 basename( dirname( $fullJsonFile ) ), $e->getMessage() );
1433 } elseif ( $e->missingExtensions || $e->missingSkins ) {
1434 // There's an extension missing in the dependency tree,
1435 // so add those to the dependency list and try again
1436 $status = $this->readExtension(
1437 $fullJsonFile,
1438 array_merge( $extDeps, $e->missingExtensions ),
1439 array_merge( $skinDeps, $e->missingSkins )
1440 );
1441 if ( !$status->isOK() && !$status->hasMessage( 'config-extension-dependency' ) ) {
1442 $status = Status::newFatal( 'config-extension-dependency',
1443 basename( dirname( $fullJsonFile ) ), $status->getMessage() );
1444 }
1445 return $status;
1446 }
1447 // Some other kind of dependency error?
1448 return Status::newFatal( 'config-extension-dependency',
1449 basename( dirname( $fullJsonFile ) ), $e->getMessage() );
1450 }
1451 $ret = [];
1452 // The order of credits will be the order of $load,
1453 // so the first extension is the one we want to load,
1454 // everything else is a dependency
1455 $i = 0;
1456 foreach ( $info['credits'] as $name => $credit ) {
1457 $i++;
1458 if ( $i == 1 ) {
1459 // Extension we want to load
1460 continue;
1461 }
1462 $type = basename( $credit['path'] ) === 'skin.json' ? 'skins' : 'extensions';
1463 $ret['requires'][$type][] = $credit['name'];
1464 }
1465 $credits = array_values( $info['credits'] )[0];
1466 if ( isset( $credits['url'] ) ) {
1467 $ret['url'] = $credits['url'];
1468 }
1469 $ret['type'] = $credits['type'];
1470
1471 return Status::newGood( $ret );
1472 }
1473
1482 public function getDefaultSkin( array $skinNames ) {
1483 $defaultSkin = $GLOBALS['wgDefaultSkin'];
1484 if ( !$skinNames || in_array( $defaultSkin, $skinNames ) ) {
1485 return $defaultSkin;
1486 } else {
1487 return $skinNames[0];
1488 }
1489 }
1490
1497 protected function includeExtensions() {
1498 global $IP;
1499 $exts = $this->getVar( '_Extensions' );
1500 $IP = $this->getVar( 'IP' );
1501
1502 // Marker for DatabaseUpdater::loadExtensions so we don't
1503 // double load extensions
1504 define( 'MW_EXTENSIONS_LOADED', true );
1505
1514 global $wgAutoloadClasses;
1515 $wgAutoloadClasses = [];
1516 $queue = [];
1517
1518 require "$IP/includes/DefaultSettings.php";
1519
1520 foreach ( $exts as $e ) {
1521 if ( file_exists( "$IP/extensions/$e/extension.json" ) ) {
1522 $queue["$IP/extensions/$e/extension.json"] = 1;
1523 } else {
1524 require_once "$IP/extensions/$e/$e.php";
1525 }
1526 }
1527
1528 $registry = new ExtensionRegistry();
1529 $data = $registry->readFromQueue( $queue );
1530 $wgAutoloadClasses += $data['autoload'];
1531
1532 // @phan-suppress-next-line PhanUndeclaredVariable $wgHooks is set by DefaultSettings
1533 $hooksWeWant = $wgHooks['LoadExtensionSchemaUpdates'] ?? [];
1534
1535 if ( isset( $data['globals']['wgHooks']['LoadExtensionSchemaUpdates'] ) ) {
1536 $hooksWeWant = array_merge_recursive(
1537 $hooksWeWant,
1538 $data['globals']['wgHooks']['LoadExtensionSchemaUpdates']
1539 );
1540 }
1541 // Unset everyone else's hooks. Lord knows what someone might be doing
1542 // in ParserFirstCallInit (see T29171)
1543 $GLOBALS['wgHooks'] = [ 'LoadExtensionSchemaUpdates' => $hooksWeWant ];
1544
1545 return Status::newGood();
1546 }
1547
1560 protected function getInstallSteps( DatabaseInstaller $installer ) {
1561 $coreInstallSteps = [
1562 [ 'name' => 'database', 'callback' => [ $installer, 'setupDatabase' ] ],
1563 [ 'name' => 'tables', 'callback' => [ $installer, 'createTables' ] ],
1564 [ 'name' => 'interwiki', 'callback' => [ $installer, 'populateInterwikiTable' ] ],
1565 [ 'name' => 'stats', 'callback' => [ $this, 'populateSiteStats' ] ],
1566 [ 'name' => 'keys', 'callback' => [ $this, 'generateKeys' ] ],
1567 [ 'name' => 'updates', 'callback' => [ $installer, 'insertUpdateKeys' ] ],
1568 [ 'name' => 'sysop', 'callback' => [ $this, 'createSysop' ] ],
1569 [ 'name' => 'mainpage', 'callback' => [ $this, 'createMainpage' ] ],
1570 ];
1571
1572 // Build the array of install steps starting from the core install list,
1573 // then adding any callbacks that wanted to attach after a given step
1574 foreach ( $coreInstallSteps as $step ) {
1575 $this->installSteps[] = $step;
1576 if ( isset( $this->extraInstallSteps[$step['name']] ) ) {
1577 $this->installSteps = array_merge(
1578 $this->installSteps,
1579 $this->extraInstallSteps[$step['name']]
1580 );
1581 }
1582 }
1583
1584 // Prepend any steps that want to be at the beginning
1585 if ( isset( $this->extraInstallSteps['BEGINNING'] ) ) {
1586 $this->installSteps = array_merge(
1587 $this->extraInstallSteps['BEGINNING'],
1588 $this->installSteps
1589 );
1590 }
1591
1592 // Extensions should always go first, chance to tie into hooks and such
1593 if ( count( $this->getVar( '_Extensions' ) ) ) {
1594 array_unshift( $this->installSteps,
1595 [ 'name' => 'extensions', 'callback' => [ $this, 'includeExtensions' ] ]
1596 );
1597 $this->installSteps[] = [
1598 'name' => 'extension-tables',
1599 'callback' => [ $installer, 'createExtensionTables' ]
1600 ];
1601 }
1602
1603 return $this->installSteps;
1604 }
1605
1614 public function performInstallation( $startCB, $endCB ) {
1615 $installResults = [];
1616 $installer = $this->getDBInstaller();
1617 $installer->preInstall();
1618 $steps = $this->getInstallSteps( $installer );
1619 foreach ( $steps as $stepObj ) {
1620 $name = $stepObj['name'];
1621 call_user_func_array( $startCB, [ $name ] );
1622
1623 // Perform the callback step
1624 $status = call_user_func( $stepObj['callback'], $installer );
1625
1626 // Output and save the results
1627 call_user_func( $endCB, $name, $status );
1628 $installResults[$name] = $status;
1629
1630 // If we've hit some sort of fatal, we need to bail.
1631 // Callback already had a chance to do output above.
1632 if ( !$status->isOK() ) {
1633 break;
1634 }
1635 }
1636 if ( $status->isOK() ) {
1637 $this->showMessage(
1638 'config-install-db-success'
1639 );
1640 $this->setVar( '_InstallDone', true );
1641 }
1642
1643 return $installResults;
1644 }
1645
1651 public function generateKeys() {
1652 $keys = [ 'wgSecretKey' => 64 ];
1653 if ( strval( $this->getVar( 'wgUpgradeKey' ) ) === '' ) {
1654 $keys['wgUpgradeKey'] = 16;
1655 }
1656
1657 return $this->doGenerateKeys( $keys );
1658 }
1659
1666 protected function doGenerateKeys( $keys ) {
1667 $status = Status::newGood();
1668
1669 foreach ( $keys as $name => $length ) {
1670 $secretKey = MWCryptRand::generateHex( $length );
1671 $this->setVar( $name, $secretKey );
1672 }
1673
1674 return $status;
1675 }
1676
1682 protected function createSysop() {
1683 $name = $this->getVar( '_AdminName' );
1684 $user = User::newFromName( $name );
1685
1686 if ( !$user ) {
1687 // We should've validated this earlier anyway!
1688 return Status::newFatal( 'config-admin-error-user', $name );
1689 }
1690
1691 if ( $user->idForName() == 0 ) {
1692 $user->addToDatabase();
1693
1694 try {
1695 $user->setPassword( $this->getVar( '_AdminPassword' ) );
1696 } catch ( PasswordError $pwe ) {
1697 return Status::newFatal( 'config-admin-error-password', $name, $pwe->getMessage() );
1698 }
1699
1700 $user->addGroup( 'sysop' );
1701 $user->addGroup( 'bureaucrat' );
1702 $user->addGroup( 'interface-admin' );
1703 if ( $this->getVar( '_AdminEmail' ) ) {
1704 $user->setEmail( $this->getVar( '_AdminEmail' ) );
1705 }
1706 $user->saveSettings();
1707
1708 // Update user count
1709 $ssUpdate = SiteStatsUpdate::factory( [ 'users' => 1 ] );
1710 $ssUpdate->doUpdate();
1711 }
1712 $status = Status::newGood();
1713
1714 if ( $this->getVar( '_Subscribe' ) && $this->getVar( '_AdminEmail' ) ) {
1715 $this->subscribeToMediaWikiAnnounce( $status );
1716 }
1717
1718 return $status;
1719 }
1720
1725 $params = [
1726 'email' => $this->getVar( '_AdminEmail' ),
1727 'language' => 'en',
1728 'digest' => 0
1729 ];
1730
1731 // Mailman doesn't support as many languages as we do, so check to make
1732 // sure their selected language is available
1733 $myLang = $this->getVar( '_UserLang' );
1734 if ( in_array( $myLang, $this->mediaWikiAnnounceLanguages ) ) {
1735 $myLang = $myLang == 'pt-br' ? 'pt_BR' : $myLang; // rewrite to Mailman's pt_BR
1736 $params['language'] = $myLang;
1737 }
1738
1739 if ( MWHttpRequest::canMakeRequests() ) {
1740 $res = MWHttpRequest::factory( $this->mediaWikiAnnounceUrl,
1741 [ 'method' => 'POST', 'postData' => $params ], __METHOD__ )->execute();
1742 if ( !$res->isOK() ) {
1743 $s->warning( 'config-install-subscribe-fail', $res->getMessage() );
1744 }
1745 } else {
1746 $s->warning( 'config-install-subscribe-notpossible' );
1747 }
1748 }
1749
1756 protected function createMainpage( DatabaseInstaller $installer ) {
1757 $status = Status::newGood();
1758 $title = Title::newMainPage();
1759 if ( $title->exists() ) {
1760 $status->warning( 'config-install-mainpage-exists' );
1761 return $status;
1762 }
1763 try {
1764 $page = WikiPage::factory( $title );
1766 wfMessage( 'mainpagetext' )->inContentLanguage()->text() . "\n\n" .
1767 wfMessage( 'mainpagedocfooter' )->inContentLanguage()->text()
1768 );
1769
1770 $status = $page->doEditContent( $content,
1771 '',
1772 EDIT_NEW,
1773 false,
1774 User::newSystemUser( 'MediaWiki default' )
1775 );
1776 } catch ( Exception $e ) {
1777 // using raw, because $wgShowExceptionDetails can not be set yet
1778 $status->fatal( 'config-install-mainpage-failed', $e->getMessage() );
1779 }
1780
1781 return $status;
1782 }
1783
1787 public static function overrideConfig() {
1788 // Use PHP's built-in session handling, since MediaWiki's
1789 // SessionHandler can't work before we have an object cache set up.
1790 if ( !defined( 'MW_NO_SESSION_HANDLER' ) ) {
1791 define( 'MW_NO_SESSION_HANDLER', 1 );
1792 }
1793
1794 // Don't access the database
1795 $GLOBALS['wgUseDatabaseMessages'] = false;
1796 // Don't cache langconv tables
1797 $GLOBALS['wgLanguageConverterCacheType'] = CACHE_NONE;
1798 // Debug-friendly
1799 $GLOBALS['wgShowExceptionDetails'] = true;
1800 $GLOBALS['wgShowHostnames'] = true;
1801 // Don't break forms
1802 $GLOBALS['wgExternalLinkTarget'] = '_blank';
1803
1804 // Allow multiple ob_flush() calls
1805 $GLOBALS['wgDisableOutputCompression'] = true;
1806
1807 // Use a sensible cookie prefix (not my_wiki)
1808 $GLOBALS['wgCookiePrefix'] = 'mw_installer';
1809
1810 // Some of the environment checks make shell requests, remove limits
1811 $GLOBALS['wgMaxShellMemory'] = 0;
1812
1813 // Override the default CookieSessionProvider with a dummy
1814 // implementation that won't stomp on PHP's cookies.
1815 $GLOBALS['wgSessionProviders'] = [
1816 [
1817 'class' => InstallerSessionProvider::class,
1818 'args' => [ [
1819 'priority' => 1,
1820 ] ]
1821 ]
1822 ];
1823
1824 // Don't try to use any object cache for SessionManager either.
1825 $GLOBALS['wgSessionCacheType'] = CACHE_NONE;
1826
1827 // Set a dummy $wgServer to bypass the check in Setup.php, the
1828 // web installer will automatically detect it and not use this value.
1829 $GLOBALS['wgServer'] = 'https://🌻.invalid';
1830 }
1831
1839 public function addInstallStep( $callback, $findStep = 'BEGINNING' ) {
1840 $this->extraInstallSteps[$findStep][] = $callback;
1841 }
1842
1847 protected function disableTimeLimit() {
1848 Wikimedia\suppressWarnings();
1849 set_time_limit( 0 );
1850 Wikimedia\restoreWarnings();
1851 }
1852}
$GLOBALS['IP']
$wgObjectCaches
Advanced object cache configuration.
$wgStyleDirectory
Filesystem stylesheets directory.
$wgAutoloadClasses
Array mapping class names to filenames, for autoloading.
$wgHooks
Global list of hooks.
$wgExtensionDirectory
Filesystem extensions directory.
$wgExternalLinkTarget
Set a default target for external links, e.g.
wfIsWindows()
Check if the operating system is Windows.
wfShorthandToInteger( $string='', $default=-1)
Converts shorthand byte notation to integer form.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfIsHHVM()
Check if we are running under HHVM.
$wgMemc
Definition Setup.php:790
$wgLang
Definition Setup.php:880
$IP
Definition WebStart.php:41
$line
Definition cdb.php:59
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@member.fsf.org
ExtensionRegistry class.
Accesses configuration settings from $GLOBALS.
A Config instance which stores all settings as a member variable.
Base installer class.
Definition Installer.php:46
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().
Definition Installer.php:66
getExtensionInfo( $type, $parentRelPath, $name)
Title $parserTitle
Cached Title, used by parse().
Definition Installer.php:87
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.
Definition Installer.php:54
getDefaultSkin(array $skinNames)
Returns a default value to be used for $wgDefaultSkin: normally the one set in DefaultSettings,...
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.
$mediaWikiAnnounceUrl
URL to mediawiki-announce subscription.
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.
getParserOptions()
getCompiledDBs()
Get a list of DBs supported by current PHP setup.
envCheckBrokenXML()
Some versions of libxml+PHP break < and > encoding horribly.
array $installSteps
The actual list of installation steps.
ParserOptions $parserOptions
Cached ParserOptions, used by parse().
Definition Installer.php:94
dirIsExecutable( $dir, $url)
Checks if scripts located in the given directory can be executed via the given URL.
doEnvironmentPreps()
envCheckGit()
Search for git.
getDocUrl( $page)
Overridden by WebInstaller to provide lastPage parameters.
array $defaultVarNames
MediaWiki configuration globals that will eventually be passed through to LocalSettings....
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...
array $settings
Definition Installer.php:59
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.
disableLinkPopups()
performInstallation( $startCB, $endCB)
Actually perform the installation.
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.
subscribeToMediaWikiAnnounce(Status $s)
envCheckCache()
Environment check for compiled object cache types.
__construct()
Constructor, always call this from child classes.
int $minMemorySize
Minimum memory size in MB.
Definition Installer.php:80
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.
readExtension( $fullJsonFile, $extDeps=[], $skinDeps=[])
envCheckPath()
Environment check to inform user which paths we've assumed.
array $envPreps
A list of environment preparation methods called by doEnvironmentPreps().
$mediaWikiAnnounceLanguages
Supported language codes for Mailman.
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.
static overrideConfig()
Override the necessary bits of the config to run an installation.
restoreLinkPopups()
array $extraInstallSteps
Extra steps for installation, for things like DatabaseInstallers to modify.
static array $dbTypes
Known database types.
envCheckDiff3()
Search for GNU diff3.
envCheckShellLocale()
Environment check for preferred locale in shell.
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().
Definition Installer.php:73
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.
An interwiki lookup that has no data, intended for use in the installer.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Executes shell commands.
Definition Shell.php:44
Provides a fallback sequence for Config objects.
Set options of the Parser.
Show an error when any operation involving passwords fails to run.
Test for PHP+libxml2 bug which breaks XML input subtly with certain versions.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:40
Represents a title within MediaWiki.
Definition Title.php:42
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition User.php:518
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition User.php:542
static newSystemUser( $name, $options=[])
Static factory method for creation of a "system" user from username.
Definition User.php:740
Class for the core installer web interface.
Content object for wiki text pages.
const CACHE_NONE
Definition Defines.php:91
const CACHE_ANYTHING
Definition Defines.php:90
const CACHE_MEMCACHED
Definition Defines.php:93
const CACHE_DB
Definition Defines.php:92
const EDIT_NEW
Definition Defines.php:141
Interface for configuration instances.
Definition Config.php:28
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
$source
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...
$lines
Definition router.php:61
$content
Definition router.php:78
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition router.php:42
if(!is_readable( $file)) $ext
Definition router.php:48
if(!isset( $args[0])) $lang