2010-05-07 12:25:01 +00:00
|
|
|
<?php
|
2010-08-21 18:20:09 +00:00
|
|
|
/**
|
|
|
|
|
* Base code for MediaWiki installer.
|
|
|
|
|
*
|
2016-05-19 00:40:56 +00:00
|
|
|
* DO NOT PATCH THIS FILE IF YOU NEED TO CHANGE INSTALLER BEHAVIOR IN YOUR PACKAGE!
|
|
|
|
|
* See mw-config/overrides/README for details.
|
|
|
|
|
*
|
2012-05-06 05:50:15 +00:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
|
|
|
*
|
2010-08-21 18:20:09 +00:00
|
|
|
* @file
|
2019-11-25 23:24:49 +00:00
|
|
|
* @ingroup Installer
|
2010-08-21 18:20:09 +00:00
|
|
|
*/
|
2018-06-07 08:01:13 +00:00
|
|
|
|
2020-11-03 06:00:34 +00:00
|
|
|
use MediaWiki\HookContainer\HookContainer;
|
|
|
|
|
use MediaWiki\HookContainer\StaticHookRegistry;
|
2018-06-07 08:01:13 +00:00
|
|
|
use MediaWiki\Interwiki\NullInterwikiLookup;
|
2016-05-13 19:27:06 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
2010-05-07 12:25:01 +00:00
|
|
|
|
2010-07-29 18:36:39 +00:00
|
|
|
/**
|
2019-11-25 23:24:49 +00:00
|
|
|
* The Installer helps admins create or upgrade their wiki.
|
2010-07-29 18:36:39 +00:00
|
|
|
*
|
2019-11-25 23:24:49 +00:00
|
|
|
* The installer classes are exposed through these human interfaces:
|
|
|
|
|
*
|
|
|
|
|
* - The `maintenance/install.php` script, backed by CliInstaller.
|
|
|
|
|
* - The `maintenance/update.php` script, backed by DatabaseUpdater.
|
|
|
|
|
* - The `mw-config/index.php` web entry point, backed by WebInstaller.
|
|
|
|
|
*
|
2019-12-21 18:09:51 +00:00
|
|
|
* @defgroup Installer Installer
|
2010-07-29 18:36:39 +00:00
|
|
|
*/
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-19 02:41:54 +00:00
|
|
|
* Base installer class.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2010-07-22 17:58:26 +00:00
|
|
|
* This class provides the base for installation and update functionality
|
|
|
|
|
* for both MediaWiki core and extensions.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2019-11-25 23:24:49 +00:00
|
|
|
* @ingroup Installer
|
2010-07-22 17:58:26 +00:00
|
|
|
* @since 1.17
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
|
|
|
|
abstract class Installer {
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2013-12-16 16:02:51 +00:00
|
|
|
/**
|
|
|
|
|
* The oldest version of PCRE we can support.
|
|
|
|
|
*
|
|
|
|
|
* Defining this is necessary because PHP may be linked with a system version
|
|
|
|
|
* of PCRE, which may be older than that bundled with the minimum PHP version.
|
|
|
|
|
*/
|
2020-05-12 22:37:45 +00:00
|
|
|
public const MINIMUM_PCRE_VERSION = '7.2';
|
2013-12-16 16:02:51 +00:00
|
|
|
|
2021-08-29 10:53:15 +00:00
|
|
|
/**
|
|
|
|
|
* URL to mediawiki-announce list summary page
|
|
|
|
|
*/
|
|
|
|
|
private const MEDIAWIKI_ANNOUNCE_URL =
|
|
|
|
|
'https://lists.wikimedia.org/postorius/lists/mediawiki-announce.lists.wikimedia.org/';
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-21 17:20:50 +00:00
|
|
|
* @var array
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2011-01-28 15:00:18 +00:00
|
|
|
protected $settings;
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2013-05-25 10:59:13 +00:00
|
|
|
/**
|
|
|
|
|
* List of detected DBs, access using getCompiledDBs().
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
|
|
|
|
protected $compiledDBs;
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-22 17:58:26 +00:00
|
|
|
* Cached DB installer instances, access using getDBInstaller().
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2010-07-21 17:20:50 +00:00
|
|
|
* @var array
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
protected $dbInstallers = [];
|
2010-05-07 12:25:01 +00:00
|
|
|
|
|
|
|
|
/**
|
2019-09-09 08:49:23 +00:00
|
|
|
* Minimum memory size in MiB.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @var int
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2010-07-29 18:18:03 +00:00
|
|
|
protected $minMemorySize = 50;
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-21 17:20:50 +00:00
|
|
|
* Cached Title, used by parse().
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2010-07-22 17:58:26 +00:00
|
|
|
* @var Title
|
2010-07-21 17:20:50 +00:00
|
|
|
*/
|
2010-07-22 17:58:26 +00:00
|
|
|
protected $parserTitle;
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-07-21 17:20:50 +00:00
|
|
|
/**
|
|
|
|
|
* Cached ParserOptions, used by parse().
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2010-07-22 17:58:26 +00:00
|
|
|
* @var ParserOptions
|
2010-07-29 18:18:03 +00:00
|
|
|
*/
|
|
|
|
|
protected $parserOptions;
|
|
|
|
|
|
2010-07-21 17:20:50 +00:00
|
|
|
/**
|
2020-07-22 22:54:19 +00:00
|
|
|
* Known database types. These correspond to the class names <type>Installer,
|
|
|
|
|
* and are also MediaWiki database types valid for $wgDBtype.
|
|
|
|
|
*
|
|
|
|
|
* To add a new type, create a <type>Installer class and a Database<type>
|
|
|
|
|
* class, and add a config-type-<type> message to MessagesEn.php.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2020-07-22 22:54:19 +00:00
|
|
|
protected static $dbTypes = [
|
|
|
|
|
'mysql',
|
|
|
|
|
'postgres',
|
|
|
|
|
'sqlite',
|
|
|
|
|
];
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-18 18:52:05 +00:00
|
|
|
* A list of environment check methods called by doEnvironmentChecks().
|
|
|
|
|
* These may output warnings using showMessage(), and/or abort the
|
2010-05-07 12:25:01 +00:00
|
|
|
* installation process by returning false.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2014-07-10 16:27:11 +00:00
|
|
|
* For the WebInstaller these are only called on the Welcome page,
|
|
|
|
|
* if these methods have side-effects that should affect later page loads
|
|
|
|
|
* (as well as the generated stylesheet), use envPreps instead.
|
|
|
|
|
*
|
2010-07-21 17:20:50 +00:00
|
|
|
* @var array
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
protected $envChecks = [
|
2010-05-07 12:25:01 +00:00
|
|
|
'envCheckDB',
|
|
|
|
|
'envCheckPCRE',
|
|
|
|
|
'envCheckMemory',
|
|
|
|
|
'envCheckCache',
|
2011-08-06 16:39:59 +00:00
|
|
|
'envCheckModSecurity',
|
2010-05-07 12:25:01 +00:00
|
|
|
'envCheckDiff3',
|
|
|
|
|
'envCheckGraphics',
|
2012-08-01 20:49:17 +00:00
|
|
|
'envCheckGit',
|
2011-06-15 07:35:47 +00:00
|
|
|
'envCheckServer',
|
2010-05-07 12:25:01 +00:00
|
|
|
'envCheckPath',
|
|
|
|
|
'envCheckUploadsDirectory',
|
2011-05-05 11:52:23 +00:00
|
|
|
'envCheckLibicu',
|
|
|
|
|
'envCheckSuhosinMaxValueLength',
|
2017-07-31 22:28:47 +00:00
|
|
|
'envCheck64Bit',
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2014-07-10 16:27:11 +00:00
|
|
|
/**
|
|
|
|
|
* A list of environment preparation methods called by doEnvironmentPreps().
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
protected $envPreps = [
|
2014-07-10 16:27:11 +00:00
|
|
|
'envPrepServer',
|
|
|
|
|
'envPrepPath',
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2014-07-10 16:27:11 +00:00
|
|
|
|
2011-01-25 18:24:16 +00:00
|
|
|
/**
|
2011-01-21 15:27:16 +00:00
|
|
|
* MediaWiki configuration globals that will eventually be passed through
|
|
|
|
|
* to LocalSettings.php. The names only are given here, the defaults
|
|
|
|
|
* typically come from DefaultSettings.php.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
protected $defaultVarNames = [
|
2011-01-21 15:27:16 +00:00
|
|
|
'wgSitename',
|
|
|
|
|
'wgPasswordSender',
|
|
|
|
|
'wgLanguageCode',
|
2021-09-12 08:05:53 +00:00
|
|
|
'wgLocaltimezone',
|
2011-01-21 15:27:16 +00:00
|
|
|
'wgRightsIcon',
|
|
|
|
|
'wgRightsText',
|
|
|
|
|
'wgRightsUrl',
|
|
|
|
|
'wgEnableEmail',
|
|
|
|
|
'wgEnableUserEmail',
|
|
|
|
|
'wgEnotifUserTalk',
|
|
|
|
|
'wgEnotifWatchlist',
|
|
|
|
|
'wgEmailAuthentication',
|
2015-10-28 02:01:54 +00:00
|
|
|
'wgDBname',
|
2011-01-21 15:27:16 +00:00
|
|
|
'wgDBtype',
|
|
|
|
|
'wgDiff3',
|
|
|
|
|
'wgImageMagickConvertCommand',
|
2012-08-01 20:49:17 +00:00
|
|
|
'wgGitBin',
|
2011-01-21 15:27:16 +00:00
|
|
|
'IP',
|
|
|
|
|
'wgScriptPath',
|
|
|
|
|
'wgMetaNamespace',
|
|
|
|
|
'wgDeletedDirectory',
|
|
|
|
|
'wgEnableUploads',
|
|
|
|
|
'wgSecretKey',
|
|
|
|
|
'wgUseInstantCommons',
|
|
|
|
|
'wgUpgradeKey',
|
|
|
|
|
'wgDefaultSkin',
|
2016-06-30 09:29:10 +00:00
|
|
|
'wgPingback',
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Variables that are stored alongside globals, and are used for any
|
|
|
|
|
* configuration of the installation process aside from the MediaWiki
|
|
|
|
|
* configuration. Map of names to defaults.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
protected $internalDefaults = [
|
2011-01-21 15:27:16 +00:00
|
|
|
'_UserLang' => 'en',
|
|
|
|
|
'_Environment' => false,
|
|
|
|
|
'_RaiseMemory' => false,
|
|
|
|
|
'_UpgradeDone' => false,
|
|
|
|
|
'_InstallDone' => false,
|
2016-02-17 09:09:32 +00:00
|
|
|
'_Caches' => [],
|
2011-01-21 15:27:16 +00:00
|
|
|
'_InstallPassword' => '',
|
|
|
|
|
'_SameAccount' => true,
|
|
|
|
|
'_CreateDBAccount' => false,
|
|
|
|
|
'_NamespaceType' => 'site-name',
|
|
|
|
|
'_AdminName' => '', // will be set later, when the user selects language
|
|
|
|
|
'_AdminPassword' => '',
|
2013-05-26 09:41:10 +00:00
|
|
|
'_AdminPasswordConfirm' => '',
|
2011-01-21 15:27:16 +00:00
|
|
|
'_AdminEmail' => '',
|
|
|
|
|
'_Subscribe' => false,
|
|
|
|
|
'_SkipOptional' => 'continue',
|
|
|
|
|
'_RightsProfile' => 'wiki',
|
|
|
|
|
'_LicenseCode' => 'none',
|
|
|
|
|
'_CCDone' => false,
|
2016-02-17 09:09:32 +00:00
|
|
|
'_Extensions' => [],
|
|
|
|
|
'_Skins' => [],
|
2011-01-21 15:27:16 +00:00
|
|
|
'_MemCachedServers' => '',
|
|
|
|
|
'_UpgradeKeySupplied' => false,
|
|
|
|
|
'_ExistingDBSettings' => false,
|
2020-02-27 16:37:02 +00:00
|
|
|
// Single quotes are intentional, LocalSettingsGenerator must output this unescaped.
|
|
|
|
|
'_Logo' => '$wgResourceBasePath/resources/assets/wiki.png',
|
2013-09-25 06:48:05 +00:00
|
|
|
|
2016-02-05 18:47:51 +00:00
|
|
|
'wgAuthenticationTokenVersion' => 1,
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The actual list of installation steps. This will be initialized by getInstallSteps()
|
|
|
|
|
*
|
2019-10-11 14:06:45 +00:00
|
|
|
* @var array[]
|
|
|
|
|
* @phan-var array<int,array{name:string,callback:array{0:object,1:string}}>
|
2011-01-21 15:27:16 +00:00
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
private $installSteps = [];
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Extra steps for installation, for things like DatabaseInstallers to modify
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
protected $extraInstallSteps = [];
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Known object cache types and the functions used to test for their existence.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
protected $objectCaches = [
|
2016-10-01 17:00:53 +00:00
|
|
|
'apcu' => 'apcu_fetch',
|
2011-01-21 15:27:16 +00:00
|
|
|
'wincache' => 'wincache_ucache_get'
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* User rights profiles.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
public $rightsProfiles = [
|
|
|
|
|
'wiki' => [],
|
|
|
|
|
'no-anon' => [
|
|
|
|
|
'*' => [ 'edit' => false ]
|
|
|
|
|
],
|
|
|
|
|
'fishbowl' => [
|
|
|
|
|
'*' => [
|
2011-01-21 15:27:16 +00:00
|
|
|
'createaccount' => false,
|
|
|
|
|
'edit' => false,
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'private' => [
|
|
|
|
|
'*' => [
|
2011-01-21 15:27:16 +00:00
|
|
|
'createaccount' => false,
|
|
|
|
|
'edit' => false,
|
|
|
|
|
'read' => false,
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
];
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* License types.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
public $licenses = [
|
|
|
|
|
'cc-by' => [
|
2015-10-23 22:23:43 +00:00
|
|
|
'url' => 'https://creativecommons.org/licenses/by/4.0/',
|
2015-05-24 09:30:21 +00:00
|
|
|
'icon' => '$wgResourceBasePath/resources/assets/licenses/cc-by.png',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
'cc-by-sa' => [
|
2015-10-23 22:23:43 +00:00
|
|
|
'url' => 'https://creativecommons.org/licenses/by-sa/4.0/',
|
2015-05-24 09:30:21 +00:00
|
|
|
'icon' => '$wgResourceBasePath/resources/assets/licenses/cc-by-sa.png',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
'cc-by-nc-sa' => [
|
2015-10-23 22:23:43 +00:00
|
|
|
'url' => 'https://creativecommons.org/licenses/by-nc-sa/4.0/',
|
2015-05-24 09:30:21 +00:00
|
|
|
'icon' => '$wgResourceBasePath/resources/assets/licenses/cc-by-nc-sa.png',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
'cc-0' => [
|
2011-03-06 20:14:12 +00:00
|
|
|
'url' => 'https://creativecommons.org/publicdomain/zero/1.0/',
|
2015-05-24 09:30:21 +00:00
|
|
|
'icon' => '$wgResourceBasePath/resources/assets/licenses/cc-0.png',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
'gfdl' => [
|
2014-04-09 23:19:19 +00:00
|
|
|
'url' => 'https://www.gnu.org/copyleft/fdl.html',
|
2015-05-24 09:30:21 +00:00
|
|
|
'icon' => '$wgResourceBasePath/resources/assets/licenses/gnu-fdl.png',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
'none' => [
|
2011-01-21 15:27:16 +00:00
|
|
|
'url' => '',
|
|
|
|
|
'icon' => '',
|
|
|
|
|
'text' => ''
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
'cc-choose' => [
|
2011-01-21 15:27:16 +00:00
|
|
|
// Details will be filled in by the selector.
|
|
|
|
|
'url' => '',
|
|
|
|
|
'icon' => '',
|
|
|
|
|
'text' => '',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
];
|
2011-01-21 15:27:16 +00:00
|
|
|
|
2020-11-03 06:00:34 +00:00
|
|
|
/**
|
|
|
|
|
* @var HookContainer|null
|
|
|
|
|
*/
|
|
|
|
|
protected $autoExtensionHookContainer;
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-22 17:58:26 +00:00
|
|
|
* UI interface for displaying a short message
|
2012-08-29 08:07:10 +00:00
|
|
|
* The parameters are like parameters to wfMessage().
|
2010-07-22 17:58:26 +00:00
|
|
|
* The messages will be in wikitext format, which will be converted to an
|
|
|
|
|
* output format such as HTML or text before being sent to the user.
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param string $msg
|
Get rid of unnecessary func_get_args() and friends
HHVM does not support variadic arguments with type hints. This is
mostly not a big problem, because we can just drop the type hint, but
for some reason PHPUnit adds a type hint of "array" when it creates
mocks, so a class with a variadic method can't be mocked (at least in
some cases). As such, I left alone all the classes that seem like
someone might like to mock them, like Title and User. If anyone wants
to mock them in the future, they'll have to switch back to
func_get_args(). Some of the changes are definitely safe, like
functions and test classes.
In most cases, func_get_args() (and/or func_get_arg(), func_num_args() )
were only present because the code was written before we required PHP
5.6, and writing them as variadic functions is strictly superior. In
some cases I left them alone, aside from HHVM compatibility:
* Forwarding all arguments to another function. It's useful to keep
func_get_args() here where we want to keep the list of expected
arguments and their meanings in the function signature line for
documentation purposes, but don't want to copy-paste a long line of
argument names.
* Handling deprecated calling conventions.
* One or two miscellaneous cases where we're basically using the
arguments individually but want to use them as an array as well for
some reason.
Change-Id: I066ec95a7beb7c0665146195a08e7cce1222c788
2018-10-08 14:10:45 +00:00
|
|
|
* @param mixed ...$params
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
Get rid of unnecessary func_get_args() and friends
HHVM does not support variadic arguments with type hints. This is
mostly not a big problem, because we can just drop the type hint, but
for some reason PHPUnit adds a type hint of "array" when it creates
mocks, so a class with a variadic method can't be mocked (at least in
some cases). As such, I left alone all the classes that seem like
someone might like to mock them, like Title and User. If anyone wants
to mock them in the future, they'll have to switch back to
func_get_args(). Some of the changes are definitely safe, like
functions and test classes.
In most cases, func_get_args() (and/or func_get_arg(), func_num_args() )
were only present because the code was written before we required PHP
5.6, and writing them as variadic functions is strictly superior. In
some cases I left them alone, aside from HHVM compatibility:
* Forwarding all arguments to another function. It's useful to keep
func_get_args() here where we want to keep the list of expected
arguments and their meanings in the function signature line for
documentation purposes, but don't want to copy-paste a long line of
argument names.
* Handling deprecated calling conventions.
* One or two miscellaneous cases where we're basically using the
arguments individually but want to use them as an array as well for
some reason.
Change-Id: I066ec95a7beb7c0665146195a08e7cce1222c788
2018-10-08 14:10:45 +00:00
|
|
|
abstract public function showMessage( $msg, ...$params );
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2011-04-27 18:22:01 +00:00
|
|
|
/**
|
|
|
|
|
* Same as showMessage(), but for displaying errors
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param string $msg
|
Get rid of unnecessary func_get_args() and friends
HHVM does not support variadic arguments with type hints. This is
mostly not a big problem, because we can just drop the type hint, but
for some reason PHPUnit adds a type hint of "array" when it creates
mocks, so a class with a variadic method can't be mocked (at least in
some cases). As such, I left alone all the classes that seem like
someone might like to mock them, like Title and User. If anyone wants
to mock them in the future, they'll have to switch back to
func_get_args(). Some of the changes are definitely safe, like
functions and test classes.
In most cases, func_get_args() (and/or func_get_arg(), func_num_args() )
were only present because the code was written before we required PHP
5.6, and writing them as variadic functions is strictly superior. In
some cases I left them alone, aside from HHVM compatibility:
* Forwarding all arguments to another function. It's useful to keep
func_get_args() here where we want to keep the list of expected
arguments and their meanings in the function signature line for
documentation purposes, but don't want to copy-paste a long line of
argument names.
* Handling deprecated calling conventions.
* One or two miscellaneous cases where we're basically using the
arguments individually but want to use them as an array as well for
some reason.
Change-Id: I066ec95a7beb7c0665146195a08e7cce1222c788
2018-10-08 14:10:45 +00:00
|
|
|
* @param mixed ...$params
|
2011-04-27 18:22:01 +00:00
|
|
|
*/
|
Get rid of unnecessary func_get_args() and friends
HHVM does not support variadic arguments with type hints. This is
mostly not a big problem, because we can just drop the type hint, but
for some reason PHPUnit adds a type hint of "array" when it creates
mocks, so a class with a variadic method can't be mocked (at least in
some cases). As such, I left alone all the classes that seem like
someone might like to mock them, like Title and User. If anyone wants
to mock them in the future, they'll have to switch back to
func_get_args(). Some of the changes are definitely safe, like
functions and test classes.
In most cases, func_get_args() (and/or func_get_arg(), func_num_args() )
were only present because the code was written before we required PHP
5.6, and writing them as variadic functions is strictly superior. In
some cases I left them alone, aside from HHVM compatibility:
* Forwarding all arguments to another function. It's useful to keep
func_get_args() here where we want to keep the list of expected
arguments and their meanings in the function signature line for
documentation purposes, but don't want to copy-paste a long line of
argument names.
* Handling deprecated calling conventions.
* One or two miscellaneous cases where we're basically using the
arguments individually but want to use them as an array as well for
some reason.
Change-Id: I066ec95a7beb7c0665146195a08e7cce1222c788
2018-10-08 14:10:45 +00:00
|
|
|
abstract public function showError( $msg, ...$params );
|
2011-04-27 18:22:01 +00:00
|
|
|
|
2011-01-21 15:27:16 +00:00
|
|
|
/**
|
2014-07-21 08:31:09 +00:00
|
|
|
* Show a message to the installing user by using a Status object
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param Status $status
|
2011-01-21 15:27:16 +00:00
|
|
|
*/
|
2014-07-21 08:31:09 +00:00
|
|
|
abstract public function showStatusMessage( Status $status );
|
2011-01-21 15:27:16 +00:00
|
|
|
|
2016-05-01 19:29:11 +00:00
|
|
|
/**
|
|
|
|
|
* Constructs a Config object that contains configuration settings that should be
|
|
|
|
|
* overwritten for the installation process.
|
|
|
|
|
*
|
|
|
|
|
* @since 1.27
|
|
|
|
|
*
|
|
|
|
|
* @param Config $baseConfig
|
|
|
|
|
*
|
|
|
|
|
* @return Config The config to use during installation.
|
|
|
|
|
*/
|
|
|
|
|
public static function getInstallerConfig( Config $baseConfig ) {
|
|
|
|
|
$configOverrides = new HashConfig();
|
|
|
|
|
|
|
|
|
|
// disable (problematic) object cache types explicitly, preserving all other (working) ones
|
|
|
|
|
// bug T113843
|
2018-01-13 00:02:09 +00:00
|
|
|
$emptyCache = [ 'class' => EmptyBagOStuff::class ];
|
2016-05-01 19:29:11 +00:00
|
|
|
|
|
|
|
|
$objectCaches = [
|
|
|
|
|
CACHE_NONE => $emptyCache,
|
|
|
|
|
CACHE_DB => $emptyCache,
|
|
|
|
|
CACHE_ANYTHING => $emptyCache,
|
|
|
|
|
CACHE_MEMCACHED => $emptyCache,
|
|
|
|
|
] + $baseConfig->get( 'ObjectCaches' );
|
|
|
|
|
|
|
|
|
|
$configOverrides->set( 'ObjectCaches', $objectCaches );
|
|
|
|
|
|
|
|
|
|
// Load the installer's i18n.
|
|
|
|
|
$messageDirs = $baseConfig->get( 'MessagesDirs' );
|
|
|
|
|
$messageDirs['MediawikiInstaller'] = __DIR__ . '/i18n';
|
|
|
|
|
|
|
|
|
|
$configOverrides->set( 'MessagesDirs', $messageDirs );
|
|
|
|
|
|
2016-05-13 19:27:06 +00:00
|
|
|
$installerConfig = new MultiConfig( [ $configOverrides, $baseConfig ] );
|
|
|
|
|
|
|
|
|
|
// make sure we use the installer config as the main config
|
|
|
|
|
$configRegistry = $baseConfig->get( 'ConfigRegistry' );
|
2021-02-10 22:31:02 +00:00
|
|
|
$configRegistry['main'] = static function () use ( $installerConfig ) {
|
2016-05-13 19:27:06 +00:00
|
|
|
return $installerConfig;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
$configOverrides->set( 'ConfigRegistry', $configRegistry );
|
|
|
|
|
|
|
|
|
|
return $installerConfig;
|
2016-05-01 19:29:11 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-22 17:58:26 +00:00
|
|
|
* Constructor, always call this from child classes.
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2010-07-29 18:18:03 +00:00
|
|
|
public function __construct() {
|
2016-05-01 19:29:11 +00:00
|
|
|
$defaultConfig = new GlobalVarConfig(); // all the stuff from DefaultSettings.php
|
|
|
|
|
$installerConfig = self::getInstallerConfig( $defaultConfig );
|
|
|
|
|
|
2020-09-17 19:12:33 +00:00
|
|
|
$this->resetMediaWikiServices( $installerConfig );
|
2011-01-21 15:27:16 +00:00
|
|
|
|
2020-09-17 19:12:33 +00:00
|
|
|
// Disable all storage services, since we don't have any configuration yet!
|
2018-06-07 08:01:13 +00:00
|
|
|
MediaWikiServices::disableStorageBackend();
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
$this->settings = $this->internalDefaults;
|
|
|
|
|
|
|
|
|
|
foreach ( $this->defaultVarNames as $var ) {
|
|
|
|
|
$this->settings[$var] = $GLOBALS[$var];
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-10 16:27:11 +00:00
|
|
|
$this->doEnvironmentPreps();
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$this->compiledDBs = [];
|
2020-07-22 22:54:19 +00:00
|
|
|
foreach ( self::getDBTypes() as $type ) {
|
2011-01-21 15:27:16 +00:00
|
|
|
$installer = $this->getDBInstaller( $type );
|
|
|
|
|
|
|
|
|
|
if ( !$installer->isCompiled() ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2014-06-27 01:17:05 +00:00
|
|
|
$this->compiledDBs[] = $type;
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->parserTitle = Title::newFromText( 'Installer' );
|
2020-09-17 19:12:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reset the global service container and associated global state
|
|
|
|
|
* to accommodate different stages of the installation.
|
|
|
|
|
* @since 1.35
|
|
|
|
|
*
|
|
|
|
|
* @param Config|null $installerConfig Config override. If null, the previous
|
|
|
|
|
* config will be inherited.
|
|
|
|
|
* @param array $serviceOverrides Service definition overrides. Values can be null to
|
|
|
|
|
* disable specific overrides that would be applied per default, namely
|
|
|
|
|
* 'InterwikiLookup' and 'UserOptionsLookup'.
|
|
|
|
|
*
|
|
|
|
|
* @return MediaWikiServices
|
|
|
|
|
* @throws MWException
|
|
|
|
|
*/
|
|
|
|
|
public function resetMediaWikiServices( Config $installerConfig = null, $serviceOverrides = [] ) {
|
2021-09-04 19:19:47 +00:00
|
|
|
global $wgObjectCaches, $wgLang;
|
2020-09-17 19:12:33 +00:00
|
|
|
|
|
|
|
|
$serviceOverrides += [
|
|
|
|
|
// Disable interwiki lookup, to avoid database access during parses
|
2021-02-10 22:31:02 +00:00
|
|
|
'InterwikiLookup' => static function () {
|
2020-09-17 19:12:33 +00:00
|
|
|
return new NullInterwikiLookup();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Disable user options database fetching, only rely on default options.
|
2021-02-10 22:31:02 +00:00
|
|
|
'UserOptionsLookup' => static function ( MediaWikiServices $services ) {
|
2020-09-17 19:12:33 +00:00
|
|
|
return $services->get( '_DefaultOptionsLookup' );
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$lang = $this->getVar( '_UserLang', 'en' );
|
|
|
|
|
|
|
|
|
|
// Reset all services and inject config overrides
|
|
|
|
|
MediaWikiServices::resetGlobalInstance( $installerConfig );
|
|
|
|
|
|
|
|
|
|
$mwServices = MediaWikiServices::getInstance();
|
|
|
|
|
|
|
|
|
|
foreach ( $serviceOverrides as $name => $callback ) {
|
|
|
|
|
// Skip if the caller set $callback to null
|
|
|
|
|
// to suppress default overrides.
|
|
|
|
|
if ( $callback ) {
|
|
|
|
|
$mwServices->redefineService( $name, $callback );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Disable i18n cache
|
|
|
|
|
$mwServices->getLocalisationCache()->disableBackend();
|
|
|
|
|
|
|
|
|
|
// Set a fake user.
|
|
|
|
|
// Note that this will reset the context's language,
|
|
|
|
|
// so set the user before setting the language.
|
|
|
|
|
$user = User::newFromId( 0 );
|
2021-09-04 19:19:47 +00:00
|
|
|
StubGlobalUser::setUser( $user );
|
2020-09-17 19:12:33 +00:00
|
|
|
|
|
|
|
|
RequestContext::getMain()->setUser( $user );
|
|
|
|
|
|
|
|
|
|
// Don't attempt to load user language options (T126177)
|
|
|
|
|
// This will be overridden in the web installer with the user-specified language
|
|
|
|
|
// Ensure $wgLang does not have a reference to a stale LocalisationCache instance
|
|
|
|
|
// (T241638, T261081)
|
|
|
|
|
RequestContext::getMain()->setLanguage( $lang );
|
|
|
|
|
$wgLang = RequestContext::getMain()->getLanguage();
|
|
|
|
|
|
|
|
|
|
// Disable object cache (otherwise CACHE_ANYTHING will try CACHE_DB and
|
|
|
|
|
// SqlBagOStuff will then throw since we just disabled wfGetDB)
|
|
|
|
|
$wgObjectCaches = $mwServices->getMainConfig()->get( 'ObjectCaches' );
|
|
|
|
|
|
2020-06-05 11:04:20 +00:00
|
|
|
$this->parserOptions = new ParserOptions( $user ); // language will be wrong :(
|
2017-04-03 03:55:48 +00:00
|
|
|
// Don't try to access DB before user language is initialised
|
2019-08-26 12:24:37 +00:00
|
|
|
$this->setParserLanguage( $mwServices->getLanguageFactory()->getLanguage( 'en' ) );
|
2020-09-17 19:12:33 +00:00
|
|
|
|
|
|
|
|
return $mwServices;
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-19 02:41:54 +00:00
|
|
|
* Get a list of known DB types.
|
2011-05-02 16:58:29 +00:00
|
|
|
*
|
|
|
|
|
* @return array
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2010-08-15 18:55:08 +00:00
|
|
|
public static function getDBTypes() {
|
2020-07-22 22:54:19 +00:00
|
|
|
return self::$dbTypes;
|
2010-07-29 18:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-18 18:52:05 +00:00
|
|
|
* Do initial checks of the PHP environment. Set variables according to
|
2010-05-07 12:25:01 +00:00
|
|
|
* the observed environment.
|
|
|
|
|
*
|
|
|
|
|
* It's possible that this may be called under the CLI SAPI, not the SAPI
|
|
|
|
|
* that the wiki will primarily run under. In that case, the subclass should
|
|
|
|
|
* initialise variables such as wgScriptPath, before calling this function.
|
|
|
|
|
*
|
2010-07-18 18:52:05 +00:00
|
|
|
* Under the web subclass, it can already be assumed that PHP 5+ is in use
|
2010-05-07 12:25:01 +00:00
|
|
|
* and that sessions are working.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2011-01-05 23:20:12 +00:00
|
|
|
* @return Status
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2010-07-19 02:41:54 +00:00
|
|
|
public function doEnvironmentChecks() {
|
2019-10-03 03:55:29 +00:00
|
|
|
// PHP version has already been checked by entry scripts
|
2014-07-07 10:48:11 +00:00
|
|
|
// Show message here for information purposes
|
2019-10-03 03:55:29 +00:00
|
|
|
$this->showMessage( 'config-env-php', PHP_VERSION );
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2014-07-07 10:48:11 +00:00
|
|
|
$good = true;
|
2013-12-16 16:02:51 +00:00
|
|
|
// Must go here because an old version of PCRE can prevent other checks from completing
|
2019-05-17 14:54:47 +00:00
|
|
|
$pcreVersion = explode( ' ', PCRE_VERSION, 2 )[0];
|
2014-07-07 10:48:11 +00:00
|
|
|
if ( version_compare( $pcreVersion, self::MINIMUM_PCRE_VERSION, '<' ) ) {
|
|
|
|
|
$this->showError( 'config-pcre-old', self::MINIMUM_PCRE_VERSION, $pcreVersion );
|
|
|
|
|
$good = false;
|
|
|
|
|
} else {
|
2011-03-04 13:58:40 +00:00
|
|
|
foreach ( $this->envChecks as $check ) {
|
|
|
|
|
$status = $this->$check();
|
|
|
|
|
if ( $status === false ) {
|
|
|
|
|
$good = false;
|
|
|
|
|
}
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
$this->setVar( '_Environment', $good );
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2011-01-05 23:20:12 +00:00
|
|
|
return $good ? Status::newGood() : Status::newFatal( 'config-env-bad' );
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
2014-07-10 16:27:11 +00:00
|
|
|
public function doEnvironmentPreps() {
|
|
|
|
|
foreach ( $this->envPreps as $prep ) {
|
|
|
|
|
$this->$prep();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-22 17:58:26 +00:00
|
|
|
/**
|
|
|
|
|
* Set a MW configuration variable, or internal installer configuration variable.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param string $name
|
|
|
|
|
* @param mixed $value
|
2010-07-22 17:58:26 +00:00
|
|
|
*/
|
|
|
|
|
public function setVar( $name, $value ) {
|
|
|
|
|
$this->settings[$name] = $value;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
|
|
|
|
* Get an MW configuration variable, or internal installer configuration variable.
|
|
|
|
|
* The defaults come from $GLOBALS (ultimately DefaultSettings.php).
|
|
|
|
|
* Installer variables are typically prefixed by an underscore.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param string $name
|
2018-06-26 21:14:43 +00:00
|
|
|
* @param mixed|null $default
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2010-07-22 17:58:26 +00:00
|
|
|
* @return mixed
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2010-07-19 02:41:54 +00:00
|
|
|
public function getVar( $name, $default = null ) {
|
2018-10-20 21:55:44 +00:00
|
|
|
return $this->settings[$name] ?? $default;
|
2010-07-29 18:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
2013-05-25 10:59:13 +00:00
|
|
|
/**
|
|
|
|
|
* Get a list of DBs supported by current PHP setup
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function getCompiledDBs() {
|
|
|
|
|
return $this->compiledDBs;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-03 05:14:33 +00:00
|
|
|
/**
|
|
|
|
|
* Get the DatabaseInstaller class name for this type
|
|
|
|
|
*
|
|
|
|
|
* @param string $type database type ($wgDBtype)
|
|
|
|
|
* @return string Class name
|
|
|
|
|
* @since 1.30
|
|
|
|
|
*/
|
|
|
|
|
public static function getDBInstallerClass( $type ) {
|
2020-07-22 22:54:19 +00:00
|
|
|
return ucfirst( $type ) . 'Installer';
|
2017-10-03 05:14:33 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-22 17:58:26 +00:00
|
|
|
* Get an instance of DatabaseInstaller for the specified DB type.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param mixed $type DB installer for which is needed, false to use default.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2010-07-22 17:58:26 +00:00
|
|
|
* @return DatabaseInstaller
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2010-07-22 17:58:26 +00:00
|
|
|
public function getDBInstaller( $type = false ) {
|
|
|
|
|
if ( !$type ) {
|
|
|
|
|
$type = $this->getVar( 'wgDBtype' );
|
|
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2020-07-22 22:54:19 +00:00
|
|
|
$type = strtolower( $type );
|
|
|
|
|
|
2010-07-22 17:58:26 +00:00
|
|
|
if ( !isset( $this->dbInstallers[$type] ) ) {
|
2020-07-22 22:54:19 +00:00
|
|
|
$class = self::getDBInstallerClass( $type );
|
2010-07-22 17:58:26 +00:00
|
|
|
$this->dbInstallers[$type] = new $class( $this );
|
|
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-07-22 17:58:26 +00:00
|
|
|
return $this->dbInstallers[$type];
|
2010-07-29 18:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2014-01-29 23:08:19 +00:00
|
|
|
* Determine if LocalSettings.php exists. If it does, return its variables.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2016-12-08 05:04:53 +00:00
|
|
|
* @return array|false
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2011-06-05 19:52:03 +00:00
|
|
|
public static function getExistingLocalSettings() {
|
2010-07-22 17:58:26 +00:00
|
|
|
global $IP;
|
|
|
|
|
|
2014-07-02 22:40:49 +00:00
|
|
|
// You might be wondering why this is here. Well if you don't do this
|
|
|
|
|
// then some poorly-formed extensions try to call their own classes
|
|
|
|
|
// after immediately registering them. We really need to get extension
|
|
|
|
|
// registration out of the global scope and into a real format.
|
2015-09-12 13:54:13 +00:00
|
|
|
// @see https://phabricator.wikimedia.org/T69440
|
2014-07-02 22:40:49 +00:00
|
|
|
global $wgAutoloadClasses;
|
2016-02-17 09:09:32 +00:00
|
|
|
$wgAutoloadClasses = [];
|
2014-07-02 22:40:49 +00:00
|
|
|
|
2015-07-27 19:04:36 +00:00
|
|
|
// LocalSettings.php should not call functions, except wfLoadSkin/wfLoadExtensions
|
2015-07-28 17:21:58 +00:00
|
|
|
// Define the required globals here, to ensure, the functions can do it work correctly.
|
2018-01-01 13:10:16 +00:00
|
|
|
// phpcs:ignore MediaWiki.VariableAnalysis.UnusedGlobalVariables
|
2015-07-27 19:04:36 +00:00
|
|
|
global $wgExtensionDirectory, $wgStyleDirectory;
|
|
|
|
|
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\suppressWarnings();
|
* Made the web upgrade process more friendly. Instead of saying "access denied, go away" when the user has a normal LocalSettings.php file, generate a random $wgUpgradeKey and instruct the user to insert it into their LocalSettings.php. The subsequent file modification then authenticates the session and allows the upgrade.
* When an upgrade key is entered, or a supplied upgrade key is edited into LocalSettings.php by the upgrader, fetch database settings from LocalSettings.php and AdminSettings.php for use during the upgrade. This allows the DBConnect page to be skipped, making web upgrade almost as easy to use as CLI upgrade.
* Made LocalSettingsGenerator add $wgUpgradeKey in non-commented form, for easier subsequent upgrades.
* Converted the $wgUpgradeKey check to a normal in-sequence page, called ExistingWiki. This allows the removal of related special cases from WebInstaller. The code for WebInstaller_ExistingWiki is loosely based on WebInstaller_Locked.
* Added Status::replaceMessage(), to support informative DB connection error messages from the ExistingWiki page.
* In WebInstaller::getInfoBox(), call parse() with $lineStart=true, so that line-start syntax like bullet points can work.
* Reduced the length of the generated $wgUpgradeKey from 64 to 16. This is ample for what it does, and makes it fit on the screen and not overlap with the right sidebar when when displayed by WebInstaller_ExistingWiki.
* Added $wgUpgradeKey to DefaultSettings.php.
2010-12-09 08:24:54 +00:00
|
|
|
$_lsExists = file_exists( "$IP/LocalSettings.php" );
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\restoreWarnings();
|
2010-07-22 17:58:26 +00:00
|
|
|
|
2013-04-20 21:11:46 +00:00
|
|
|
if ( !$_lsExists ) {
|
* Made the web upgrade process more friendly. Instead of saying "access denied, go away" when the user has a normal LocalSettings.php file, generate a random $wgUpgradeKey and instruct the user to insert it into their LocalSettings.php. The subsequent file modification then authenticates the session and allows the upgrade.
* When an upgrade key is entered, or a supplied upgrade key is edited into LocalSettings.php by the upgrader, fetch database settings from LocalSettings.php and AdminSettings.php for use during the upgrade. This allows the DBConnect page to be skipped, making web upgrade almost as easy to use as CLI upgrade.
* Made LocalSettingsGenerator add $wgUpgradeKey in non-commented form, for easier subsequent upgrades.
* Converted the $wgUpgradeKey check to a normal in-sequence page, called ExistingWiki. This allows the removal of related special cases from WebInstaller. The code for WebInstaller_ExistingWiki is loosely based on WebInstaller_Locked.
* Added Status::replaceMessage(), to support informative DB connection error messages from the ExistingWiki page.
* In WebInstaller::getInfoBox(), call parse() with $lineStart=true, so that line-start syntax like bullet points can work.
* Reduced the length of the generated $wgUpgradeKey from 64 to 16. This is ample for what it does, and makes it fit on the screen and not overlap with the right sidebar when when displayed by WebInstaller_ExistingWiki.
* Added $wgUpgradeKey to DefaultSettings.php.
2010-12-09 08:24:54 +00:00
|
|
|
return false;
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
2013-02-03 19:28:43 +00:00
|
|
|
unset( $_lsExists );
|
2010-12-11 22:54:41 +00:00
|
|
|
|
2013-05-07 23:00:15 +00:00
|
|
|
require "$IP/includes/DefaultSettings.php";
|
|
|
|
|
require "$IP/LocalSettings.php";
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2010-12-11 22:54:41 +00:00
|
|
|
return get_defined_vars();
|
2010-07-29 18:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
|
|
|
|
* Get a fake password for sending back to the user in HTML.
|
|
|
|
|
* This is a security mechanism to avoid compromise of the password in the
|
|
|
|
|
* event of session ID compromise.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param string $realPassword
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2010-07-22 17:58:26 +00:00
|
|
|
* @return string
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2010-07-19 02:41:54 +00:00
|
|
|
public function getFakePassword( $realPassword ) {
|
2010-05-07 12:25:01 +00:00
|
|
|
return str_repeat( '*', strlen( $realPassword ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2010-07-18 18:52:05 +00:00
|
|
|
* Set a variable which stores a password, except if the new value is a
|
2010-05-07 12:25:01 +00:00
|
|
|
* fake password in which case leave it as it is.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param string $name
|
|
|
|
|
* @param mixed $value
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2010-07-19 02:41:54 +00:00
|
|
|
public function setPassword( $name, $value ) {
|
2010-05-07 12:25:01 +00:00
|
|
|
if ( !preg_match( '/^\*+$/', $value ) ) {
|
|
|
|
|
$this->setVar( $name, $value );
|
|
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
}
|
2010-07-22 17:58:26 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* On POSIX systems return the primary group of the webserver we're running under.
|
|
|
|
|
* On other systems just returns null.
|
|
|
|
|
*
|
2011-02-26 12:35:23 +00:00
|
|
|
* This is used to advice the user that he should chgrp his mw-config/data/images directory as the
|
2010-07-22 17:58:26 +00:00
|
|
|
* webserver user before he can install.
|
|
|
|
|
*
|
|
|
|
|
* Public because SqliteInstaller needs it, and doesn't subclass Installer.
|
|
|
|
|
*
|
|
|
|
|
* @return mixed
|
|
|
|
|
*/
|
|
|
|
|
public static function maybeGetWebserverPrimaryGroup() {
|
|
|
|
|
if ( !function_exists( 'posix_getegid' ) || !function_exists( 'posix_getpwuid' ) ) {
|
|
|
|
|
# I don't know this, this isn't UNIX.
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# posix_getegid() *not* getmygid() because we want the group of the webserver,
|
|
|
|
|
# not whoever owns the current script.
|
|
|
|
|
$gid = posix_getegid();
|
2020-02-24 12:07:25 +00:00
|
|
|
return posix_getpwuid( $gid )['name'] ?? null;
|
2010-07-29 18:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
2010-07-22 17:58:26 +00:00
|
|
|
/**
|
|
|
|
|
* Convert wikitext $text to HTML.
|
|
|
|
|
*
|
|
|
|
|
* This is potentially error prone since many parser features require a complete
|
|
|
|
|
* installed MW database. The solution is to just not use those features when you
|
|
|
|
|
* write your messages. This appears to work well enough. Basic formatting and
|
|
|
|
|
* external links work just fine.
|
|
|
|
|
*
|
2012-07-15 20:32:48 +00:00
|
|
|
* But in case a translator decides to throw in a "#ifexist" or internal link or
|
2010-11-11 23:04:55 +00:00
|
|
|
* whatever, this function is guarded to catch the attempted DB access and to present
|
2010-07-22 17:58:26 +00:00
|
|
|
* some fallback text.
|
|
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param string $text
|
|
|
|
|
* @param bool $lineStart
|
|
|
|
|
* @return string
|
2010-07-22 17:58:26 +00:00
|
|
|
*/
|
|
|
|
|
public function parse( $text, $lineStart = false ) {
|
2019-03-03 12:23:47 +00:00
|
|
|
$parser = MediaWikiServices::getInstance()->getParser();
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-07-22 17:58:26 +00:00
|
|
|
try {
|
2019-03-03 12:23:47 +00:00
|
|
|
$out = $parser->parse( $text, $this->parserTitle, $this->parserOptions, $lineStart );
|
2017-11-22 20:07:51 +00:00
|
|
|
$html = $out->getText( [
|
|
|
|
|
'enableSectionEditLinks' => false,
|
2017-12-22 18:32:49 +00:00
|
|
|
'unwrap' => true,
|
2017-11-22 20:07:51 +00:00
|
|
|
] );
|
2019-04-08 02:24:57 +00:00
|
|
|
$html = Parser::stripOuterParagraph( $html );
|
2018-12-10 17:33:38 +00:00
|
|
|
} catch ( Wikimedia\Services\ServiceDisabledException $e ) {
|
2010-07-22 17:58:26 +00:00
|
|
|
$html = '<!--DB access attempted during parse--> ' . htmlspecialchars( $text );
|
|
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-07-22 17:58:26 +00:00
|
|
|
return $html;
|
2010-07-29 18:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
2011-05-02 16:58:29 +00:00
|
|
|
/**
|
|
|
|
|
* @return ParserOptions
|
|
|
|
|
*/
|
2010-12-10 03:02:03 +00:00
|
|
|
public function getParserOptions() {
|
|
|
|
|
return $this->parserOptions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function disableLinkPopups() {
|
|
|
|
|
$this->parserOptions->setExternalLinkTarget( false );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function restoreLinkPopups() {
|
|
|
|
|
global $wgExternalLinkTarget;
|
|
|
|
|
$this->parserOptions->setExternalLinkTarget( $wgExternalLinkTarget );
|
2010-12-16 11:20:39 +00:00
|
|
|
}
|
2010-12-10 03:02:03 +00:00
|
|
|
|
* Fixed a bug causing the installer to ignore the "engine" and "charset" settings when installing a MySQL database.
* Fixed a bug causing the engine and charset settings to not be properly preserved when adding new tables on upgrade.
* Fixed total breakage of SQLite upgrade, by reusing the administrative connection to the SQLite database instead of creating a new one when wfGetDB() is called. Added LBFactory_Single to support this.
* Introduced a "schema variable" concept to DatabaseBase to avoid the use of globals for communication between the installer and the Database. Removed a lot of old global variable names from Database::replaceVars(), most were only added on a whim and were never used.
* Introduced DatabaseInstaller::getSchemaVars(), to allow schema variables to be supplied by the DatabaseInstaller child classes.
* Removed messages config-mysql-egine-mismatch [sic] and config-mysql-charset-mismatch. In the old installer it was possible for users to request a certain character set for an upgrade, but in the new installer the question is never asked. So these warnings were shown whenever a non-default character set or engine was used in the old database.
* In MysqlInstaller::preUpgrade(), fixed the incorrect strings used to identify the MySQL character sets: mysql5 instead of utf8 and mysql5-binary instead of binary.
* On install, initialise the site_stats table, using code copied from the old installer. Unlike the old installer, use SiteStats to increment the user count when the initial user is added.
* Fixed several instances of inappropriate call-by-reference.
* Replaced call_user_func_array() with call_user_func() where possible, it is shorter and simpler.
* Moved the caching boilerplate for DatabaseInstaller::getConnection() to the base class, and have the derived classes override an uncached function openConnection() instead. Updates r80892.
* In MysqlInstaller::getLocalSettings(), escape PHP strings correctly with LocalSettingsGenerator::escapePhpString().
* Reduce timeout for checks in dirIsExecutable() to 3 seconds, so that it doesn't take 30s to run when apache is in single-threaded mode for debugging.
* MySQL and SQLite have been tested and they appear to work. PostgreSQL upgrade is totally broken, apparently it was like that before I started. The Oracle code is untested.
2011-01-25 07:37:48 +00:00
|
|
|
/**
|
2011-01-25 18:24:16 +00:00
|
|
|
* Install step which adds a row to the site_stats table with appropriate
|
* Fixed a bug causing the installer to ignore the "engine" and "charset" settings when installing a MySQL database.
* Fixed a bug causing the engine and charset settings to not be properly preserved when adding new tables on upgrade.
* Fixed total breakage of SQLite upgrade, by reusing the administrative connection to the SQLite database instead of creating a new one when wfGetDB() is called. Added LBFactory_Single to support this.
* Introduced a "schema variable" concept to DatabaseBase to avoid the use of globals for communication between the installer and the Database. Removed a lot of old global variable names from Database::replaceVars(), most were only added on a whim and were never used.
* Introduced DatabaseInstaller::getSchemaVars(), to allow schema variables to be supplied by the DatabaseInstaller child classes.
* Removed messages config-mysql-egine-mismatch [sic] and config-mysql-charset-mismatch. In the old installer it was possible for users to request a certain character set for an upgrade, but in the new installer the question is never asked. So these warnings were shown whenever a non-default character set or engine was used in the old database.
* In MysqlInstaller::preUpgrade(), fixed the incorrect strings used to identify the MySQL character sets: mysql5 instead of utf8 and mysql5-binary instead of binary.
* On install, initialise the site_stats table, using code copied from the old installer. Unlike the old installer, use SiteStats to increment the user count when the initial user is added.
* Fixed several instances of inappropriate call-by-reference.
* Replaced call_user_func_array() with call_user_func() where possible, it is shorter and simpler.
* Moved the caching boilerplate for DatabaseInstaller::getConnection() to the base class, and have the derived classes override an uncached function openConnection() instead. Updates r80892.
* In MysqlInstaller::getLocalSettings(), escape PHP strings correctly with LocalSettingsGenerator::escapePhpString().
* Reduce timeout for checks in dirIsExecutable() to 3 seconds, so that it doesn't take 30s to run when apache is in single-threaded mode for debugging.
* MySQL and SQLite have been tested and they appear to work. PostgreSQL upgrade is totally broken, apparently it was like that before I started. The Oracle code is untested.
2011-01-25 07:37:48 +00:00
|
|
|
* initial values.
|
2011-05-02 16:58:29 +00:00
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param DatabaseInstaller $installer
|
2011-05-02 16:58:29 +00:00
|
|
|
*
|
|
|
|
|
* @return Status
|
* Fixed a bug causing the installer to ignore the "engine" and "charset" settings when installing a MySQL database.
* Fixed a bug causing the engine and charset settings to not be properly preserved when adding new tables on upgrade.
* Fixed total breakage of SQLite upgrade, by reusing the administrative connection to the SQLite database instead of creating a new one when wfGetDB() is called. Added LBFactory_Single to support this.
* Introduced a "schema variable" concept to DatabaseBase to avoid the use of globals for communication between the installer and the Database. Removed a lot of old global variable names from Database::replaceVars(), most were only added on a whim and were never used.
* Introduced DatabaseInstaller::getSchemaVars(), to allow schema variables to be supplied by the DatabaseInstaller child classes.
* Removed messages config-mysql-egine-mismatch [sic] and config-mysql-charset-mismatch. In the old installer it was possible for users to request a certain character set for an upgrade, but in the new installer the question is never asked. So these warnings were shown whenever a non-default character set or engine was used in the old database.
* In MysqlInstaller::preUpgrade(), fixed the incorrect strings used to identify the MySQL character sets: mysql5 instead of utf8 and mysql5-binary instead of binary.
* On install, initialise the site_stats table, using code copied from the old installer. Unlike the old installer, use SiteStats to increment the user count when the initial user is added.
* Fixed several instances of inappropriate call-by-reference.
* Replaced call_user_func_array() with call_user_func() where possible, it is shorter and simpler.
* Moved the caching boilerplate for DatabaseInstaller::getConnection() to the base class, and have the derived classes override an uncached function openConnection() instead. Updates r80892.
* In MysqlInstaller::getLocalSettings(), escape PHP strings correctly with LocalSettingsGenerator::escapePhpString().
* Reduce timeout for checks in dirIsExecutable() to 3 seconds, so that it doesn't take 30s to run when apache is in single-threaded mode for debugging.
* MySQL and SQLite have been tested and they appear to work. PostgreSQL upgrade is totally broken, apparently it was like that before I started. The Oracle code is untested.
2011-01-25 07:37:48 +00:00
|
|
|
*/
|
|
|
|
|
public function populateSiteStats( DatabaseInstaller $installer ) {
|
|
|
|
|
$status = $installer->getConnection();
|
|
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
2019-08-31 16:14:38 +00:00
|
|
|
// @phan-suppress-next-line PhanUndeclaredMethod
|
2014-02-05 11:02:29 +00:00
|
|
|
$status->value->insert(
|
|
|
|
|
'site_stats',
|
2016-02-17 09:09:32 +00:00
|
|
|
[
|
2014-02-05 11:02:29 +00:00
|
|
|
'ss_row_id' => 1,
|
|
|
|
|
'ss_total_edits' => 0,
|
|
|
|
|
'ss_good_articles' => 0,
|
|
|
|
|
'ss_total_pages' => 0,
|
|
|
|
|
'ss_users' => 0,
|
2017-04-22 19:23:11 +00:00
|
|
|
'ss_active_users' => 0,
|
2014-02-05 11:02:29 +00:00
|
|
|
'ss_images' => 0
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2020-10-28 03:31:03 +00:00
|
|
|
__METHOD__,
|
|
|
|
|
'IGNORE'
|
2014-02-05 11:02:29 +00:00
|
|
|
);
|
2013-10-08 11:43:42 +00:00
|
|
|
|
* Fixed a bug causing the installer to ignore the "engine" and "charset" settings when installing a MySQL database.
* Fixed a bug causing the engine and charset settings to not be properly preserved when adding new tables on upgrade.
* Fixed total breakage of SQLite upgrade, by reusing the administrative connection to the SQLite database instead of creating a new one when wfGetDB() is called. Added LBFactory_Single to support this.
* Introduced a "schema variable" concept to DatabaseBase to avoid the use of globals for communication between the installer and the Database. Removed a lot of old global variable names from Database::replaceVars(), most were only added on a whim and were never used.
* Introduced DatabaseInstaller::getSchemaVars(), to allow schema variables to be supplied by the DatabaseInstaller child classes.
* Removed messages config-mysql-egine-mismatch [sic] and config-mysql-charset-mismatch. In the old installer it was possible for users to request a certain character set for an upgrade, but in the new installer the question is never asked. So these warnings were shown whenever a non-default character set or engine was used in the old database.
* In MysqlInstaller::preUpgrade(), fixed the incorrect strings used to identify the MySQL character sets: mysql5 instead of utf8 and mysql5-binary instead of binary.
* On install, initialise the site_stats table, using code copied from the old installer. Unlike the old installer, use SiteStats to increment the user count when the initial user is added.
* Fixed several instances of inappropriate call-by-reference.
* Replaced call_user_func_array() with call_user_func() where possible, it is shorter and simpler.
* Moved the caching boilerplate for DatabaseInstaller::getConnection() to the base class, and have the derived classes override an uncached function openConnection() instead. Updates r80892.
* In MysqlInstaller::getLocalSettings(), escape PHP strings correctly with LocalSettingsGenerator::escapePhpString().
* Reduce timeout for checks in dirIsExecutable() to 3 seconds, so that it doesn't take 30s to run when apache is in single-threaded mode for debugging.
* MySQL and SQLite have been tested and they appear to work. PostgreSQL upgrade is totally broken, apparently it was like that before I started. The Oracle code is untested.
2011-01-25 07:37:48 +00:00
|
|
|
return Status::newGood();
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-22 17:58:26 +00:00
|
|
|
/**
|
|
|
|
|
* Environment check for DB types.
|
2011-11-22 16:31:33 +00:00
|
|
|
* @return bool
|
2010-07-22 17:58:26 +00:00
|
|
|
*/
|
2010-11-16 15:50:32 +00:00
|
|
|
protected function envCheckDB() {
|
2010-07-21 17:20:50 +00:00
|
|
|
global $wgLang;
|
2019-07-27 15:38:54 +00:00
|
|
|
/** @var string|null $dbType The user-specified database type */
|
|
|
|
|
$dbType = $this->getVar( 'wgDBtype' );
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$allNames = [];
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2019-08-14 15:04:50 +00:00
|
|
|
// Messages: config-type-mysql, config-type-postgres, config-type-sqlite
|
2020-07-22 22:54:19 +00:00
|
|
|
foreach ( self::getDBTypes() as $name ) {
|
2012-08-29 08:07:10 +00:00
|
|
|
$allNames[] = wfMessage( "config-type-$name" )->text();
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2013-05-25 10:59:13 +00:00
|
|
|
$databases = $this->getCompiledDBs();
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2013-10-08 11:43:42 +00:00
|
|
|
$databases = array_flip( $databases );
|
2019-07-27 15:38:54 +00:00
|
|
|
$ok = true;
|
2012-01-04 10:41:39 +00:00
|
|
|
foreach ( array_keys( $databases ) as $db ) {
|
|
|
|
|
$installer = $this->getDBInstaller( $db );
|
|
|
|
|
$status = $installer->checkPrerequisites();
|
|
|
|
|
if ( !$status->isGood() ) {
|
2019-07-27 15:38:54 +00:00
|
|
|
if ( !$this instanceof WebInstaller && $db === $dbType ) {
|
|
|
|
|
// Strictly check the key database type instead of just outputting message
|
|
|
|
|
// Note: No perform this check run from the web installer, since this method always called by
|
|
|
|
|
// the welcome page under web installation, so $dbType will always be 'mysql'
|
|
|
|
|
$ok = false;
|
|
|
|
|
}
|
2012-01-04 10:41:39 +00:00
|
|
|
$this->showStatusMessage( $status );
|
|
|
|
|
unset( $databases[$db] );
|
2010-12-07 18:29:04 +00:00
|
|
|
}
|
2010-10-01 21:06:32 +00:00
|
|
|
}
|
2012-01-04 10:41:39 +00:00
|
|
|
$databases = array_flip( $databases );
|
|
|
|
|
if ( !$databases ) {
|
2015-01-14 16:29:59 +00:00
|
|
|
$this->showError( 'config-no-db', $wgLang->commaList( $allNames ), count( $allNames ) );
|
2012-01-04 10:41:39 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2019-07-27 15:38:54 +00:00
|
|
|
return $ok;
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
2010-07-21 17:20:50 +00:00
|
|
|
/**
|
|
|
|
|
* Environment check for the PCRE module.
|
2012-08-29 08:07:10 +00:00
|
|
|
*
|
|
|
|
|
* @note If this check were to fail, the parser would
|
|
|
|
|
* probably throw an exception before the result
|
|
|
|
|
* of this check is shown to the user.
|
2012-02-09 21:35:05 +00:00
|
|
|
* @return bool
|
2010-07-21 17:20:50 +00:00
|
|
|
*/
|
2010-11-16 15:50:32 +00:00
|
|
|
protected function envCheckPCRE() {
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\suppressWarnings();
|
2011-02-19 07:27:27 +00:00
|
|
|
$regexd = preg_replace( '/[\x{0430}-\x{04FF}]/iu', '', '-АБВГД-' );
|
2012-08-29 08:07:10 +00:00
|
|
|
// Need to check for \p support too, as PCRE can be compiled
|
|
|
|
|
// with utf8 support, but not unicode property support.
|
|
|
|
|
// check that \p{Zs} (space separators) matches
|
|
|
|
|
// U+3000 (Ideographic space)
|
2017-10-07 00:26:23 +00:00
|
|
|
$regexprop = preg_replace( '/\p{Zs}/u', '', "-\u{3000}-" );
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\restoreWarnings();
|
2012-08-29 08:07:10 +00:00
|
|
|
if ( $regexd != '--' || $regexprop != '--' ) {
|
2011-04-27 18:22:01 +00:00
|
|
|
$this->showError( 'config-pcre-no-utf8' );
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2010-11-10 16:45:28 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2012-03-01 19:12:07 +00:00
|
|
|
return true;
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
2010-07-21 17:20:50 +00:00
|
|
|
/**
|
|
|
|
|
* Environment check for available memory.
|
2012-02-09 21:35:05 +00:00
|
|
|
* @return bool
|
2010-07-21 17:20:50 +00:00
|
|
|
*/
|
2010-11-16 15:50:32 +00:00
|
|
|
protected function envCheckMemory() {
|
2010-05-07 12:25:01 +00:00
|
|
|
$limit = ini_get( 'memory_limit' );
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
if ( !$limit || $limit == -1 ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2011-01-25 22:42:53 +00:00
|
|
|
$n = wfShorthandToInteger( $limit );
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2013-04-20 21:11:46 +00:00
|
|
|
if ( $n < $this->minMemorySize * 1024 * 1024 ) {
|
2010-05-07 12:25:01 +00:00
|
|
|
$newLimit = "{$this->minMemorySize}M";
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2013-04-20 21:11:46 +00:00
|
|
|
if ( ini_set( "memory_limit", $newLimit ) === false ) {
|
2010-05-07 12:25:01 +00:00
|
|
|
$this->showMessage( 'config-memory-bad', $limit );
|
|
|
|
|
} else {
|
|
|
|
|
$this->showMessage( 'config-memory-raised', $limit, $newLimit );
|
|
|
|
|
$this->setVar( '_RaiseMemory', true );
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2012-03-01 19:12:07 +00:00
|
|
|
return true;
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
2010-07-21 17:20:50 +00:00
|
|
|
/**
|
|
|
|
|
* Environment check for compiled object cache types.
|
|
|
|
|
*/
|
2010-11-16 15:50:32 +00:00
|
|
|
protected function envCheckCache() {
|
2016-02-17 09:09:32 +00:00
|
|
|
$caches = [];
|
2010-05-07 12:25:01 +00:00
|
|
|
foreach ( $this->objectCaches as $name => $function ) {
|
|
|
|
|
if ( function_exists( $function ) ) {
|
|
|
|
|
$caches[$name] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
if ( !$caches ) {
|
2019-03-09 22:15:20 +00:00
|
|
|
$this->showMessage( 'config-no-cache-apcu' );
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
$this->setVar( '_Caches', $caches );
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-06 16:39:59 +00:00
|
|
|
/**
|
2014-09-20 15:29:05 +00:00
|
|
|
* Scare user to death if they have mod_security or mod_security2
|
2012-03-01 19:12:07 +00:00
|
|
|
* @return bool
|
2011-08-06 16:39:59 +00:00
|
|
|
*/
|
|
|
|
|
protected function envCheckModSecurity() {
|
2014-09-20 15:29:05 +00:00
|
|
|
if ( self::apacheModulePresent( 'mod_security' )
|
|
|
|
|
|| self::apacheModulePresent( 'mod_security2' ) ) {
|
2011-08-06 16:39:59 +00:00
|
|
|
$this->showMessage( 'config-mod-security' );
|
|
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2012-03-01 19:12:07 +00:00
|
|
|
return true;
|
2011-08-06 16:39:59 +00:00
|
|
|
}
|
|
|
|
|
|
2010-07-21 17:20:50 +00:00
|
|
|
/**
|
|
|
|
|
* Search for GNU diff3.
|
2012-03-01 19:12:07 +00:00
|
|
|
* @return bool
|
2010-07-21 17:20:50 +00:00
|
|
|
*/
|
2010-11-16 15:50:32 +00:00
|
|
|
protected function envCheckDiff3() {
|
2017-10-20 07:36:03 +00:00
|
|
|
$names = [ "gdiff3", "diff3" ];
|
|
|
|
|
if ( wfIsWindows() ) {
|
|
|
|
|
$names[] = 'diff3.exe';
|
|
|
|
|
}
|
|
|
|
|
$versionInfo = [ '--version', 'GNU diffutils' ];
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2017-10-20 07:36:03 +00:00
|
|
|
$diff3 = ExecutableFinder::findInDefaultPaths( $names, $versionInfo );
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-10-17 17:20:12 +00:00
|
|
|
if ( $diff3 ) {
|
|
|
|
|
$this->setVar( 'wgDiff3', $diff3 );
|
2010-05-07 12:25:01 +00:00
|
|
|
} else {
|
|
|
|
|
$this->setVar( 'wgDiff3', false );
|
|
|
|
|
$this->showMessage( 'config-diff3-bad' );
|
2010-07-22 17:58:26 +00:00
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2012-03-01 19:12:07 +00:00
|
|
|
return true;
|
2010-07-29 18:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
2010-07-21 17:20:50 +00:00
|
|
|
/**
|
|
|
|
|
* Environment check for ImageMagick and GD.
|
2012-02-09 21:35:05 +00:00
|
|
|
* @return bool
|
2010-07-21 17:20:50 +00:00
|
|
|
*/
|
2010-11-16 15:50:32 +00:00
|
|
|
protected function envCheckGraphics() {
|
2017-10-20 07:36:03 +00:00
|
|
|
$names = wfIsWindows() ? 'convert.exe' : 'convert';
|
|
|
|
|
$versionInfo = [ '-version', 'ImageMagick' ];
|
|
|
|
|
$convert = ExecutableFinder::findInDefaultPaths( $names, $versionInfo );
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2011-03-07 18:45:43 +00:00
|
|
|
$this->setVar( 'wgImageMagickConvertCommand', '' );
|
2010-10-17 17:20:12 +00:00
|
|
|
if ( $convert ) {
|
|
|
|
|
$this->setVar( 'wgImageMagickConvertCommand', $convert );
|
|
|
|
|
$this->showMessage( 'config-imagemagick', $convert );
|
2010-10-16 18:19:00 +00:00
|
|
|
} elseif ( function_exists( 'imagejpeg' ) ) {
|
2010-05-07 12:25:01 +00:00
|
|
|
$this->showMessage( 'config-gd' );
|
2010-10-16 18:19:00 +00:00
|
|
|
} else {
|
2011-04-01 18:24:37 +00:00
|
|
|
$this->showMessage( 'config-no-scaling' );
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2012-03-01 19:12:07 +00:00
|
|
|
return true;
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
2012-08-01 20:49:17 +00:00
|
|
|
/**
|
|
|
|
|
* Search for git.
|
|
|
|
|
*
|
|
|
|
|
* @since 1.22
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
protected function envCheckGit() {
|
2017-10-20 07:36:03 +00:00
|
|
|
$names = wfIsWindows() ? 'git.exe' : 'git';
|
|
|
|
|
$versionInfo = [ '--version', 'git version' ];
|
2012-08-01 20:49:17 +00:00
|
|
|
|
2017-10-20 07:36:03 +00:00
|
|
|
$git = ExecutableFinder::findInDefaultPaths( $names, $versionInfo );
|
2012-08-01 20:49:17 +00:00
|
|
|
|
|
|
|
|
if ( $git ) {
|
|
|
|
|
$this->setVar( 'wgGitBin', $git );
|
|
|
|
|
$this->showMessage( 'config-git', $git );
|
|
|
|
|
} else {
|
|
|
|
|
$this->setVar( 'wgGitBin', false );
|
|
|
|
|
$this->showMessage( 'config-git-bad' );
|
|
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2012-08-01 20:49:17 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-15 07:35:47 +00:00
|
|
|
/**
|
2014-07-10 16:27:11 +00:00
|
|
|
* Environment check to inform user which server we've assumed.
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
2011-06-15 07:35:47 +00:00
|
|
|
*/
|
2011-12-12 15:12:38 +00:00
|
|
|
protected function envCheckServer() {
|
2011-12-12 15:11:08 +00:00
|
|
|
$server = $this->envGetDefaultServer();
|
2013-10-06 19:41:18 +00:00
|
|
|
if ( $server !== null ) {
|
|
|
|
|
$this->showMessage( 'config-using-server', $server );
|
|
|
|
|
}
|
2012-03-01 19:12:07 +00:00
|
|
|
return true;
|
2011-06-15 07:35:47 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-12 15:11:08 +00:00
|
|
|
/**
|
2014-07-10 16:27:11 +00:00
|
|
|
* Environment check to inform user which paths we've assumed.
|
|
|
|
|
*
|
2011-11-22 16:31:33 +00:00
|
|
|
* @return bool
|
2010-07-21 17:31:00 +00:00
|
|
|
*/
|
2010-11-16 15:50:32 +00:00
|
|
|
protected function envCheckPath() {
|
2013-10-23 12:16:03 +00:00
|
|
|
$this->showMessage(
|
|
|
|
|
'config-using-uri',
|
|
|
|
|
$this->getVar( 'wgServer' ),
|
|
|
|
|
$this->getVar( 'wgScriptPath' )
|
|
|
|
|
);
|
2012-03-01 19:12:07 +00:00
|
|
|
return true;
|
2010-05-07 12:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
2010-07-22 17:58:26 +00:00
|
|
|
/**
|
2013-04-06 05:52:05 +00:00
|
|
|
* Environment check for the permissions of the uploads directory
|
2012-02-09 21:35:05 +00:00
|
|
|
* @return bool
|
2010-07-22 17:58:26 +00:00
|
|
|
*/
|
2010-11-16 15:50:32 +00:00
|
|
|
protected function envCheckUploadsDirectory() {
|
2011-06-15 07:35:47 +00:00
|
|
|
global $IP;
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
$dir = $IP . '/images/';
|
2011-06-15 07:35:47 +00:00
|
|
|
$url = $this->getVar( 'wgServer' ) . $this->getVar( 'wgScriptPath' ) . '/images/';
|
2010-05-07 12:25:01 +00:00
|
|
|
$safe = !$this->dirIsExecutable( $dir, $url );
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2012-03-01 19:12:07 +00:00
|
|
|
if ( !$safe ) {
|
2010-05-07 12:25:01 +00:00
|
|
|
$this->showMessage( 'config-uploads-not-safe', $dir );
|
|
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2012-03-01 19:12:07 +00:00
|
|
|
return true;
|
2010-07-29 18:18:03 +00:00
|
|
|
}
|
2011-05-20 18:20:16 +00:00
|
|
|
|
2011-05-05 11:52:23 +00:00
|
|
|
/**
|
2013-06-04 23:02:10 +00:00
|
|
|
* Checks if suhosin.get.max_value_length is set, and if so generate
|
2019-08-31 22:30:22 +00:00
|
|
|
* a warning because it is incompatible with ResourceLoader.
|
2012-03-01 19:12:07 +00:00
|
|
|
* @return bool
|
2011-05-05 11:52:23 +00:00
|
|
|
*/
|
|
|
|
|
protected function envCheckSuhosinMaxValueLength() {
|
2019-08-31 22:30:22 +00:00
|
|
|
$currentValue = ini_get( 'suhosin.get.max_value_length' );
|
|
|
|
|
$minRequired = 2000;
|
|
|
|
|
$recommended = 5000;
|
|
|
|
|
if ( $currentValue > 0 && $currentValue < $minRequired ) {
|
|
|
|
|
$this->showError( 'config-suhosin-max-value-length', $currentValue, $minRequired, $recommended );
|
|
|
|
|
return false;
|
2011-05-05 11:52:23 +00:00
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2012-03-01 19:12:07 +00:00
|
|
|
return true;
|
2011-05-05 11:52:23 +00:00
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2017-07-31 22:28:47 +00:00
|
|
|
/**
|
|
|
|
|
* Checks if we're running on 64 bit or not. 32 bit is becoming increasingly
|
|
|
|
|
* hard to support, so let's at least warn people.
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
protected function envCheck64Bit() {
|
|
|
|
|
if ( PHP_INT_SIZE == 4 ) {
|
|
|
|
|
$this->showMessage( 'config-using-32bit' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-29 02:44:23 +00:00
|
|
|
/**
|
|
|
|
|
* Check the libicu version
|
|
|
|
|
*/
|
2010-11-16 15:50:32 +00:00
|
|
|
protected function envCheckLibicu() {
|
2010-07-29 02:44:23 +00:00
|
|
|
/**
|
|
|
|
|
* This needs to be updated something that the latest libicu
|
|
|
|
|
* will properly normalize. This normalization was found at
|
2017-12-02 20:38:29 +00:00
|
|
|
* https://www.unicode.org/versions/Unicode5.2.0/#Character_Additions
|
2010-07-29 02:44:23 +00:00
|
|
|
* Note that we use the hex representation to create the code
|
2010-07-29 19:28:16 +00:00
|
|
|
* points in order to avoid any Unicode-destroying during transit.
|
2010-07-29 02:44:23 +00:00
|
|
|
*/
|
2018-01-08 22:18:00 +00:00
|
|
|
$not_normal_c = "\u{FA6C}";
|
|
|
|
|
$normal_c = "\u{242EE}";
|
2010-07-29 02:44:23 +00:00
|
|
|
|
2020-11-29 00:13:24 +00:00
|
|
|
$intl = normalizer_normalize( $not_normal_c, Normalizer::FORM_C );
|
2010-07-29 02:44:23 +00:00
|
|
|
|
2020-11-29 00:13:24 +00:00
|
|
|
$this->showMessage( 'config-unicode-using-intl' );
|
|
|
|
|
if ( $intl !== $normal_c ) {
|
|
|
|
|
$this->showMessage( 'config-unicode-update-warning' );
|
2010-07-29 02:44:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-10 16:27:11 +00:00
|
|
|
/**
|
|
|
|
|
* Environment prep for the server hostname.
|
|
|
|
|
*/
|
|
|
|
|
protected function envPrepServer() {
|
|
|
|
|
$server = $this->envGetDefaultServer();
|
|
|
|
|
if ( $server !== null ) {
|
|
|
|
|
$this->setVar( 'wgServer', $server );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Helper function to be called from envPrepServer()
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
abstract protected function envGetDefaultServer();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Environment prep for setting $IP and $wgScriptPath.
|
|
|
|
|
*/
|
|
|
|
|
protected function envPrepPath() {
|
|
|
|
|
global $IP;
|
|
|
|
|
$IP = dirname( dirname( __DIR__ ) );
|
|
|
|
|
$this->setVar( 'IP', $IP );
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
/**
|
2010-07-19 02:41:54 +00:00
|
|
|
* Checks if scripts located in the given directory can be executed via the given URL.
|
2010-07-29 18:18:03 +00:00
|
|
|
*
|
2010-07-22 17:58:26 +00:00
|
|
|
* Used only by environment checks.
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param string $dir
|
|
|
|
|
* @param string $url
|
2012-02-09 21:35:05 +00:00
|
|
|
* @return bool|int|string
|
2010-05-07 12:25:01 +00:00
|
|
|
*/
|
2010-07-19 02:41:54 +00:00
|
|
|
public function dirIsExecutable( $dir, $url ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$scriptTypes = [
|
|
|
|
|
'php' => [
|
2019-03-01 21:15:22 +00:00
|
|
|
"<?php echo 'exec';",
|
|
|
|
|
"#!/var/env php\n<?php echo 'exec';",
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
];
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-07-21 17:31:00 +00:00
|
|
|
// it would be good to check other popular languages here, but it'll be slow.
|
2020-10-28 03:31:03 +00:00
|
|
|
// TODO no need to have a loop if there is going to only be one script type
|
|
|
|
|
|
|
|
|
|
$httpRequestFactory = MediaWikiServices::getInstance()->getHttpRequestFactory();
|
2010-05-07 12:25:01 +00:00
|
|
|
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\suppressWarnings();
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
foreach ( $scriptTypes as $ext => $contents ) {
|
|
|
|
|
foreach ( $contents as $source ) {
|
|
|
|
|
$file = 'exectest.' . $ext;
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
if ( !file_put_contents( $dir . $file, $source ) ) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2011-05-20 21:42:41 +00:00
|
|
|
try {
|
2020-10-28 03:31:03 +00:00
|
|
|
$text = $httpRequestFactory->get(
|
|
|
|
|
$url . $file,
|
|
|
|
|
[ 'timeout' => 3 ],
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
2015-01-09 23:44:47 +00:00
|
|
|
} catch ( Exception $e ) {
|
2019-04-15 13:23:02 +00:00
|
|
|
// HttpRequestFactory::get can throw with allow_url_fopen = false and no curl
|
|
|
|
|
// extension.
|
2011-05-20 21:42:41 +00:00
|
|
|
$text = null;
|
|
|
|
|
}
|
2010-05-07 12:25:01 +00:00
|
|
|
unlink( $dir . $file );
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
if ( $text == 'exec' ) {
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\restoreWarnings();
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
return $ext;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\restoreWarnings();
|
2010-07-29 18:18:03 +00:00
|
|
|
|
2010-05-07 12:25:01 +00:00
|
|
|
return false;
|
2010-07-29 18:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
2011-08-06 16:39:59 +00:00
|
|
|
/**
|
|
|
|
|
* Checks for presence of an Apache module. Works only if PHP is running as an Apache module, too.
|
2011-10-11 03:49:40 +00:00
|
|
|
*
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $moduleName Name of module to check.
|
2011-08-06 16:39:59 +00:00
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public static function apacheModulePresent( $moduleName ) {
|
|
|
|
|
if ( function_exists( 'apache_get_modules' ) && in_array( $moduleName, apache_get_modules() ) ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// try it the hard way
|
|
|
|
|
ob_start();
|
|
|
|
|
phpinfo( INFO_MODULES );
|
|
|
|
|
$info = ob_get_clean();
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2011-08-06 16:39:59 +00:00
|
|
|
return strpos( $info, $moduleName ) !== false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-21 15:27:16 +00:00
|
|
|
/**
|
|
|
|
|
* ParserOptions are constructed before we determined the language, so fix it
|
2011-05-28 14:52:55 +00:00
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param Language $lang
|
2011-01-21 15:27:16 +00:00
|
|
|
*/
|
|
|
|
|
public function setParserLanguage( $lang ) {
|
|
|
|
|
$this->parserOptions->setTargetLanguage( $lang );
|
2011-10-19 14:16:01 +00:00
|
|
|
$this->parserOptions->setUserLang( $lang );
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Overridden by WebInstaller to provide lastPage parameters.
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param string $page
|
2011-10-18 17:26:09 +00:00
|
|
|
* @return string
|
2011-01-21 15:27:16 +00:00
|
|
|
*/
|
|
|
|
|
protected function getDocUrl( $page ) {
|
|
|
|
|
return "{$_SERVER['PHP_SELF']}?page=" . urlencode( $page );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
* Find extensions or skins in a subdirectory of $IP.
|
|
|
|
|
* Returns an array containing the value for 'Name' for each found extension.
|
2011-01-21 15:27:16 +00:00
|
|
|
*
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
* @param string $directory Directory to search in, relative to $IP, must be either "extensions"
|
|
|
|
|
* or "skins"
|
2019-09-05 14:34:36 +00:00
|
|
|
* @return Status An object containing an error list. If there were no errors, an associative
|
|
|
|
|
* array of information about the extension can be found in $status->value.
|
2011-01-21 15:27:16 +00:00
|
|
|
*/
|
2014-06-10 11:41:29 +00:00
|
|
|
public function findExtensions( $directory = 'extensions' ) {
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
switch ( $directory ) {
|
|
|
|
|
case 'extensions':
|
|
|
|
|
return $this->findExtensionsByType( 'extension', 'extensions' );
|
|
|
|
|
case 'skins':
|
|
|
|
|
return $this->findExtensionsByType( 'skin', 'skins' );
|
|
|
|
|
default:
|
|
|
|
|
throw new InvalidArgumentException( "Invalid extension type" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Find extensions or skins, and return an array containing the value for 'Name' for each found
|
|
|
|
|
* extension.
|
|
|
|
|
*
|
|
|
|
|
* @param string $type Either "extension" or "skin"
|
|
|
|
|
* @param string $directory Directory to search in, relative to $IP
|
2019-09-05 14:34:36 +00:00
|
|
|
* @return Status An object containing an error list. If there were no errors, an associative
|
|
|
|
|
* array of information about the extension can be found in $status->value.
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
*/
|
|
|
|
|
protected function findExtensionsByType( $type = 'extension', $directory = 'extensions' ) {
|
2013-04-20 21:11:46 +00:00
|
|
|
if ( $this->getVar( 'IP' ) === null ) {
|
2019-09-05 14:34:36 +00:00
|
|
|
return Status::newGood( [] );
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
2014-06-10 11:41:29 +00:00
|
|
|
$extDir = $this->getVar( 'IP' ) . '/' . $directory;
|
2013-03-22 17:53:51 +00:00
|
|
|
if ( !is_readable( $extDir ) || !is_dir( $extDir ) ) {
|
2019-09-05 14:34:36 +00:00
|
|
|
return Status::newGood( [] );
|
2013-03-22 17:53:51 +00:00
|
|
|
}
|
2011-01-21 15:27:16 +00:00
|
|
|
|
2021-08-28 08:40:44 +00:00
|
|
|
// @phan-suppress-next-line SecurityCheck-PathTraversal False positive
|
2013-03-22 17:53:51 +00:00
|
|
|
$dh = opendir( $extDir );
|
2016-02-17 09:09:32 +00:00
|
|
|
$exts = [];
|
2019-09-05 14:34:36 +00:00
|
|
|
$status = new Status;
|
2011-01-21 15:27:16 +00:00
|
|
|
while ( ( $file = readdir( $dh ) ) !== false ) {
|
2019-09-05 14:34:36 +00:00
|
|
|
// skip non-dirs and hidden directories
|
|
|
|
|
if ( !is_dir( "$extDir/$file" ) || $file[0] === '.' ) {
|
2011-05-20 22:08:04 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
2019-09-05 14:34:36 +00:00
|
|
|
$extStatus = $this->getExtensionInfo( $type, $directory, $file );
|
|
|
|
|
if ( $extStatus->isOK() ) {
|
|
|
|
|
$exts[$file] = $extStatus->value;
|
|
|
|
|
} elseif ( $extStatus->hasMessage( 'config-extension-not-found' ) ) {
|
|
|
|
|
// (T225512) The directory is not actually an extension. Downgrade to warning.
|
|
|
|
|
$status->warning( 'config-extension-not-found', $file );
|
|
|
|
|
} else {
|
|
|
|
|
$status->merge( $extStatus );
|
2018-04-08 23:26:01 +00:00
|
|
|
}
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
2013-03-22 17:53:51 +00:00
|
|
|
closedir( $dh );
|
2017-08-26 16:53:44 +00:00
|
|
|
uksort( $exts, 'strnatcasecmp' );
|
2014-01-12 23:59:44 +00:00
|
|
|
|
2019-09-05 14:34:36 +00:00
|
|
|
$status->value = $exts;
|
|
|
|
|
|
|
|
|
|
return $status;
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
/**
|
|
|
|
|
* @param string $type Either "extension" or "skin"
|
|
|
|
|
* @param string $parentRelPath The parent directory relative to $IP
|
|
|
|
|
* @param string $name The extension or skin name
|
|
|
|
|
* @return Status An object containing an error list. If there were no errors, an associative
|
|
|
|
|
* array of information about the extension can be found in $status->value.
|
|
|
|
|
*/
|
|
|
|
|
protected function getExtensionInfo( $type, $parentRelPath, $name ) {
|
|
|
|
|
if ( $this->getVar( 'IP' ) === null ) {
|
|
|
|
|
throw new Exception( 'Cannot find extensions since the IP variable is not yet set' );
|
|
|
|
|
}
|
|
|
|
|
if ( $type !== 'extension' && $type !== 'skin' ) {
|
|
|
|
|
throw new InvalidArgumentException( "Invalid extension type" );
|
|
|
|
|
}
|
|
|
|
|
$absDir = $this->getVar( 'IP' ) . "/$parentRelPath/$name";
|
|
|
|
|
$relDir = "../$parentRelPath/$name";
|
|
|
|
|
if ( !is_dir( $absDir ) ) {
|
|
|
|
|
return Status::newFatal( 'config-extension-not-found', $name );
|
|
|
|
|
}
|
|
|
|
|
$jsonFile = $type . '.json';
|
|
|
|
|
$fullJsonFile = "$absDir/$jsonFile";
|
|
|
|
|
$isJson = file_exists( $fullJsonFile );
|
|
|
|
|
$isPhp = false;
|
|
|
|
|
if ( !$isJson ) {
|
|
|
|
|
// Only fallback to PHP file if JSON doesn't exist
|
|
|
|
|
$fullPhpFile = "$absDir/$name.php";
|
|
|
|
|
$isPhp = file_exists( $fullPhpFile );
|
|
|
|
|
}
|
|
|
|
|
if ( !$isJson && !$isPhp ) {
|
|
|
|
|
return Status::newFatal( 'config-extension-not-found', $name );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Extension exists. Now see if there are screenshots
|
|
|
|
|
$info = [];
|
|
|
|
|
if ( is_dir( "$absDir/screenshots" ) ) {
|
|
|
|
|
$paths = glob( "$absDir/screenshots/*.png" );
|
|
|
|
|
foreach ( $paths as $path ) {
|
|
|
|
|
$info['screenshots'][] = str_replace( $absDir, $relDir, $path );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $isJson ) {
|
|
|
|
|
$jsonStatus = $this->readExtension( $fullJsonFile );
|
|
|
|
|
if ( !$jsonStatus->isOK() ) {
|
|
|
|
|
return $jsonStatus;
|
|
|
|
|
}
|
|
|
|
|
$info += $jsonStatus->value;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-28 08:40:44 +00:00
|
|
|
// @phan-suppress-next-line SecurityCheckMulti
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
return Status::newGood( $info );
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-08 23:26:01 +00:00
|
|
|
/**
|
|
|
|
|
* @param string $fullJsonFile
|
|
|
|
|
* @param array $extDeps
|
|
|
|
|
* @param array $skinDeps
|
|
|
|
|
*
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
* @return Status On success, an array of extension information is in $status->value. On
|
|
|
|
|
* failure, the Status object will have an error list.
|
2018-04-08 23:26:01 +00:00
|
|
|
*/
|
|
|
|
|
private function readExtension( $fullJsonFile, $extDeps = [], $skinDeps = [] ) {
|
|
|
|
|
$load = [
|
|
|
|
|
$fullJsonFile => 1
|
|
|
|
|
];
|
|
|
|
|
if ( $extDeps ) {
|
|
|
|
|
$extDir = $this->getVar( 'IP' ) . '/extensions';
|
|
|
|
|
foreach ( $extDeps as $dep ) {
|
|
|
|
|
$fname = "$extDir/$dep/extension.json";
|
|
|
|
|
if ( !file_exists( $fname ) ) {
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
return Status::newFatal( 'config-extension-not-found', $dep );
|
2018-04-08 23:26:01 +00:00
|
|
|
}
|
|
|
|
|
$load[$fname] = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( $skinDeps ) {
|
|
|
|
|
$skinDir = $this->getVar( 'IP' ) . '/skins';
|
|
|
|
|
foreach ( $skinDeps as $dep ) {
|
|
|
|
|
$fname = "$skinDir/$dep/skin.json";
|
|
|
|
|
if ( !file_exists( $fname ) ) {
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
return Status::newFatal( 'config-extension-not-found', $dep );
|
2018-04-08 23:26:01 +00:00
|
|
|
}
|
|
|
|
|
$load[$fname] = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$registry = new ExtensionRegistry();
|
|
|
|
|
try {
|
|
|
|
|
$info = $registry->readFromQueue( $load );
|
|
|
|
|
} catch ( ExtensionDependencyError $e ) {
|
|
|
|
|
if ( $e->incompatibleCore || $e->incompatibleSkins
|
|
|
|
|
|| $e->incompatibleExtensions
|
|
|
|
|
) {
|
|
|
|
|
// If something is incompatible with a dependency, we have no real
|
|
|
|
|
// option besides skipping it
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
return Status::newFatal( 'config-extension-dependency',
|
|
|
|
|
basename( dirname( $fullJsonFile ) ), $e->getMessage() );
|
2018-04-08 23:26:01 +00:00
|
|
|
} elseif ( $e->missingExtensions || $e->missingSkins ) {
|
|
|
|
|
// There's an extension missing in the dependency tree,
|
|
|
|
|
// so add those to the dependency list and try again
|
2019-09-05 14:34:36 +00:00
|
|
|
$status = $this->readExtension(
|
2018-04-08 23:26:01 +00:00
|
|
|
$fullJsonFile,
|
|
|
|
|
array_merge( $extDeps, $e->missingExtensions ),
|
|
|
|
|
array_merge( $skinDeps, $e->missingSkins )
|
|
|
|
|
);
|
2019-09-05 14:34:36 +00:00
|
|
|
if ( !$status->isOK() && !$status->hasMessage( 'config-extension-dependency' ) ) {
|
|
|
|
|
$status = Status::newFatal( 'config-extension-dependency',
|
|
|
|
|
basename( dirname( $fullJsonFile ) ), $status->getMessage() );
|
|
|
|
|
}
|
|
|
|
|
return $status;
|
2018-04-08 23:26:01 +00:00
|
|
|
}
|
|
|
|
|
// Some other kind of dependency error?
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
return Status::newFatal( 'config-extension-dependency',
|
|
|
|
|
basename( dirname( $fullJsonFile ) ), $e->getMessage() );
|
2018-04-08 23:26:01 +00:00
|
|
|
}
|
|
|
|
|
$ret = [];
|
|
|
|
|
// The order of credits will be the order of $load,
|
|
|
|
|
// so the first extension is the one we want to load,
|
|
|
|
|
// everything else is a dependency
|
|
|
|
|
$i = 0;
|
|
|
|
|
foreach ( $info['credits'] as $name => $credit ) {
|
|
|
|
|
$i++;
|
|
|
|
|
if ( $i == 1 ) {
|
|
|
|
|
// Extension we want to load
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$type = basename( $credit['path'] ) === 'skin.json' ? 'skins' : 'extensions';
|
|
|
|
|
$ret['requires'][$type][] = $credit['name'];
|
|
|
|
|
}
|
|
|
|
|
$credits = array_values( $info['credits'] )[0];
|
|
|
|
|
if ( isset( $credits['url'] ) ) {
|
|
|
|
|
$ret['url'] = $credits['url'];
|
|
|
|
|
}
|
|
|
|
|
$ret['type'] = $credits['type'];
|
|
|
|
|
|
install.php: Allow extensions and skins to be specified
Allow the extensions and skins installed by maintenance/install.php to
be customised using --skins= and --extensions=. If the argument is
am empty string then no extensions/skins are installed. For backwards
compatibility, the default is to install all skins, but to install all
extensions only if --with-extensions is given.
The new CLI options may be specified multiple times, but for
convenience, comma-separated lists can also be used.
Also:
* Rename $option to $options
* If an extension has a dependency error, propagate the very readable
error message generated by ExtensionRegistry back to the user.
* Split getExtensionInfo() from the loop body of findExtensionsByType(),
so that CliInstaller can use it to validate its parameters and get
error messages.
* I didn't like the idea of removing the "s" from the directory name in
order to construct the JSON file name, so I split
findExtensionsByType() from findExtensions(), with the former not
having this hack. In findExtensions(), make the previous assumption
that the directory name is always "extensions" or "skins" explicit,
throwing an exception if it is otherwise.
Change-Id: Id0fb63cd4e61a047ef3396ee1c38d6073dfc7fd1
2018-09-19 05:43:14 +00:00
|
|
|
return Status::newGood( $ret );
|
2018-04-08 23:26:01 +00:00
|
|
|
}
|
|
|
|
|
|
2014-09-13 18:34:52 +00:00
|
|
|
/**
|
2015-01-10 02:55:38 +00:00
|
|
|
* Returns a default value to be used for $wgDefaultSkin: normally the one set in DefaultSettings,
|
|
|
|
|
* but will fall back to another if the default skin is missing and some other one is present
|
|
|
|
|
* instead.
|
2014-09-13 18:34:52 +00:00
|
|
|
*
|
|
|
|
|
* @param string[] $skinNames Names of installed skins.
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public function getDefaultSkin( array $skinNames ) {
|
|
|
|
|
$defaultSkin = $GLOBALS['wgDefaultSkin'];
|
2015-01-10 02:55:38 +00:00
|
|
|
if ( !$skinNames || in_array( $defaultSkin, $skinNames ) ) {
|
2014-09-13 18:34:52 +00:00
|
|
|
return $defaultSkin;
|
|
|
|
|
} else {
|
|
|
|
|
return $skinNames[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-21 15:27:16 +00:00
|
|
|
/**
|
|
|
|
|
* Installs the auto-detected extensions.
|
|
|
|
|
*
|
|
|
|
|
* @return Status
|
|
|
|
|
*/
|
|
|
|
|
protected function includeExtensions() {
|
2018-04-11 03:10:22 +00:00
|
|
|
// Marker for DatabaseUpdater::loadExtensions so we don't
|
|
|
|
|
// double load extensions
|
|
|
|
|
define( 'MW_EXTENSIONS_LOADED', true );
|
|
|
|
|
|
2020-11-03 06:00:34 +00:00
|
|
|
$legacySchemaHooks = $this->getAutoExtensionLegacyHooks();
|
|
|
|
|
$data = $this->getAutoExtensionData();
|
|
|
|
|
if ( isset( $data['globals']['wgHooks']['LoadExtensionSchemaUpdates'] ) ) {
|
|
|
|
|
$legacySchemaHooks = array_merge( $legacySchemaHooks,
|
|
|
|
|
$data['globals']['wgHooks']['LoadExtensionSchemaUpdates'] );
|
|
|
|
|
}
|
|
|
|
|
$extDeprecatedHooks = $data['attributes']['DeprecatedHooks'] ?? [];
|
|
|
|
|
|
|
|
|
|
$this->autoExtensionHookContainer = new HookContainer(
|
|
|
|
|
new StaticHookRegistry(
|
|
|
|
|
[ 'LoadExtensionSchemaUpdates' => $legacySchemaHooks ],
|
|
|
|
|
$data['attributes']['Hooks'] ?? [],
|
|
|
|
|
$extDeprecatedHooks
|
|
|
|
|
),
|
|
|
|
|
MediaWikiServices::getInstance()->getObjectFactory()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return Status::newGood();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Auto-detect extensions with an old style .php registration file, load
|
|
|
|
|
* the extensions, and return the merged $wgHooks array.
|
|
|
|
|
*
|
2020-11-29 11:37:44 +00:00
|
|
|
* @suppress SecurityCheck-PathTraversal It thinks $exts/$IP is user controlled but they are not.
|
2020-11-03 06:00:34 +00:00
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
protected function getAutoExtensionLegacyHooks() {
|
|
|
|
|
$exts = $this->getVar( '_Extensions' );
|
|
|
|
|
$installPath = $this->getVar( 'IP' );
|
|
|
|
|
$files = [];
|
|
|
|
|
foreach ( $exts as $e ) {
|
|
|
|
|
if ( file_exists( "$installPath/extensions/$e/$e.php" ) ) {
|
|
|
|
|
$files[] = "$installPath/extensions/$e/$e.php";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $files ) {
|
|
|
|
|
return $this->includeExtensionFiles( $files );
|
|
|
|
|
} else {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Include the specified extension PHP files. Populate $wgAutoloadClasses
|
|
|
|
|
* and return the LoadExtensionSchemaUpdates hooks.
|
|
|
|
|
*
|
|
|
|
|
* @param string[] $files
|
|
|
|
|
* @return array LoadExtensionSchemaUpdates legacy hooks
|
|
|
|
|
*/
|
|
|
|
|
protected function includeExtensionFiles( $files ) {
|
|
|
|
|
global $IP;
|
|
|
|
|
$IP = $this->getVar( 'IP' );
|
|
|
|
|
|
2011-01-31 20:00:59 +00:00
|
|
|
/**
|
|
|
|
|
* We need to include DefaultSettings before including extensions to avoid
|
|
|
|
|
* warnings about unset variables. However, the only thing we really
|
|
|
|
|
* want here is $wgHooks['LoadExtensionSchemaUpdates']. This won't work
|
|
|
|
|
* if the extension has hidden hook registration in $wgExtensionFunctions,
|
|
|
|
|
* but we're not opening that can of worms
|
2015-09-12 13:54:13 +00:00
|
|
|
* @see https://phabricator.wikimedia.org/T28857
|
2011-01-31 20:00:59 +00:00
|
|
|
*/
|
2021-08-28 08:40:44 +00:00
|
|
|
// @phan-suppress-next-line SecurityCheck-PathTraversal
|
2020-11-03 06:00:34 +00:00
|
|
|
require "$IP/includes/DefaultSettings.php";
|
|
|
|
|
|
|
|
|
|
// phpcs:ignore MediaWiki.VariableAnalysis.UnusedGlobalVariables
|
2011-03-25 18:24:58 +00:00
|
|
|
global $wgAutoloadClasses;
|
2020-11-03 06:00:34 +00:00
|
|
|
foreach ( $files as $file ) {
|
|
|
|
|
require_once $file;
|
|
|
|
|
}
|
2011-05-20 18:20:16 +00:00
|
|
|
|
2020-11-03 06:00:34 +00:00
|
|
|
// @phpcs:disable MediaWiki.VariableAnalysis.MisleadingGlobalNames.Misleading$wgHooks
|
|
|
|
|
// @phan-suppress-next-line PhanUndeclaredVariable,PhanCoalescingAlwaysNull $wgHooks is set by DefaultSettings
|
|
|
|
|
$hooksWeWant = $wgHooks['LoadExtensionSchemaUpdates'] ?? [];
|
|
|
|
|
// @phpcs:enable MediaWiki.VariableAnalysis.MisleadingGlobalNames.Misleading$wgHooks
|
|
|
|
|
|
|
|
|
|
// Ignore everyone else's hooks. Lord knows what someone might be doing
|
|
|
|
|
// in ParserFirstCallInit (see T29171)
|
|
|
|
|
return [ 'LoadExtensionSchemaUpdates' => $hooksWeWant ];
|
|
|
|
|
}
|
2011-01-21 15:27:16 +00:00
|
|
|
|
2020-11-03 06:00:34 +00:00
|
|
|
/**
|
|
|
|
|
* Auto-detect extensions with an extension.json file. Load the extensions,
|
|
|
|
|
* populate $wgAutoloadClasses and return the merged registry data.
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
protected function getAutoExtensionData() {
|
|
|
|
|
$exts = $this->getVar( '_Extensions' );
|
|
|
|
|
$installPath = $this->getVar( 'IP' );
|
|
|
|
|
$queue = [];
|
2013-04-20 21:11:46 +00:00
|
|
|
foreach ( $exts as $e ) {
|
2020-11-03 06:00:34 +00:00
|
|
|
if ( file_exists( "$installPath/extensions/$e/extension.json" ) ) {
|
|
|
|
|
$queue["$installPath/extensions/$e/extension.json"] = 1;
|
2015-04-02 05:51:38 +00:00
|
|
|
}
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
2015-04-02 05:51:38 +00:00
|
|
|
$registry = new ExtensionRegistry();
|
|
|
|
|
$data = $registry->readFromQueue( $queue );
|
2020-11-03 06:00:34 +00:00
|
|
|
global $wgAutoloadClasses;
|
2019-12-19 04:27:55 +00:00
|
|
|
$wgAutoloadClasses += $data['globals']['wgAutoloadClasses'];
|
2020-11-03 06:00:34 +00:00
|
|
|
return $data;
|
|
|
|
|
}
|
2015-04-02 05:51:38 +00:00
|
|
|
|
2020-11-03 06:00:34 +00:00
|
|
|
/**
|
|
|
|
|
* Get the hook container previously populated by includeExtensions().
|
|
|
|
|
*
|
|
|
|
|
* @internal For use by DatabaseInstaller
|
|
|
|
|
* @since 1.36
|
|
|
|
|
* @return HookContainer
|
|
|
|
|
*/
|
|
|
|
|
public function getAutoExtensionHookContainer() {
|
|
|
|
|
if ( !$this->autoExtensionHookContainer ) {
|
|
|
|
|
throw new \Exception( __METHOD__ .
|
|
|
|
|
': includeExtensions() has not been called' );
|
2015-04-02 05:51:38 +00:00
|
|
|
}
|
2020-11-03 06:00:34 +00:00
|
|
|
return $this->autoExtensionHookContainer;
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get an array of install steps. Should always be in the format of
|
2016-08-26 11:36:58 +00:00
|
|
|
* [
|
2011-01-21 15:27:16 +00:00
|
|
|
* 'name' => 'someuniquename',
|
2016-08-26 11:36:58 +00:00
|
|
|
* 'callback' => [ $obj, 'method' ],
|
|
|
|
|
* ]
|
2011-01-21 15:27:16 +00:00
|
|
|
* There must be a config-install-$name message defined per step, which will
|
|
|
|
|
* be shown on install.
|
|
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param DatabaseInstaller $installer DatabaseInstaller so we can make callbacks
|
2019-10-11 14:06:45 +00:00
|
|
|
* @return array[]
|
|
|
|
|
* @phan-return array<int,array{name:string,callback:array{0:object,1:string}}>
|
2011-01-21 15:27:16 +00:00
|
|
|
*/
|
* Fixed a bug causing the installer to ignore the "engine" and "charset" settings when installing a MySQL database.
* Fixed a bug causing the engine and charset settings to not be properly preserved when adding new tables on upgrade.
* Fixed total breakage of SQLite upgrade, by reusing the administrative connection to the SQLite database instead of creating a new one when wfGetDB() is called. Added LBFactory_Single to support this.
* Introduced a "schema variable" concept to DatabaseBase to avoid the use of globals for communication between the installer and the Database. Removed a lot of old global variable names from Database::replaceVars(), most were only added on a whim and were never used.
* Introduced DatabaseInstaller::getSchemaVars(), to allow schema variables to be supplied by the DatabaseInstaller child classes.
* Removed messages config-mysql-egine-mismatch [sic] and config-mysql-charset-mismatch. In the old installer it was possible for users to request a certain character set for an upgrade, but in the new installer the question is never asked. So these warnings were shown whenever a non-default character set or engine was used in the old database.
* In MysqlInstaller::preUpgrade(), fixed the incorrect strings used to identify the MySQL character sets: mysql5 instead of utf8 and mysql5-binary instead of binary.
* On install, initialise the site_stats table, using code copied from the old installer. Unlike the old installer, use SiteStats to increment the user count when the initial user is added.
* Fixed several instances of inappropriate call-by-reference.
* Replaced call_user_func_array() with call_user_func() where possible, it is shorter and simpler.
* Moved the caching boilerplate for DatabaseInstaller::getConnection() to the base class, and have the derived classes override an uncached function openConnection() instead. Updates r80892.
* In MysqlInstaller::getLocalSettings(), escape PHP strings correctly with LocalSettingsGenerator::escapePhpString().
* Reduce timeout for checks in dirIsExecutable() to 3 seconds, so that it doesn't take 30s to run when apache is in single-threaded mode for debugging.
* MySQL and SQLite have been tested and they appear to work. PostgreSQL upgrade is totally broken, apparently it was like that before I started. The Oracle code is untested.
2011-01-25 07:37:48 +00:00
|
|
|
protected function getInstallSteps( DatabaseInstaller $installer ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$coreInstallSteps = [
|
|
|
|
|
[ 'name' => 'database', 'callback' => [ $installer, 'setupDatabase' ] ],
|
|
|
|
|
[ 'name' => 'tables', 'callback' => [ $installer, 'createTables' ] ],
|
2020-05-09 14:27:42 +00:00
|
|
|
[ 'name' => 'tables-manual', 'callback' => [ $installer, 'createManualTables' ] ],
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'name' => 'interwiki', 'callback' => [ $installer, 'populateInterwikiTable' ] ],
|
|
|
|
|
[ 'name' => 'stats', 'callback' => [ $this, 'populateSiteStats' ] ],
|
|
|
|
|
[ 'name' => 'keys', 'callback' => [ $this, 'generateKeys' ] ],
|
|
|
|
|
[ 'name' => 'updates', 'callback' => [ $installer, 'insertUpdateKeys' ] ],
|
2020-01-17 06:21:28 +00:00
|
|
|
[ 'name' => 'restore-services', 'callback' => [ $this, 'restoreServices' ] ],
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'name' => 'sysop', 'callback' => [ $this, 'createSysop' ] ],
|
|
|
|
|
[ 'name' => 'mainpage', 'callback' => [ $this, 'createMainpage' ] ],
|
|
|
|
|
];
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
// Build the array of install steps starting from the core install list,
|
|
|
|
|
// then adding any callbacks that wanted to attach after a given step
|
2013-04-20 21:11:46 +00:00
|
|
|
foreach ( $coreInstallSteps as $step ) {
|
2011-01-21 15:27:16 +00:00
|
|
|
$this->installSteps[] = $step;
|
2013-04-20 21:11:46 +00:00
|
|
|
if ( isset( $this->extraInstallSteps[$step['name']] ) ) {
|
2011-01-21 15:27:16 +00:00
|
|
|
$this->installSteps = array_merge(
|
|
|
|
|
$this->installSteps,
|
2013-03-24 10:01:51 +00:00
|
|
|
$this->extraInstallSteps[$step['name']]
|
2011-01-21 15:27:16 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Prepend any steps that want to be at the beginning
|
2013-04-20 21:11:46 +00:00
|
|
|
if ( isset( $this->extraInstallSteps['BEGINNING'] ) ) {
|
2011-01-21 15:27:16 +00:00
|
|
|
$this->installSteps = array_merge(
|
|
|
|
|
$this->extraInstallSteps['BEGINNING'],
|
|
|
|
|
$this->installSteps
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Extensions should always go first, chance to tie into hooks and such
|
2013-04-20 21:11:46 +00:00
|
|
|
if ( count( $this->getVar( '_Extensions' ) ) ) {
|
2011-01-21 15:27:16 +00:00
|
|
|
array_unshift( $this->installSteps,
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'name' => 'extensions', 'callback' => [ $this, 'includeExtensions' ] ]
|
2011-01-21 15:27:16 +00:00
|
|
|
);
|
2016-02-17 09:09:32 +00:00
|
|
|
$this->installSteps[] = [
|
2011-01-31 20:00:59 +00:00
|
|
|
'name' => 'extension-tables',
|
2016-02-17 09:09:32 +00:00
|
|
|
'callback' => [ $installer, 'createExtensionTables' ]
|
|
|
|
|
];
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2011-01-21 15:27:16 +00:00
|
|
|
return $this->installSteps;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Actually perform the installation.
|
|
|
|
|
*
|
2014-07-03 19:20:35 +00:00
|
|
|
* @param callable $startCB A callback array for the beginning of each step
|
|
|
|
|
* @param callable $endCB A callback array for the end of each step
|
2011-01-21 15:27:16 +00:00
|
|
|
*
|
2021-06-17 14:32:05 +00:00
|
|
|
* @return Status[]
|
2011-01-21 15:27:16 +00:00
|
|
|
*/
|
|
|
|
|
public function performInstallation( $startCB, $endCB ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$installResults = [];
|
2011-01-21 15:27:16 +00:00
|
|
|
$installer = $this->getDBInstaller();
|
|
|
|
|
$installer->preInstall();
|
|
|
|
|
$steps = $this->getInstallSteps( $installer );
|
2013-04-20 21:11:46 +00:00
|
|
|
foreach ( $steps as $stepObj ) {
|
2011-01-21 15:27:16 +00:00
|
|
|
$name = $stepObj['name'];
|
2016-02-17 09:09:32 +00:00
|
|
|
call_user_func_array( $startCB, [ $name ] );
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
// Perform the callback step
|
* Fixed a bug causing the installer to ignore the "engine" and "charset" settings when installing a MySQL database.
* Fixed a bug causing the engine and charset settings to not be properly preserved when adding new tables on upgrade.
* Fixed total breakage of SQLite upgrade, by reusing the administrative connection to the SQLite database instead of creating a new one when wfGetDB() is called. Added LBFactory_Single to support this.
* Introduced a "schema variable" concept to DatabaseBase to avoid the use of globals for communication between the installer and the Database. Removed a lot of old global variable names from Database::replaceVars(), most were only added on a whim and were never used.
* Introduced DatabaseInstaller::getSchemaVars(), to allow schema variables to be supplied by the DatabaseInstaller child classes.
* Removed messages config-mysql-egine-mismatch [sic] and config-mysql-charset-mismatch. In the old installer it was possible for users to request a certain character set for an upgrade, but in the new installer the question is never asked. So these warnings were shown whenever a non-default character set or engine was used in the old database.
* In MysqlInstaller::preUpgrade(), fixed the incorrect strings used to identify the MySQL character sets: mysql5 instead of utf8 and mysql5-binary instead of binary.
* On install, initialise the site_stats table, using code copied from the old installer. Unlike the old installer, use SiteStats to increment the user count when the initial user is added.
* Fixed several instances of inappropriate call-by-reference.
* Replaced call_user_func_array() with call_user_func() where possible, it is shorter and simpler.
* Moved the caching boilerplate for DatabaseInstaller::getConnection() to the base class, and have the derived classes override an uncached function openConnection() instead. Updates r80892.
* In MysqlInstaller::getLocalSettings(), escape PHP strings correctly with LocalSettingsGenerator::escapePhpString().
* Reduce timeout for checks in dirIsExecutable() to 3 seconds, so that it doesn't take 30s to run when apache is in single-threaded mode for debugging.
* MySQL and SQLite have been tested and they appear to work. PostgreSQL upgrade is totally broken, apparently it was like that before I started. The Oracle code is untested.
2011-01-25 07:37:48 +00:00
|
|
|
$status = call_user_func( $stepObj['callback'], $installer );
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
// Output and save the results
|
* Fixed a bug causing the installer to ignore the "engine" and "charset" settings when installing a MySQL database.
* Fixed a bug causing the engine and charset settings to not be properly preserved when adding new tables on upgrade.
* Fixed total breakage of SQLite upgrade, by reusing the administrative connection to the SQLite database instead of creating a new one when wfGetDB() is called. Added LBFactory_Single to support this.
* Introduced a "schema variable" concept to DatabaseBase to avoid the use of globals for communication between the installer and the Database. Removed a lot of old global variable names from Database::replaceVars(), most were only added on a whim and were never used.
* Introduced DatabaseInstaller::getSchemaVars(), to allow schema variables to be supplied by the DatabaseInstaller child classes.
* Removed messages config-mysql-egine-mismatch [sic] and config-mysql-charset-mismatch. In the old installer it was possible for users to request a certain character set for an upgrade, but in the new installer the question is never asked. So these warnings were shown whenever a non-default character set or engine was used in the old database.
* In MysqlInstaller::preUpgrade(), fixed the incorrect strings used to identify the MySQL character sets: mysql5 instead of utf8 and mysql5-binary instead of binary.
* On install, initialise the site_stats table, using code copied from the old installer. Unlike the old installer, use SiteStats to increment the user count when the initial user is added.
* Fixed several instances of inappropriate call-by-reference.
* Replaced call_user_func_array() with call_user_func() where possible, it is shorter and simpler.
* Moved the caching boilerplate for DatabaseInstaller::getConnection() to the base class, and have the derived classes override an uncached function openConnection() instead. Updates r80892.
* In MysqlInstaller::getLocalSettings(), escape PHP strings correctly with LocalSettingsGenerator::escapePhpString().
* Reduce timeout for checks in dirIsExecutable() to 3 seconds, so that it doesn't take 30s to run when apache is in single-threaded mode for debugging.
* MySQL and SQLite have been tested and they appear to work. PostgreSQL upgrade is totally broken, apparently it was like that before I started. The Oracle code is untested.
2011-01-25 07:37:48 +00:00
|
|
|
call_user_func( $endCB, $name, $status );
|
2011-01-21 15:27:16 +00:00
|
|
|
$installResults[$name] = $status;
|
|
|
|
|
|
|
|
|
|
// If we've hit some sort of fatal, we need to bail.
|
|
|
|
|
// Callback already had a chance to do output above.
|
2019-08-31 20:59:45 +00:00
|
|
|
if ( !$status->isOK() ) {
|
2011-01-21 15:27:16 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-31 20:59:45 +00:00
|
|
|
if ( $status->isOK() ) {
|
2017-11-29 20:42:39 +00:00
|
|
|
$this->showMessage(
|
2018-07-07 15:32:12 +00:00
|
|
|
'config-install-db-success'
|
2017-11-29 20:42:39 +00:00
|
|
|
);
|
2011-01-21 15:27:16 +00:00
|
|
|
$this->setVar( '_InstallDone', true );
|
|
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2011-01-21 15:27:16 +00:00
|
|
|
return $installResults;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-03-20 05:17:40 +00:00
|
|
|
* Generate $wgSecretKey. Will warn if we had to use an insecure random source.
|
2011-01-21 15:27:16 +00:00
|
|
|
*
|
|
|
|
|
* @return Status
|
|
|
|
|
*/
|
2011-03-29 19:00:23 +00:00
|
|
|
public function generateKeys() {
|
2016-02-17 09:09:32 +00:00
|
|
|
$keys = [ 'wgSecretKey' => 64 ];
|
2011-03-29 19:00:23 +00:00
|
|
|
if ( strval( $this->getVar( 'wgUpgradeKey' ) ) === '' ) {
|
|
|
|
|
$keys['wgUpgradeKey'] = 16;
|
|
|
|
|
}
|
2013-10-08 11:43:42 +00:00
|
|
|
|
2011-03-29 19:00:23 +00:00
|
|
|
return $this->doGenerateKeys( $keys );
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
2020-01-17 06:21:28 +00:00
|
|
|
/**
|
|
|
|
|
* Restore services that have been redefined in the early stage of installation
|
|
|
|
|
* @return Status
|
|
|
|
|
*/
|
|
|
|
|
public function restoreServices() {
|
2020-09-17 19:12:33 +00:00
|
|
|
$this->resetMediaWikiServices( null, [
|
2021-02-10 22:31:02 +00:00
|
|
|
'UserOptionsLookup' => static function ( MediaWikiServices $services ) {
|
2020-01-17 06:21:28 +00:00
|
|
|
return $services->get( 'UserOptionsManager' );
|
|
|
|
|
}
|
2020-09-17 19:12:33 +00:00
|
|
|
] );
|
2020-01-17 06:21:28 +00:00
|
|
|
return Status::newGood();
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-21 15:27:16 +00:00
|
|
|
/**
|
2019-03-09 03:12:49 +00:00
|
|
|
* Generate a secret value for variables using a secure generator.
|
2011-01-21 15:27:16 +00:00
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param array $keys
|
2011-01-21 15:27:16 +00:00
|
|
|
* @return Status
|
|
|
|
|
*/
|
2011-03-29 19:00:23 +00:00
|
|
|
protected function doGenerateKeys( $keys ) {
|
|
|
|
|
foreach ( $keys as $name => $length ) {
|
2018-01-19 22:42:56 +00:00
|
|
|
$secretKey = MWCryptRand::generateHex( $length );
|
2011-03-29 19:00:23 +00:00
|
|
|
$this->setVar( $name, $secretKey );
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
2020-10-28 03:31:03 +00:00
|
|
|
return Status::newGood();
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2018-03-20 22:44:27 +00:00
|
|
|
* Create the first user account, grant it sysop, bureaucrat and interface-admin rights
|
2011-01-21 15:27:16 +00:00
|
|
|
*
|
|
|
|
|
* @return Status
|
|
|
|
|
*/
|
|
|
|
|
protected function createSysop() {
|
|
|
|
|
$name = $this->getVar( '_AdminName' );
|
|
|
|
|
$user = User::newFromName( $name );
|
|
|
|
|
|
|
|
|
|
if ( !$user ) {
|
|
|
|
|
// We should've validated this earlier anyway!
|
|
|
|
|
return Status::newFatal( 'config-admin-error-user', $name );
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-08 20:04:45 +00:00
|
|
|
if ( $user->idForName() == 0 ) {
|
|
|
|
|
$user->addToDatabase();
|
2011-01-21 15:27:16 +00:00
|
|
|
|
2020-04-02 01:05:17 +00:00
|
|
|
$password = $this->getVar( '_AdminPassword' );
|
|
|
|
|
$status = $user->changeAuthenticationData( [
|
|
|
|
|
'username' => $user->getName(),
|
|
|
|
|
'password' => $password,
|
|
|
|
|
'retype' => $password,
|
|
|
|
|
] );
|
|
|
|
|
if ( !$status->isGood() ) {
|
|
|
|
|
return Status::newFatal( 'config-admin-error-password',
|
2021-10-16 20:35:01 +00:00
|
|
|
$name, $status->getWikiText( false, false, $this->getVar( '_UserLang' ) ) );
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
2021-07-01 10:32:24 +00:00
|
|
|
$userGroupManager = MediaWikiServices::getInstance()->getUserGroupManager();
|
|
|
|
|
$userGroupManager->addUserToGroup( $user, 'sysop' );
|
|
|
|
|
$userGroupManager->addUserToGroup( $user, 'bureaucrat' );
|
|
|
|
|
$userGroupManager->addUserToGroup( $user, 'interface-admin' );
|
2013-04-20 21:11:46 +00:00
|
|
|
if ( $this->getVar( '_AdminEmail' ) ) {
|
2011-01-21 15:27:16 +00:00
|
|
|
$user->setEmail( $this->getVar( '_AdminEmail' ) );
|
|
|
|
|
}
|
2011-06-08 20:04:45 +00:00
|
|
|
$user->saveSettings();
|
* Fixed a bug causing the installer to ignore the "engine" and "charset" settings when installing a MySQL database.
* Fixed a bug causing the engine and charset settings to not be properly preserved when adding new tables on upgrade.
* Fixed total breakage of SQLite upgrade, by reusing the administrative connection to the SQLite database instead of creating a new one when wfGetDB() is called. Added LBFactory_Single to support this.
* Introduced a "schema variable" concept to DatabaseBase to avoid the use of globals for communication between the installer and the Database. Removed a lot of old global variable names from Database::replaceVars(), most were only added on a whim and were never used.
* Introduced DatabaseInstaller::getSchemaVars(), to allow schema variables to be supplied by the DatabaseInstaller child classes.
* Removed messages config-mysql-egine-mismatch [sic] and config-mysql-charset-mismatch. In the old installer it was possible for users to request a certain character set for an upgrade, but in the new installer the question is never asked. So these warnings were shown whenever a non-default character set or engine was used in the old database.
* In MysqlInstaller::preUpgrade(), fixed the incorrect strings used to identify the MySQL character sets: mysql5 instead of utf8 and mysql5-binary instead of binary.
* On install, initialise the site_stats table, using code copied from the old installer. Unlike the old installer, use SiteStats to increment the user count when the initial user is added.
* Fixed several instances of inappropriate call-by-reference.
* Replaced call_user_func_array() with call_user_func() where possible, it is shorter and simpler.
* Moved the caching boilerplate for DatabaseInstaller::getConnection() to the base class, and have the derived classes override an uncached function openConnection() instead. Updates r80892.
* In MysqlInstaller::getLocalSettings(), escape PHP strings correctly with LocalSettingsGenerator::escapePhpString().
* Reduce timeout for checks in dirIsExecutable() to 3 seconds, so that it doesn't take 30s to run when apache is in single-threaded mode for debugging.
* MySQL and SQLite have been tested and they appear to work. PostgreSQL upgrade is totally broken, apparently it was like that before I started. The Oracle code is untested.
2011-01-25 07:37:48 +00:00
|
|
|
|
|
|
|
|
// Update user count
|
2018-02-11 19:49:27 +00:00
|
|
|
$ssUpdate = SiteStatsUpdate::factory( [ 'users' => 1 ] );
|
* Fixed a bug causing the installer to ignore the "engine" and "charset" settings when installing a MySQL database.
* Fixed a bug causing the engine and charset settings to not be properly preserved when adding new tables on upgrade.
* Fixed total breakage of SQLite upgrade, by reusing the administrative connection to the SQLite database instead of creating a new one when wfGetDB() is called. Added LBFactory_Single to support this.
* Introduced a "schema variable" concept to DatabaseBase to avoid the use of globals for communication between the installer and the Database. Removed a lot of old global variable names from Database::replaceVars(), most were only added on a whim and were never used.
* Introduced DatabaseInstaller::getSchemaVars(), to allow schema variables to be supplied by the DatabaseInstaller child classes.
* Removed messages config-mysql-egine-mismatch [sic] and config-mysql-charset-mismatch. In the old installer it was possible for users to request a certain character set for an upgrade, but in the new installer the question is never asked. So these warnings were shown whenever a non-default character set or engine was used in the old database.
* In MysqlInstaller::preUpgrade(), fixed the incorrect strings used to identify the MySQL character sets: mysql5 instead of utf8 and mysql5-binary instead of binary.
* On install, initialise the site_stats table, using code copied from the old installer. Unlike the old installer, use SiteStats to increment the user count when the initial user is added.
* Fixed several instances of inappropriate call-by-reference.
* Replaced call_user_func_array() with call_user_func() where possible, it is shorter and simpler.
* Moved the caching boilerplate for DatabaseInstaller::getConnection() to the base class, and have the derived classes override an uncached function openConnection() instead. Updates r80892.
* In MysqlInstaller::getLocalSettings(), escape PHP strings correctly with LocalSettingsGenerator::escapePhpString().
* Reduce timeout for checks in dirIsExecutable() to 3 seconds, so that it doesn't take 30s to run when apache is in single-threaded mode for debugging.
* MySQL and SQLite have been tested and they appear to work. PostgreSQL upgrade is totally broken, apparently it was like that before I started. The Oracle code is untested.
2011-01-25 07:37:48 +00:00
|
|
|
$ssUpdate->doUpdate();
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-20 21:11:46 +00:00
|
|
|
if ( $this->getVar( '_Subscribe' ) && $this->getVar( '_AdminEmail' ) ) {
|
2020-10-28 03:31:03 +00:00
|
|
|
return $this->subscribeToMediaWikiAnnounce();
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
2020-10-28 03:31:03 +00:00
|
|
|
return Status::newGood();
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
2011-11-22 16:31:33 +00:00
|
|
|
/**
|
2020-10-28 03:31:03 +00:00
|
|
|
* @return Status
|
2011-11-22 16:31:33 +00:00
|
|
|
*/
|
2020-10-28 03:31:03 +00:00
|
|
|
private function subscribeToMediaWikiAnnounce() {
|
2021-08-29 10:53:15 +00:00
|
|
|
$status = Status::newGood();
|
|
|
|
|
$http = MediaWikiServices::getInstance()->getHttpRequestFactory();
|
|
|
|
|
if ( !$http->canMakeRequests() ) {
|
|
|
|
|
$status->warning( 'config-install-subscribe-fail',
|
|
|
|
|
wfMessage( 'config-install-subscribe-notpossible' ) );
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create subscription request
|
|
|
|
|
$params = [ 'email' => $this->getVar( '_AdminEmail' ) ];
|
|
|
|
|
$req = $http->create( self::MEDIAWIKI_ANNOUNCE_URL . 'anonymous_subscribe',
|
|
|
|
|
[ 'method' => 'POST', 'postData' => $params ], __METHOD__ );
|
|
|
|
|
|
|
|
|
|
// Add headers needed to pass Django's CSRF checks
|
|
|
|
|
$token = str_repeat( 'a', 64 );
|
|
|
|
|
$req->setHeader( 'Referer', self::MEDIAWIKI_ANNOUNCE_URL );
|
|
|
|
|
$req->setHeader( 'Cookie', "csrftoken=$token" );
|
|
|
|
|
$req->setHeader( 'X-CSRFToken', $token );
|
2011-01-21 15:27:16 +00:00
|
|
|
|
2021-08-29 10:53:15 +00:00
|
|
|
// Send subscription request
|
|
|
|
|
$reqStatus = $req->execute();
|
|
|
|
|
if ( !$reqStatus->isOK() ) {
|
|
|
|
|
$status->warning( 'config-install-subscribe-fail',
|
|
|
|
|
Status::wrap( $reqStatus )->getMessage() );
|
|
|
|
|
return $status;
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
2021-08-29 10:53:15 +00:00
|
|
|
// Was the request submitted successfully?
|
|
|
|
|
// The status message is displayed after a redirect, using Django's messages
|
|
|
|
|
// framework, so load the list summary page and look for the expected text.
|
|
|
|
|
// (Though parsing the cookie set by the framework may be possible, it isn't
|
|
|
|
|
// simple, since the format of the cookie has changed between versions.)
|
|
|
|
|
$checkReq = $http->create( self::MEDIAWIKI_ANNOUNCE_URL, [], __METHOD__ );
|
|
|
|
|
$checkReq->setCookieJar( $req->getCookieJar() );
|
|
|
|
|
if ( !$checkReq->execute()->isOK() ) {
|
|
|
|
|
$status->warning( 'config-install-subscribe-possiblefail' );
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
$html = $checkReq->getContent();
|
|
|
|
|
if ( strpos( $html, 'Please check your inbox for further instructions' ) !== false ) {
|
|
|
|
|
// Success
|
|
|
|
|
} elseif ( strpos( $html, 'Member already subscribed' ) !== false ) {
|
|
|
|
|
$status->warning( 'config-install-subscribe-alreadysubscribed' );
|
|
|
|
|
} elseif ( strpos( $html, 'Subscription request already pending' ) !== false ) {
|
|
|
|
|
$status->warning( 'config-install-subscribe-alreadypending' );
|
2011-07-18 21:56:10 +00:00
|
|
|
} else {
|
2021-08-29 10:53:15 +00:00
|
|
|
$status->warning( 'config-install-subscribe-possiblefail' );
|
2011-06-03 01:06:07 +00:00
|
|
|
}
|
2020-10-28 03:31:03 +00:00
|
|
|
return $status;
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Insert Main Page with default content.
|
|
|
|
|
*
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param DatabaseInstaller $installer
|
2011-01-21 15:27:16 +00:00
|
|
|
* @return Status
|
|
|
|
|
*/
|
* Fixed a bug causing the installer to ignore the "engine" and "charset" settings when installing a MySQL database.
* Fixed a bug causing the engine and charset settings to not be properly preserved when adding new tables on upgrade.
* Fixed total breakage of SQLite upgrade, by reusing the administrative connection to the SQLite database instead of creating a new one when wfGetDB() is called. Added LBFactory_Single to support this.
* Introduced a "schema variable" concept to DatabaseBase to avoid the use of globals for communication between the installer and the Database. Removed a lot of old global variable names from Database::replaceVars(), most were only added on a whim and were never used.
* Introduced DatabaseInstaller::getSchemaVars(), to allow schema variables to be supplied by the DatabaseInstaller child classes.
* Removed messages config-mysql-egine-mismatch [sic] and config-mysql-charset-mismatch. In the old installer it was possible for users to request a certain character set for an upgrade, but in the new installer the question is never asked. So these warnings were shown whenever a non-default character set or engine was used in the old database.
* In MysqlInstaller::preUpgrade(), fixed the incorrect strings used to identify the MySQL character sets: mysql5 instead of utf8 and mysql5-binary instead of binary.
* On install, initialise the site_stats table, using code copied from the old installer. Unlike the old installer, use SiteStats to increment the user count when the initial user is added.
* Fixed several instances of inappropriate call-by-reference.
* Replaced call_user_func_array() with call_user_func() where possible, it is shorter and simpler.
* Moved the caching boilerplate for DatabaseInstaller::getConnection() to the base class, and have the derived classes override an uncached function openConnection() instead. Updates r80892.
* In MysqlInstaller::getLocalSettings(), escape PHP strings correctly with LocalSettingsGenerator::escapePhpString().
* Reduce timeout for checks in dirIsExecutable() to 3 seconds, so that it doesn't take 30s to run when apache is in single-threaded mode for debugging.
* MySQL and SQLite have been tested and they appear to work. PostgreSQL upgrade is totally broken, apparently it was like that before I started. The Oracle code is untested.
2011-01-25 07:37:48 +00:00
|
|
|
protected function createMainpage( DatabaseInstaller $installer ) {
|
2011-01-21 15:27:16 +00:00
|
|
|
$status = Status::newGood();
|
2017-01-24 00:52:37 +00:00
|
|
|
$title = Title::newMainPage();
|
|
|
|
|
if ( $title->exists() ) {
|
|
|
|
|
$status->warning( 'config-install-mainpage-exists' );
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
2011-01-21 15:27:16 +00:00
|
|
|
try {
|
2020-11-11 21:45:19 +00:00
|
|
|
$page = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $title );
|
2013-03-24 10:01:51 +00:00
|
|
|
$content = new WikitextContent(
|
2012-08-29 08:07:10 +00:00
|
|
|
wfMessage( 'mainpagetext' )->inContentLanguage()->text() . "\n\n" .
|
|
|
|
|
wfMessage( 'mainpagedocfooter' )->inContentLanguage()->text()
|
2012-08-28 14:02:13 +00:00
|
|
|
);
|
|
|
|
|
|
2021-06-24 08:42:19 +00:00
|
|
|
$status = $page->doUserEditContent(
|
2020-10-28 03:31:03 +00:00
|
|
|
$content,
|
2021-06-24 08:42:19 +00:00
|
|
|
User::newSystemUser( 'MediaWiki default' ),
|
2013-10-08 11:43:42 +00:00
|
|
|
'',
|
2021-06-24 08:42:19 +00:00
|
|
|
EDIT_NEW
|
2013-10-08 11:43:42 +00:00
|
|
|
);
|
2015-01-09 23:44:47 +00:00
|
|
|
} catch ( Exception $e ) {
|
2015-09-11 13:44:59 +00:00
|
|
|
// using raw, because $wgShowExceptionDetails can not be set yet
|
2011-01-21 15:27:16 +00:00
|
|
|
$status->fatal( 'config-install-mainpage-failed', $e->getMessage() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Override the necessary bits of the config to run an installation.
|
|
|
|
|
*/
|
|
|
|
|
public static function overrideConfig() {
|
2016-02-18 20:56:40 +00:00
|
|
|
// Use PHP's built-in session handling, since MediaWiki's
|
|
|
|
|
// SessionHandler can't work before we have an object cache set up.
|
2019-05-28 19:29:59 +00:00
|
|
|
if ( !defined( 'MW_NO_SESSION_HANDLER' ) ) {
|
|
|
|
|
define( 'MW_NO_SESSION_HANDLER', 1 );
|
|
|
|
|
}
|
2011-01-21 15:27:16 +00:00
|
|
|
|
|
|
|
|
// Don't access the database
|
|
|
|
|
$GLOBALS['wgUseDatabaseMessages'] = false;
|
2012-05-07 07:51:38 +00:00
|
|
|
// Don't cache langconv tables
|
|
|
|
|
$GLOBALS['wgLanguageConverterCacheType'] = CACHE_NONE;
|
2020-03-16 17:36:46 +00:00
|
|
|
// Don't try to cache ResourceLoader dependencies in the database
|
|
|
|
|
$GLOBALS['wgResourceLoaderUseObjectCacheForDeps'] = true;
|
2011-01-21 15:27:16 +00:00
|
|
|
// Debug-friendly
|
|
|
|
|
$GLOBALS['wgShowExceptionDetails'] = true;
|
2018-07-17 16:51:36 +00:00
|
|
|
$GLOBALS['wgShowHostnames'] = true;
|
2011-01-21 15:27:16 +00:00
|
|
|
// Don't break forms
|
|
|
|
|
$GLOBALS['wgExternalLinkTarget'] = '_blank';
|
|
|
|
|
|
|
|
|
|
// Allow multiple ob_flush() calls
|
|
|
|
|
$GLOBALS['wgDisableOutputCompression'] = true;
|
|
|
|
|
|
|
|
|
|
// Use a sensible cookie prefix (not my_wiki)
|
|
|
|
|
$GLOBALS['wgCookiePrefix'] = 'mw_installer';
|
|
|
|
|
|
|
|
|
|
// Some of the environment checks make shell requests, remove limits
|
|
|
|
|
$GLOBALS['wgMaxShellMemory'] = 0;
|
2016-02-10 10:04:28 +00:00
|
|
|
|
2016-02-18 20:56:40 +00:00
|
|
|
// Override the default CookieSessionProvider with a dummy
|
|
|
|
|
// implementation that won't stomp on PHP's cookies.
|
2016-02-17 09:09:32 +00:00
|
|
|
$GLOBALS['wgSessionProviders'] = [
|
|
|
|
|
[
|
2018-01-13 00:02:09 +00:00
|
|
|
'class' => InstallerSessionProvider::class,
|
2016-02-17 09:09:32 +00:00
|
|
|
'args' => [ [
|
2016-02-10 10:04:28 +00:00
|
|
|
'priority' => 1,
|
2016-02-17 09:09:32 +00:00
|
|
|
] ]
|
|
|
|
|
]
|
|
|
|
|
];
|
2016-02-18 20:56:40 +00:00
|
|
|
|
2020-05-23 01:41:17 +00:00
|
|
|
// Don't use the DB as the main stash
|
|
|
|
|
$GLOBALS['wgMainStash'] = CACHE_NONE;
|
|
|
|
|
|
2016-02-18 20:56:40 +00:00
|
|
|
// Don't try to use any object cache for SessionManager either.
|
|
|
|
|
$GLOBALS['wgSessionCacheType'] = CACHE_NONE;
|
2019-07-19 04:04:41 +00:00
|
|
|
|
|
|
|
|
// Set a dummy $wgServer to bypass the check in Setup.php, the
|
|
|
|
|
// web installer will automatically detect it and not use this value.
|
|
|
|
|
$GLOBALS['wgServer'] = 'https://🌻.invalid';
|
2011-01-21 15:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add an installation step following the given step.
|
|
|
|
|
*
|
2019-06-12 18:41:13 +00:00
|
|
|
* @param array $callback A valid installation callback array, in this form:
|
2016-08-26 11:36:58 +00:00
|
|
|
* [ 'name' => 'some-unique-name', 'callback' => [ $obj, 'function' ] ];
|
2014-04-19 11:55:27 +00:00
|
|
|
* @param string $findStep The step to find. Omit to put the step at the beginning
|
2011-01-21 15:27:16 +00:00
|
|
|
*/
|
|
|
|
|
public function addInstallStep( $callback, $findStep = 'BEGINNING' ) {
|
|
|
|
|
$this->extraInstallSteps[$findStep][] = $callback;
|
|
|
|
|
}
|
2011-06-21 01:13:45 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Disable the time limit for execution.
|
|
|
|
|
* Some long-running pages (Install, Upgrade) will want to do this
|
|
|
|
|
*/
|
|
|
|
|
protected function disableTimeLimit() {
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\suppressWarnings();
|
2011-06-21 01:13:45 +00:00
|
|
|
set_time_limit( 0 );
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\restoreWarnings();
|
2011-06-21 01:13:45 +00:00
|
|
|
}
|
2010-07-25 18:04:41 +00:00
|
|
|
}
|