<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
namespace Friendica\Module;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core;
+use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
-use Friendica\Util\Strings;
+use Friendica\Core\Theme;
+use Friendica\DI;
+use Friendica\Network\HTTPException;
+use Friendica\Util\BasePath;
+use Friendica\Util\Profiler;
use Friendica\Util\Temporal;
+use Psr\Log\LoggerInterface;
+use GuzzleHttp\Psr7\Uri;
class Install extends BaseModule
{
*/
const SYSTEM_CHECK = 1;
/**
- * Step two - Database configuration
+ * Step two - Base information
*/
- const DATABASE_CONFIG = 2;
+ const BASE_CONFIG = 2;
/**
- * Step three - Adapat site settings
+ * Step three - Database configuration
*/
- const SITE_SETTINGS = 3;
+ const DATABASE_CONFIG = 3;
/**
- * Step four - All steps finished
+ * Step four - Adapt site settings
*/
- const FINISHED = 4;
+ const SITE_SETTINGS = 4;
+ /**
+ * Step five - All steps finished
+ */
+ const FINISHED = 5;
/**
* @var int The current step of the wizard
*/
- private static $currentWizardStep;
+ private $currentWizardStep;
/**
* @var Core\Installer The installer
*/
- private static $installer;
+ private $installer;
+
+ /** @var App */
+ protected $app;
+ /** @var App\Mode */
+ protected $mode;
- public static function init()
+ public function __construct(App $app, BasePath $basePath, App\Mode $mode, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, Core\Installer $installer, array $server, array $parameters = [])
{
- $a = self::getApp();
+ parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
+
+ $this->app = $app;
+ $this->mode = $mode;
+ $this->installer = $installer;
+
+ if (!$this->mode->isInstall()) {
+ throw new HTTPException\ForbiddenException();
+ }
// route: install/testrwrite
// $baseurl/install/testrwrite to test if rewrite in .htaccess is working
- if ($a->getArgumentValue(1, '') == 'testrewrite') {
+ if ($args->get(1, '') == 'testrewrite') {
// Status Code 204 means that it worked without content
- Core\System::httpExit(204);
+ throw new HTTPException\NoContentException();
}
+ // get basic installation information and save them to the config cache
+ $configCache = $this->app->getConfigCache();
+ $this->installer->setUpCache($configCache, $basePath->getPath());
+
// We overwrite current theme css, because during install we may not have a working mod_rewrite
// so we may not have a css at all. Here we set a static css file for the install procedure pages
- Renderer::$theme['stylesheet'] = $a->getBaseURL() . '/view/install/style.css';
+ Renderer::$theme['stylesheet'] = $this->baseUrl . '/view/install/style.css';
- self::$installer = new Core\Installer();
- self::$currentWizardStep = defaults($_POST, 'pass', self::SYSTEM_CHECK);
+ $this->currentWizardStep = ($_POST['pass'] ?? '') ?: self::SYSTEM_CHECK;
}
- public static function post()
+ protected function post(array $request = [])
{
- $a = self::getApp();
+ $configCache = $this->app->getConfigCache();
- switch (self::$currentWizardStep) {
+ switch ($this->currentWizardStep) {
case self::SYSTEM_CHECK:
+ case self::BASE_CONFIG:
+ $this->checkSetting($configCache, $_POST, 'config', 'php_path');
+ break;
+
case self::DATABASE_CONFIG:
- // Nothing to do in these steps
+ $this->checkSetting($configCache, $_POST, 'config', 'php_path');
+
+ $this->checkSetting($configCache, $_POST, 'system', 'basepath');
+ $this->checkSetting($configCache, $_POST, 'system', 'url');
break;
case self::SITE_SETTINGS:
- $dbhost = Strings::escapeTags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST)));
- $dbuser = Strings::escapeTags(trim(defaults($_POST, 'dbuser', '')));
- $dbpass = Strings::escapeTags(trim(defaults($_POST, 'dbpass', '')));
- $dbdata = Strings::escapeTags(trim(defaults($_POST, 'dbdata', '')));
+ $this->checkSetting($configCache, $_POST, 'config', 'php_path');
+
+ $this->checkSetting($configCache, $_POST, 'system', 'basepath');
+ $this->checkSetting($configCache, $_POST, 'system', 'url');
+
+ $this->checkSetting($configCache, $_POST, 'database', 'hostname', Core\Installer::DEFAULT_HOST);
+ $this->checkSetting($configCache, $_POST, 'database', 'username', '');
+ $this->checkSetting($configCache, $_POST, 'database', 'password', '');
+ $this->checkSetting($configCache, $_POST, 'database', 'database', '');
// If we cannot connect to the database, return to the previous step
- if (!self::$installer->checkDB($a->getConfig(), $a->getProfiler(), $dbhost, $dbuser, $dbpass, $dbdata)) {
- self::$currentWizardStep = self::DATABASE_CONFIG;
+ if (!$this->installer->checkDB(DI::dba())) {
+ $this->currentWizardStep = self::DATABASE_CONFIG;
}
break;
case self::FINISHED:
- $urlpath = $a->getURLPath();
- $dbhost = Strings::escapeTags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST)));
- $dbuser = Strings::escapeTags(trim(defaults($_POST, 'dbuser', '')));
- $dbpass = Strings::escapeTags(trim(defaults($_POST, 'dbpass', '')));
- $dbdata = Strings::escapeTags(trim(defaults($_POST, 'dbdata', '')));
- $timezone = Strings::escapeTags(trim(defaults($_POST, 'timezone', Core\Installer::DEFAULT_TZ)));
- $language = Strings::escapeTags(trim(defaults($_POST, 'language', Core\Installer::DEFAULT_LANG)));
- $adminmail = Strings::escapeTags(trim(defaults($_POST, 'adminmail', '')));
+ $this->checkSetting($configCache, $_POST, 'config', 'php_path');
+
+ $this->checkSetting($configCache, $_POST, 'system', 'basepath');
+ $this->checkSetting($configCache, $_POST, 'system', 'url');
+
+ $this->checkSetting($configCache, $_POST, 'database', 'hostname', Core\Installer::DEFAULT_HOST);
+ $this->checkSetting($configCache, $_POST, 'database', 'username', '');
+ $this->checkSetting($configCache, $_POST, 'database', 'password', '');
+ $this->checkSetting($configCache, $_POST, 'database', 'database', '');
+
+ $this->checkSetting($configCache, $_POST, 'system', 'default_timezone', Core\Installer::DEFAULT_TZ);
+ $this->checkSetting($configCache, $_POST, 'system', 'language', Core\Installer::DEFAULT_LANG);
+ $this->checkSetting($configCache, $_POST, 'config', 'admin_email', '');
// If we cannot connect to the database, return to the Database config wizard
- if (!self::$installer->checkDB($a->getConfig(), $a->getProfiler(), $dbhost, $dbuser, $dbpass, $dbdata)) {
- self::$currentWizardStep = self::DATABASE_CONFIG;
+ if (!$this->installer->checkDB(DI::dba())) {
+ $this->currentWizardStep = self::DATABASE_CONFIG;
return;
}
- $phpath = self::$installer->getPHPPath();
-
- if (!self::$installer->createConfig($phpath, $urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $timezone, $language, $adminmail, $a->getBasePath())) {
+ if (!$this->installer->createConfig($configCache)) {
return;
}
- self::$installer->installDatabase($a->getBasePath());
+ $this->installer->installDatabase();
+
+ // install allowed themes to register theme hooks
+ // this is same as "Reload active theme" in /admin/themes
+ $allowed_themes = Theme::getAllowedList();
+ $allowed_themes = array_unique($allowed_themes);
+ foreach ($allowed_themes as $theme) {
+ Theme::uninstall($theme);
+ Theme::install($theme);
+ }
+ Theme::setAllowedList($allowed_themes);
break;
}
}
- public static function content()
+ protected function content(array $request = []): string
{
- $a = self::getApp();
+ $configCache = $this->app->getConfigCache();
$output = '';
- $install_title = L10n::t('Friendica Communications Server - Setup');
+ $install_title = $this->t('Friendica Communications Server - Setup');
- switch (self::$currentWizardStep) {
+ switch ($this->currentWizardStep) {
case self::SYSTEM_CHECK:
- $phppath = defaults($_POST, 'phpath', null);
+ $php_path = $configCache->get('config', 'php_path');
+
+ $status = $this->installer->checkEnvironment($this->baseUrl, $php_path);
- $status = self::$installer->checkEnvironment($a->getBaseURL(), $phppath);
+ $tpl = Renderer::getMarkupTemplate('install/01_checks.tpl');
+ $output .= Renderer::replaceMacros($tpl, [
+ '$title' => $install_title,
+ '$pass' => $this->t('System check'),
+ '$required' => $this->t('Required'),
+ '$requirement_not_satisfied' => $this->t('Requirement not satisfied'),
+ '$optional_requirement_not_satisfied' => $this->t('Optional requirement not satisfied'),
+ '$ok' => $this->t('OK'),
+ '$checks' => $this->installer->getChecks(),
+ '$passed' => $status,
+ '$see_install' => $this->t('Please see the file "doc/INSTALL.md".'),
+ '$next' => $this->t('Next'),
+ '$reload' => $this->t('Check again'),
+ '$php_path' => $php_path,
+ ]);
+ break;
- $tpl = Renderer::getMarkupTemplate('install_checks.tpl');
+ case self::BASE_CONFIG:
+ $baseUrl = $configCache->get('system', 'url') ?
+ new Uri($configCache->get('system', 'url')) :
+ $this->baseUrl;
+
+ $tpl = Renderer::getMarkupTemplate('install/02_base_config.tpl');
$output .= Renderer::replaceMacros($tpl, [
- '$title' => $install_title,
- '$pass' => L10n::t('System check'),
- '$checks' => self::$installer->getChecks(),
- '$passed' => $status,
- '$see_install' => L10n::t('Please see the file "INSTALL.txt".'),
- '$next' => L10n::t('Next'),
- '$reload' => L10n::t('Check again'),
- '$phpath' => $phppath,
- '$baseurl' => $a->getBaseURL()
+ '$title' => $install_title,
+ '$pass' => $this->t('Base settings'),
+ '$basepath' => ['system-basepath',
+ $this->t("Base path to installation"),
+ $configCache->get('system', 'basepath'),
+ $this->t("If the system cannot detect the correct path to your installation, enter the correct path here. This setting should only be set if you are using a restricted system and symbolic links to your webroot."),
+ $this->t('Required')],
+ '$system_url' => ['system-url',
+ $this->t('The Friendica system URL'),
+ (string)$baseUrl,
+ $this->t("Overwrite this field in case the system URL determination isn't right, otherwise leave it as is."),
+ $this->t('Required')],
+ '$php_path' => $configCache->get('config', 'php_path'),
+ '$submit' => $this->t('Submit'),
]);
break;
case self::DATABASE_CONFIG:
- $dbhost = Strings::escapeTags(trim(defaults($_POST, 'dbhost' , Core\Installer::DEFAULT_HOST)));
- $dbuser = Strings::escapeTags(trim(defaults($_POST, 'dbuser' , '' )));
- $dbpass = Strings::escapeTags(trim(defaults($_POST, 'dbpass' , '' )));
- $dbdata = Strings::escapeTags(trim(defaults($_POST, 'dbdata' , '' )));
- $phpath = Strings::escapeTags(trim(defaults($_POST, 'phpath' , '' )));
- $adminmail = Strings::escapeTags(trim(defaults($_POST, 'adminmail', '' )));
-
- $tpl = Renderer::getMarkupTemplate('install_db.tpl');
+ $tpl = Renderer::getMarkupTemplate('install/03_database_config.tpl');
$output .= Renderer::replaceMacros($tpl, [
- '$title' => $install_title,
- '$pass' => L10n::t('Database connection'),
- '$info_01' => L10n::t('In order to install Friendica we need to know how to connect to your database.'),
- '$info_02' => L10n::t('Please contact your hosting provider or site administrator if you have questions about these settings.'),
- '$info_03' => L10n::t('The database you specify below should already exist. If it does not, please create it before continuing.'),
- 'checks' => self::$installer->getChecks(),
- '$dbhost' => ['dbhost',
- L10n::t('Database Server Name'),
- $dbhost,
- '',
- 'required'],
- '$dbuser' => ['dbuser',
- L10n::t('Database Login Name'),
- $dbuser,
- '',
- 'required',
- 'autofocus'],
- '$dbpass' => ['dbpass',
- L10n::t('Database Login Password'),
- $dbpass,
- L10n::t("For security reasons the password must not be empty"),
- 'required'],
- '$dbdata' => ['dbdata',
- L10n::t('Database Name'),
- $dbdata,
- '',
- 'required'],
- '$adminmail' => ['adminmail',
- L10n::t('Site administrator email address'),
- $adminmail,
- L10n::t('Your account email address must match this in order to use the web admin panel.'),
- 'required',
- 'autofocus',
- 'email'],
- '$lbl_10' => L10n::t('Please select a default timezone for your website'),
- '$baseurl' => $a->getBaseURL(),
- '$phpath' => $phpath,
- '$submit' => L10n::t('Submit')
+ '$title' => $install_title,
+ '$pass' => $this->t('Database connection'),
+ '$info_01' => $this->t('In order to install Friendica we need to know how to connect to your database.'),
+ '$info_02' => $this->t('Please contact your hosting provider or site administrator if you have questions about these settings.'),
+ '$info_03' => $this->t('The database you specify below should already exist. If it does not, please create it before continuing.'),
+ '$required' => $this->t('Required'),
+ '$requirement_not_satisfied' => $this->t('Requirement not satisfied'),
+ '$checks' => $this->installer->getChecks(),
+ '$basepath' => $configCache->get('system', 'basepath'),
+ '$system_url' => $configCache->get('system', 'url'),
+ '$dbhost' => ['database-hostname',
+ $this->t('Database Server Name'),
+ $configCache->get('database', 'hostname'),
+ '',
+ $this->t('Required')],
+ '$dbuser' => ['database-username',
+ $this->t('Database Login Name'),
+ $configCache->get('database', 'username'),
+ '',
+ $this->t('Required'),
+ 'autofocus'],
+ '$dbpass' => ['database-password',
+ $this->t('Database Login Password'),
+ $configCache->get('database', 'password'),
+ $this->t("For security reasons the password must not be empty"),
+ $this->t('Required')],
+ '$dbdata' => ['database-database',
+ $this->t('Database Name'),
+ $configCache->get('database', 'database'),
+ '',
+ $this->t('Required')],
+ '$lbl_10' => $this->t('Please select a default timezone for your website'),
+ '$php_path' => $configCache->get('config', 'php_path'),
+ '$submit' => $this->t('Submit')
]);
break;
case self::SITE_SETTINGS:
- $dbhost = Strings::escapeTags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST)));
- $dbuser = Strings::escapeTags(trim(defaults($_POST, 'dbuser', '' )));
- $dbpass = Strings::escapeTags(trim(defaults($_POST, 'dbpass', '' )));
- $dbdata = Strings::escapeTags(trim(defaults($_POST, 'dbdata', '' )));
- $phpath = Strings::escapeTags(trim(defaults($_POST, 'phpath', '' )));
-
- $adminmail = Strings::escapeTags(trim(defaults($_POST, 'adminmail', '')));
-
- $timezone = defaults($_POST, 'timezone', Core\Installer::DEFAULT_TZ);
/* Installed langs */
- $lang_choices = L10n::getAvailableLanguages();
+ $lang_choices = $this->l10n->getAvailableLanguages();
- $tpl = Renderer::getMarkupTemplate('install_settings.tpl');
+ $tpl = Renderer::getMarkupTemplate('install/04_site_settings.tpl');
$output .= Renderer::replaceMacros($tpl, [
- '$title' => $install_title,
- '$checks' => self::$installer->getChecks(),
- '$pass' => L10n::t('Site settings'),
- '$dbhost' => $dbhost,
- '$dbuser' => $dbuser,
- '$dbpass' => $dbpass,
- '$dbdata' => $dbdata,
- '$phpath' => $phpath,
- '$adminmail' => ['adminmail', L10n::t('Site administrator email address'), $adminmail, L10n::t('Your account email address must match this in order to use the web admin panel.'), 'required', 'autofocus', 'email'],
- '$timezone' => Temporal::getTimezoneField('timezone', L10n::t('Please select a default timezone for your website'), $timezone, ''),
- '$language' => ['language',
- L10n::t('System Language:'),
- Core\Installer::DEFAULT_LANG,
- L10n::t('Set the default language for your Friendica installation interface and to send emails.'),
- $lang_choices],
- '$baseurl' => $a->getBaseURL(),
- '$submit' => L10n::t('Submit')
+ '$title' => $install_title,
+ '$required' => $this->t('Required'),
+ '$checks' => $this->installer->getChecks(),
+ '$pass' => $this->t('Site settings'),
+ '$basepath' => $configCache->get('system', 'basepath'),
+ '$system_url' => $configCache->get('system', 'url'),
+ '$dbhost' => $configCache->get('database', 'hostname'),
+ '$dbuser' => $configCache->get('database', 'username'),
+ '$dbpass' => $configCache->get('database', 'password'),
+ '$dbdata' => $configCache->get('database', 'database'),
+ '$adminmail' => ['config-admin_email',
+ $this->t('Site administrator email address'),
+ $configCache->get('config', 'admin_email'),
+ $this->t('Your account email address must match this in order to use the web admin panel.'),
+ $this->t('Required'), 'autofocus', 'email'],
+ '$timezone' => Temporal::getTimezoneField('system-default_timezone',
+ $this->t('Please select a default timezone for your website'),
+ $configCache->get('system', 'default_timezone'),
+ ''),
+ '$language' => ['system-language',
+ $this->t('System Language:'),
+ $configCache->get('system', 'language'),
+ $this->t('Set the default language for your Friendica installation interface and to send emails.'),
+ $lang_choices],
+ '$php_path' => $configCache->get('config', 'php_path'),
+ '$submit' => $this->t('Submit')
]);
break;
case self::FINISHED:
$db_return_text = "";
- if (count(self::$installer->getChecks()) == 0) {
- $txt = '<p style="font-size: 130%;">';
- $txt .= L10n::t('Your Friendica site database has been installed.') . EOL;
+ if (count($this->installer->getChecks()) == 0) {
+ $txt = '<p style="font-size: 130%;">';
+ $txt .= $this->t('Your Friendica site database has been installed.') . '<br />';
$db_return_text .= $txt;
}
- $tpl = Renderer::getMarkupTemplate('install_finished.tpl');
+ $tpl = Renderer::getMarkupTemplate('install/05_finished.tpl');
$output .= Renderer::replaceMacros($tpl, [
- '$title' => $install_title,
- '$checks' => self::$installer->getChecks(),
- '$pass' => L10n::t('Installation finished'),
- '$text' => $db_return_text . self::whatNext($a),
+ '$title' => $install_title,
+ '$required' => $this->t('Required'),
+ '$requirement_not_satisfied' => $this->t('Requirement not satisfied'),
+ '$checks' => $this->installer->getChecks(),
+ '$pass' => $this->t('Installation finished'),
+ '$text' => $db_return_text . $this->whatNext(),
]);
break;
/**
* Creates the text for the next steps
*
- * @param App $a The global App
- *
* @return string The text for the next steps
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- private static function whatNext($a)
+ private function whatNext(): string
{
- $baseurl = $a->getBaseUrl();
+ $baseurl = $this->baseUrl;
return
- L10n::t('<h1>What next</h1>')
- . "<p>".L10n::t('IMPORTANT: You will need to [manually] setup a scheduled task for the worker.')
- . L10n::t('Please see the file "INSTALL.txt".')
+ $this->t('<h1>What next</h1>')
+ . "<p>" . $this->t('IMPORTANT: You will need to [manually] setup a scheduled task for the worker.')
+ . $this->t('Please see the file "doc/INSTALL.md".')
. "</p><p>"
- . L10n::t('Go to your new Friendica node <a href="%s/register">registration page</a> and register as new user. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.', $baseurl)
+ . $this->t('Go to your new Friendica node <a href="%s/register">registration page</a> and register as new user. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.', $baseurl)
. "</p>";
}
+
+ /**
+ * Checks the $_POST settings and updates the config Cache for it
+ *
+ * @param \Friendica\Core\Config\ValueObject\Cache $configCache The current config cache
+ * @param array $post The $_POST data
+ * @param string $cat The category of the setting
+ * @param string $key The key of the setting
+ * @param null|string $default The default value
+ * @return void
+ */
+ private function checkSetting(Cache $configCache, array $post, string $cat, string $key, ?string $default = null)
+ {
+ $value = null;
+
+ if (isset($post[sprintf('%s-%s', $cat, $key)])) {
+ $value = trim($post[sprintf('%s-%s', $cat, $key)]);
+ }
+
+ if (isset($value)) {
+ $configCache->set($cat, $key, $value, Cache::SOURCE_ENV);
+ return;
+ }
+
+ if (isset($default)) {
+ $configCache->set($cat, $key, $default, Cache::SOURCE_ENV);
+ }
+ }
}