قرینه از
https://github.com/matomo-org/matomo.git
synced 2025-08-21 22:47:43 +00:00

* Use #[\SensitiveParameter] php attribute to hide sensitive parameters from strack traces * also hide database config parameters * also hide 2fa codes and secrets * hide some more parameters * add attribute to remaining sensitive parameters * update matomo-org/matomo-coding-standards
835 خطوط
27 KiB
PHP
835 خطوط
27 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Matomo - free/libre analytics platform
|
|
*
|
|
* @link https://matomo.org
|
|
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
|
*/
|
|
|
|
namespace Piwik\Plugins\Installation;
|
|
|
|
use Exception;
|
|
use Piwik\Access;
|
|
use Piwik\Application\Kernel\GlobalSettingsProvider;
|
|
use Piwik\AssetManager;
|
|
use Piwik\Common;
|
|
use Piwik\Config;
|
|
use Piwik\Container\StaticContainer;
|
|
use Piwik\DataAccess\ArchiveTableCreator;
|
|
use Piwik\Date;
|
|
use Piwik\Db;
|
|
use Piwik\DbHelper;
|
|
use Piwik\Filesystem;
|
|
use Piwik\Option;
|
|
use Piwik\Piwik;
|
|
use Piwik\Plugin\ControllerAdmin;
|
|
use Piwik\Plugin\Manager;
|
|
use Piwik\Plugins\CoreVue\CoreVue;
|
|
use Piwik\Plugins\Diagnostics\DiagnosticReport;
|
|
use Piwik\Plugins\Diagnostics\DiagnosticService;
|
|
use Piwik\Plugins\LanguagesManager\LanguagesManager;
|
|
use Piwik\Plugins\SitesManager\API as APISitesManager;
|
|
use Piwik\Plugins\SitesManager\SitesManager;
|
|
use Piwik\Plugins\UsersManager\API as APIUsersManager;
|
|
use Piwik\Plugins\UsersManager\NewsletterSignup;
|
|
use Piwik\Plugins\UsersManager\UserUpdater;
|
|
use Piwik\ProxyHeaders;
|
|
use Piwik\SettingsPiwik;
|
|
use Piwik\Tracker\TrackerCodeGenerator;
|
|
use Piwik\Translation\Translator;
|
|
use Piwik\Updater;
|
|
use Piwik\Url;
|
|
use Piwik\Version;
|
|
use Zend_Db_Adapter_Exception;
|
|
|
|
/**
|
|
* Installation controller
|
|
*/
|
|
class Controller extends ControllerAdmin
|
|
{
|
|
public $steps = array(
|
|
'welcome' => 'Installation_Welcome',
|
|
'systemCheck' => 'Installation_SystemCheck',
|
|
'databaseSetup' => 'Installation_DatabaseSetup',
|
|
'tablesCreation' => 'Installation_Tables',
|
|
'setupSuperUser' => 'Installation_SuperUser',
|
|
'firstWebsiteSetup' => 'Installation_SetupWebsite',
|
|
'trackingCode' => 'General_JsTrackingTag',
|
|
'finished' => 'Installation_Congratulations',
|
|
);
|
|
|
|
/**
|
|
* Get installation steps
|
|
*
|
|
* @return array installation steps
|
|
*/
|
|
public function getInstallationSteps()
|
|
{
|
|
return $this->steps;
|
|
}
|
|
|
|
/**
|
|
* Get default action (first installation step)
|
|
*
|
|
* @return string function name
|
|
*/
|
|
public function getDefaultAction()
|
|
{
|
|
$steps = array_keys($this->steps);
|
|
return $steps[0];
|
|
}
|
|
|
|
/**
|
|
* Installation Step 1: Welcome
|
|
*
|
|
* Can also display an error message when there is a failure early (eg. DB connection failed)
|
|
*
|
|
* @param string $possibleErrorMessage Possible error message which may be set in the frontcontroller when event. Config.badConfigurationFile was triggered
|
|
*/
|
|
public function welcome($possibleErrorMessage = null)
|
|
{
|
|
// Delete merged js/css files to force regenerations based on updated activated plugin list
|
|
Filesystem::deleteAllCacheOnUpdate();
|
|
|
|
$this->checkPiwikIsNotInstalled($possibleErrorMessage);
|
|
$this->checkInstallationIsNotExpired();
|
|
|
|
$view = new View(
|
|
'@Installation/welcome',
|
|
$this->getInstallationSteps(),
|
|
__FUNCTION__
|
|
);
|
|
|
|
$view->showNextStep = true;
|
|
return $view->render();
|
|
}
|
|
|
|
/**
|
|
* Installation Step 2: System Check
|
|
*/
|
|
public function systemCheck()
|
|
{
|
|
$this->checkPiwikIsNotInstalled();
|
|
$this->deleteConfigFileIfNeeded();
|
|
$this->checkInstallationIsNotExpired();
|
|
|
|
$view = new View(
|
|
'@Installation/systemCheck',
|
|
$this->getInstallationSteps(),
|
|
__FUNCTION__
|
|
);
|
|
|
|
// Do not use dependency injection because this service requires a lot of sub-services across plugins
|
|
/** @var DiagnosticService $diagnosticService */
|
|
$diagnosticService = StaticContainer::get('Piwik\Plugins\Diagnostics\DiagnosticService');
|
|
$view->diagnosticReport = $diagnosticService->runDiagnostics();
|
|
$view->isInstallation = true;
|
|
$view->systemCheckInfo = $this->getSystemCheckTextareaValue($view->diagnosticReport);
|
|
|
|
$view->showNextStep = !$view->diagnosticReport->hasErrors();
|
|
|
|
// On the system check page, if all is green, display Next link at the top
|
|
$view->showNextStepAtTop = $view->showNextStep && !$view->diagnosticReport->hasWarnings();
|
|
|
|
return $view->render();
|
|
}
|
|
|
|
/**
|
|
* Installation Step 3: Database Set-up
|
|
* @throws Exception|Zend_Db_Adapter_Exception
|
|
*/
|
|
public function databaseSetup()
|
|
{
|
|
$this->checkPiwikIsNotInstalled();
|
|
$this->checkInstallationIsNotExpired();
|
|
|
|
$view = new View(
|
|
'@Installation/databaseSetup',
|
|
$this->getInstallationSteps(),
|
|
__FUNCTION__
|
|
);
|
|
|
|
$view->showNextStep = false;
|
|
|
|
$form = new FormDatabaseSetup();
|
|
|
|
if ($form->validate()) {
|
|
try {
|
|
$dbInfos = $form->createDatabaseObject();
|
|
|
|
DbHelper::checkDatabaseVersion();
|
|
|
|
|
|
Db::get()->checkClientVersion();
|
|
|
|
$this->createConfigFile($dbInfos);
|
|
|
|
$this->redirectToNextStep(__FUNCTION__);
|
|
} catch (Exception $e) {
|
|
$view->errorMessage = Common::sanitizeInputValue($e->getMessage());
|
|
}
|
|
}
|
|
$view->addForm($form);
|
|
|
|
return $view->render();
|
|
}
|
|
|
|
/**
|
|
* Installation Step 4: Table Creation
|
|
*/
|
|
public function tablesCreation()
|
|
{
|
|
$this->checkPiwikIsNotInstalled();
|
|
$this->checkInstallationIsNotExpired();
|
|
|
|
$view = new View(
|
|
'@Installation/tablesCreation',
|
|
$this->getInstallationSteps(),
|
|
__FUNCTION__
|
|
);
|
|
|
|
if ($this->getParam('deleteTables')) {
|
|
Manager::getInstance()->clearPluginsInstalledConfig();
|
|
Db::dropAllTables();
|
|
$view->existingTablesDeleted = true;
|
|
}
|
|
|
|
$tablesInstalled = DbHelper::getTablesInstalled();
|
|
$view->tablesInstalled = '';
|
|
|
|
if (count($tablesInstalled) > 0) {
|
|
// we have existing tables
|
|
$view->tablesInstalled = implode(', ', $tablesInstalled);
|
|
$view->someTablesInstalled = true;
|
|
|
|
$self = $this;
|
|
Access::doAsSuperUser(function () use ($self, $tablesInstalled, $view) {
|
|
Access::getInstance();
|
|
if (
|
|
$self->hasEnoughTablesToReuseDb($tablesInstalled) &&
|
|
count(APISitesManager::getInstance()->getAllSitesId()) > 0 &&
|
|
count(APIUsersManager::getInstance()->getUsers()) > 0
|
|
) {
|
|
$view->showReuseExistingTables = true;
|
|
}
|
|
});
|
|
} else {
|
|
DbHelper::createTables();
|
|
DbHelper::createAnonymousUser();
|
|
DbHelper::recordInstallVersion();
|
|
|
|
$this->updateComponents();
|
|
|
|
Updater::recordComponentSuccessfullyUpdated('core', Version::VERSION);
|
|
|
|
$view->tablesCreated = true;
|
|
$view->showNextStep = true;
|
|
}
|
|
|
|
return $view->render();
|
|
}
|
|
|
|
public function reuseTables()
|
|
{
|
|
$this->checkPiwikIsNotInstalled();
|
|
$this->checkInstallationIsNotExpired();
|
|
|
|
$steps = $this->getInstallationSteps();
|
|
$steps['tablesCreation'] = 'Installation_ReusingTables';
|
|
|
|
$view = new View(
|
|
'@Installation/reuseTables',
|
|
$steps,
|
|
'tablesCreation'
|
|
);
|
|
|
|
$oldVersion = Option::get('version_core');
|
|
|
|
$result = $this->updateComponents();
|
|
if ($result === false) {
|
|
$this->redirectToNextStep('tablesCreation');
|
|
}
|
|
|
|
$view->coreError = $result['coreError'];
|
|
$view->warningMessages = $result['warnings'];
|
|
$view->errorMessages = $result['errors'];
|
|
$view->deactivatedPlugins = $result['deactivatedPlugins'];
|
|
$view->currentVersion = Version::VERSION;
|
|
$view->oldVersion = $oldVersion;
|
|
$view->showNextStep = true;
|
|
|
|
return $view->render();
|
|
}
|
|
|
|
/**
|
|
* Installation Step 5: General Set-up (superuser login/password/email and subscriptions)
|
|
*/
|
|
public function setupSuperUser()
|
|
{
|
|
$this->checkPiwikIsNotInstalled();
|
|
$this->checkInstallationIsNotExpired();
|
|
|
|
$superUserAlreadyExists = Access::doAsSuperUser(function () {
|
|
return count(APIUsersManager::getInstance()->getUsersHavingSuperUserAccess()) > 0;
|
|
});
|
|
|
|
if ($superUserAlreadyExists) {
|
|
$this->redirectToNextStep('setupSuperUser');
|
|
}
|
|
|
|
$view = new View(
|
|
'@Installation/setupSuperUser',
|
|
$this->getInstallationSteps(),
|
|
__FUNCTION__
|
|
);
|
|
|
|
$form = new FormSuperUser();
|
|
|
|
if ($form->validate()) {
|
|
try {
|
|
$loginName = $form->getSubmitValue('login');
|
|
$email = $form->getSubmitValue('email');
|
|
|
|
$this->createSuperUser(
|
|
$loginName,
|
|
$form->getSubmitValue('password'),
|
|
$email
|
|
);
|
|
|
|
$newsletterPiwikORG = $form->getSubmitValue('subscribe_newsletter_piwikorg');
|
|
$newsletterProfessionalServices = $form->getSubmitValue('subscribe_newsletter_professionalservices');
|
|
NewsletterSignup::signupForNewsletter(
|
|
$loginName,
|
|
$email,
|
|
$newsletterPiwikORG,
|
|
$newsletterProfessionalServices
|
|
);
|
|
Onboarding::sendSysAdminMail($email);
|
|
$this->redirectToNextStep(__FUNCTION__);
|
|
} catch (Exception $e) {
|
|
$view->errorMessage = $e->getMessage();
|
|
}
|
|
}
|
|
|
|
$view->addForm($form);
|
|
|
|
return $view->render();
|
|
}
|
|
|
|
/**
|
|
* Installation Step 6: Configure first web-site
|
|
*/
|
|
public function firstWebsiteSetup()
|
|
{
|
|
$this->checkPiwikIsNotInstalled();
|
|
$this->checkInstallationIsNotExpired();
|
|
|
|
ServerFilesGenerator::createFilesForSecurity();
|
|
|
|
$siteIdsCount = Access::doAsSuperUser(function () {
|
|
return count(APISitesManager::getInstance()->getAllSitesId());
|
|
});
|
|
|
|
if ($siteIdsCount > 0) {
|
|
// if there is a already a website, skip this step and trackingCode step
|
|
$this->redirectToNextStep('trackingCode');
|
|
}
|
|
|
|
$view = new View(
|
|
'@Installation/firstWebsiteSetup',
|
|
$this->getInstallationSteps(),
|
|
__FUNCTION__
|
|
);
|
|
|
|
$form = new FormFirstWebsiteSetup();
|
|
|
|
if ($form->validate()) {
|
|
$name = Common::sanitizeInputValue($form->getSubmitValue('siteName'));
|
|
$url = Common::unsanitizeInputValue($form->getSubmitValue('url'));
|
|
$ecommerce = (int)$form->getSubmitValue('ecommerce');
|
|
|
|
try {
|
|
$result = Access::doAsSuperUser(function () use ($name, $url, $ecommerce) {
|
|
return APISitesManager::getInstance()->addSite($name, $url, $ecommerce);
|
|
});
|
|
|
|
$params = array(
|
|
'site_idSite' => $result,
|
|
'site_name' => urlencode($name)
|
|
);
|
|
|
|
$this->redirectToNextStep(__FUNCTION__, $params);
|
|
} catch (Exception $e) {
|
|
$view->errorMessage = $e->getMessage();
|
|
}
|
|
}
|
|
|
|
// Display previous step success message, when current step form was not submitted yet
|
|
if (count($form->getErrorMessages()) == 0) {
|
|
$view->displayGeneralSetupSuccess = true;
|
|
}
|
|
|
|
$view->addForm($form);
|
|
return $view->render();
|
|
}
|
|
|
|
/**
|
|
* Installation Step 7: Display JavaScript tracking code
|
|
*/
|
|
public function trackingCode()
|
|
{
|
|
$this->checkPiwikIsNotInstalled();
|
|
$this->checkInstallationIsNotExpired();
|
|
|
|
$view = new View(
|
|
'@Installation/trackingCode',
|
|
$this->getInstallationSteps(),
|
|
__FUNCTION__
|
|
);
|
|
|
|
$siteName = Common::unsanitizeInputValue($this->getParam('site_name'));
|
|
$idSite = $this->getParam('site_idSite');
|
|
|
|
$javascriptGenerator = new TrackerCodeGenerator();
|
|
$jsTag = $javascriptGenerator->generate($idSite, Url::getCurrentUrlWithoutFileName());
|
|
|
|
// Needs to be generated as super user, as API requests would otherwise fail
|
|
$emailBody = Access::doAsSuperUser(
|
|
function () use ($idSite) {
|
|
return SitesManager::renderTrackingCodeEmail($idSite);
|
|
}
|
|
);
|
|
|
|
// Load the Tracking code and help text from the SitesManager
|
|
$viewTrackingHelp = new \Piwik\View('@SitesManager/_displayJavascriptCode');
|
|
$viewTrackingHelp->displaySiteName = $siteName;
|
|
$viewTrackingHelp->jsTag = $jsTag;
|
|
$viewTrackingHelp->emailBody = $emailBody;
|
|
$viewTrackingHelp->idSite = $idSite;
|
|
$viewTrackingHelp->piwikUrl = Url::getCurrentUrlWithoutFileName();
|
|
$viewTrackingHelp->isInstall = true;
|
|
|
|
$view->trackingHelp = $viewTrackingHelp->render();
|
|
$view->displaySiteName = $siteName;
|
|
|
|
$view->displayfirstWebsiteSetupSuccess = true;
|
|
$view->showNextStep = true;
|
|
|
|
return $view->render();
|
|
}
|
|
|
|
/**
|
|
* Installation Step 8: Finished!
|
|
*/
|
|
public function finished()
|
|
{
|
|
$this->checkPiwikIsNotInstalled();
|
|
$this->checkInstallationIsNotExpired();
|
|
|
|
$view = new View(
|
|
'@Installation/finished',
|
|
$this->getInstallationSteps(),
|
|
__FUNCTION__
|
|
);
|
|
|
|
$form = new FormDefaultSettings();
|
|
|
|
/**
|
|
* Triggered on initialization of the form to customize default Matomo settings (at the end of the installation process).
|
|
*
|
|
* @param \Piwik\Plugins\Installation\FormDefaultSettings $form
|
|
*/
|
|
Piwik::postEvent('Installation.defaultSettingsForm.init', array($form));
|
|
|
|
$form->addElement('submit', 'submit', array('value' => Piwik::translate('General_ContinueToPiwik') . ' »', 'class' => 'btn'));
|
|
|
|
if ($form->validate()) {
|
|
try {
|
|
/**
|
|
* Triggered on submission of the form to customize default Matomo settings (at the end of the installation process).
|
|
*
|
|
* @param \Piwik\Plugins\Installation\FormDefaultSettings $form
|
|
*/
|
|
Piwik::postEvent('Installation.defaultSettingsForm.submit', array($form));
|
|
|
|
$this->markInstallationAsCompleted();
|
|
|
|
Url::redirectToUrl('index.php');
|
|
} catch (Exception $e) {
|
|
$view->errorMessage = $e->getMessage();
|
|
}
|
|
}
|
|
|
|
$view->addForm($form);
|
|
|
|
$view->showNextStep = false;
|
|
$output = $view->render();
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* System check will call this page which should load quickly,
|
|
* in order to look at Response headers (eg. to detect if pagespeed is running)
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getEmptyPageForSystemCheck()
|
|
{
|
|
return 'Hello, world!';
|
|
}
|
|
|
|
/**
|
|
* This controller action renders an admin tab that runs the installation
|
|
* system check, so people can see if there are any issues w/ their running
|
|
* Matomo installation.
|
|
*
|
|
* This admin tab is only viewable by the Super User.
|
|
*/
|
|
public function systemCheckPage()
|
|
{
|
|
Piwik::checkUserHasSuperUserAccess();
|
|
|
|
$view = new View(
|
|
'@Installation/systemCheckPage',
|
|
$this->getInstallationSteps(),
|
|
__FUNCTION__
|
|
);
|
|
$this->setBasicVariablesView($view);
|
|
|
|
/** @var DiagnosticService $diagnosticService */
|
|
$diagnosticService = StaticContainer::get('Piwik\Plugins\Diagnostics\DiagnosticService');
|
|
$view->diagnosticReport = $diagnosticService->runDiagnostics();
|
|
$view->systemCheckInfo = $this->getSystemCheckTextareaValue($view->diagnosticReport);
|
|
return $view->render();
|
|
}
|
|
|
|
/**
|
|
* Save language selection in session-store
|
|
*/
|
|
public function saveLanguage()
|
|
{
|
|
if (DbHelper::isInstalled()) {
|
|
$this->checkTokenInUrl();
|
|
}
|
|
$language = $this->getParam('language');
|
|
LanguagesManager::setLanguageForSession($language);
|
|
Url::redirectToReferrer();
|
|
}
|
|
|
|
/**
|
|
* Return the base.less compiled to css
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getInstallationCss()
|
|
{
|
|
Common::sendHeader('Content-Type: text/css');
|
|
Common::sendHeader('Cache-Control: max-age=' . (60 * 60));
|
|
|
|
$files = array(
|
|
'plugins/Morpheus/stylesheets/base/bootstrap.css',
|
|
'plugins/Morpheus/stylesheets/base/icons.css',
|
|
"node_modules/jquery-ui-dist/jquery-ui.theme.min.css",
|
|
'node_modules/@materializecss/materialize/dist/css/materialize.min.css',
|
|
'plugins/Morpheus/stylesheets/base.less',
|
|
'plugins/Morpheus/stylesheets/general/_forms.less',
|
|
'plugins/Installation/stylesheets/installation.css'
|
|
);
|
|
|
|
return AssetManager::compileCustomStylesheets($files);
|
|
}
|
|
|
|
/**
|
|
* Return the base.less compiled to css
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getInstallationJs()
|
|
{
|
|
Common::sendHeader('Content-Type: application/javascript; charset=UTF-8');
|
|
Common::sendHeader('Cache-Control: max-age=' . (60 * 60));
|
|
|
|
$files = array(
|
|
"node_modules/jquery/dist/jquery.min.js",
|
|
"node_modules/jquery-ui-dist/jquery-ui.min.js",
|
|
'node_modules/@materializecss/materialize/dist/js/materialize.min.js',
|
|
"plugins/CoreHome/javascripts/materialize-bc.js",
|
|
'plugins/Installation/javascripts/installation.js',
|
|
'plugins/Morpheus/javascripts/piwikHelper.js',
|
|
"plugins/CoreHome/javascripts/broadcast.js",
|
|
);
|
|
|
|
CoreVue::addJsFilesTo($files);
|
|
|
|
$files[] = AssetManager\UIAssetFetcher\PluginUmdAssetFetcher::getUmdFileToUseForPlugin('CoreHome');
|
|
$files[] = AssetManager\UIAssetFetcher\PluginUmdAssetFetcher::getUmdFileToUseForPlugin('Installation');
|
|
|
|
if (
|
|
defined('PIWIK_TEST_MODE') && PIWIK_TEST_MODE
|
|
&& file_exists(PIWIK_DOCUMENT_ROOT . '/tests/resources/screenshot-override/override.js')
|
|
) {
|
|
$files[] = 'tests/resources/screenshot-override/override.js';
|
|
}
|
|
|
|
return AssetManager::compileCustomJs($files);
|
|
}
|
|
|
|
private function getParam($name)
|
|
{
|
|
return Common::getRequestVar($name, false, 'string');
|
|
}
|
|
|
|
/**
|
|
* Write configuration file from session-store
|
|
*/
|
|
private function createConfigFile($dbInfos)
|
|
{
|
|
$config = Config::getInstance();
|
|
|
|
// make sure DB sessions are used if the filesystem is NFS
|
|
if (count($headers = ProxyHeaders::getProxyClientHeaders()) > 0) {
|
|
$config->General['proxy_client_headers'] = $headers;
|
|
}
|
|
if (count($headers = ProxyHeaders::getProxyHostHeaders()) > 0) {
|
|
$config->General['proxy_host_headers'] = $headers;
|
|
}
|
|
|
|
if (Common::getRequestVar('clientProtocol', 'http', 'string') == 'https') {
|
|
$protocol = 'https';
|
|
} else {
|
|
$protocol = ProxyHeaders::getProtocolInformation();
|
|
}
|
|
|
|
if (
|
|
!empty($protocol)
|
|
&& !\Piwik\ProxyHttp::isHttps()
|
|
) {
|
|
$config->General['assume_secure_protocol'] = '1';
|
|
}
|
|
|
|
$config->General['salt'] = Common::generateUniqId();
|
|
$config->General['installation_in_progress'] = 1;
|
|
$this->setTrustedHost($config);
|
|
|
|
$config->database = $dbInfos;
|
|
$config->database['charset'] = DbHelper::getDefaultCharset();
|
|
$config->database['collation'] = DbHelper::getDefaultCollationForCharset($config->database['charset']);
|
|
|
|
$config->forceSave();
|
|
|
|
// re-save the currently viewed language (since we saved the config file, there is now a salt which makes the
|
|
// existing session cookie invalid)
|
|
$this->resetLanguageCookie();
|
|
}
|
|
|
|
private function resetLanguageCookie()
|
|
{
|
|
/** @var Translator $translator */
|
|
$translator = StaticContainer::get('Piwik\Translation\Translator');
|
|
LanguagesManager::setLanguageForSession($translator->getCurrentLanguage());
|
|
}
|
|
|
|
private function checkPiwikIsNotInstalled($possibleErrorMessage = null)
|
|
{
|
|
if (!SettingsPiwik::isMatomoInstalled()) {
|
|
return;
|
|
}
|
|
|
|
$possibleErrorMessage = $possibleErrorMessage ? sprintf('<br/><br/>Original error was "%s".<br/>', $possibleErrorMessage) : '';
|
|
|
|
\Piwik\Plugins\Login\Controller::clearSession();
|
|
$message = Piwik::translate(
|
|
'Installation_InvalidStateError',
|
|
array($possibleErrorMessage . '<br /><strong>',
|
|
// piwik-is-already-installed is checked against in checkPiwikServerWorking
|
|
'</strong><a id="piwik-is-already-installed" href=\'' . Common::sanitizeInputValue(Url::getCurrentUrlWithoutFileName()) . '\'>',
|
|
'</a>')
|
|
);
|
|
Piwik::exitWithErrorMessage($message);
|
|
}
|
|
|
|
/**
|
|
* Write configuration file from session-store
|
|
*/
|
|
private function markInstallationAsCompleted()
|
|
{
|
|
$config = Config::getInstance();
|
|
unset($config->General['installation_in_progress']);
|
|
unset($config->General['installation_first_accessed']);
|
|
$config->forceSave();
|
|
}
|
|
|
|
/**
|
|
* Redirect to next step
|
|
*
|
|
* @param string $currentStep Current step
|
|
* @return void
|
|
*/
|
|
private function redirectToNextStep($currentStep, $parameters = array())
|
|
{
|
|
$steps = array_keys($this->steps);
|
|
$nextStep = $steps[1 + array_search($currentStep, $steps)];
|
|
Piwik::redirectToModule('Installation', $nextStep, $parameters);
|
|
}
|
|
|
|
/**
|
|
* Extract host from URL
|
|
*
|
|
* @param string $url URL
|
|
*
|
|
* @return string|false
|
|
*/
|
|
private function extractHostAndPort($url)
|
|
{
|
|
$host = parse_url($url, PHP_URL_HOST) ?? false;
|
|
|
|
if (empty($host)) {
|
|
return false;
|
|
}
|
|
|
|
$port = (int) parse_url($url, PHP_URL_PORT) ?? 0;
|
|
|
|
if (!empty($port) && $port !== 80 && $port !== 443) {
|
|
return $host . ':' . $port;
|
|
}
|
|
|
|
return $host;
|
|
}
|
|
|
|
/**
|
|
* Sets trusted hosts in config
|
|
*/
|
|
private function setTrustedHost(Config $config): void
|
|
{
|
|
$host = Url::getHost(false);
|
|
|
|
// check hostname in server variables is correctly parsable
|
|
if ($host === $this->extractHostAndPort('http://' . $host)) {
|
|
$config->General['trusted_hosts'] = [$host];
|
|
}
|
|
}
|
|
|
|
private function createSuperUser(
|
|
$login,
|
|
#[\SensitiveParameter]
|
|
$password,
|
|
$email
|
|
) {
|
|
Access::doAsSuperUser(function () use ($login, $password, $email) {
|
|
$api = APIUsersManager::getInstance();
|
|
$api->addUser($login, $password, $email);
|
|
|
|
$userUpdater = new UserUpdater();
|
|
$userUpdater->setSuperUserAccessWithoutCurrentPassword($login, true);
|
|
});
|
|
}
|
|
|
|
// should be private but there's a bug in php 5.3.6
|
|
public function hasEnoughTablesToReuseDb($tablesInstalled)
|
|
{
|
|
if (empty($tablesInstalled) || !is_array($tablesInstalled)) {
|
|
return false;
|
|
}
|
|
|
|
$archiveTables = ArchiveTableCreator::getTablesArchivesInstalled();
|
|
$baseTablesInstalled = count($tablesInstalled) - count($archiveTables);
|
|
$minimumCountPiwikTables = 12;
|
|
|
|
return $baseTablesInstalled >= $minimumCountPiwikTables;
|
|
}
|
|
|
|
private function deleteConfigFileIfNeeded()
|
|
{
|
|
$config = Config::getInstance();
|
|
|
|
if ($config->existsLocalConfig()) {
|
|
$firstInstallationAccess = $config->General['installation_first_accessed'];
|
|
$settingsProvider = StaticContainer::get(GlobalSettingsProvider::class);
|
|
|
|
$config->deleteLocalConfig();
|
|
$settingsProvider->reload();
|
|
$this->setUpInstallationExpiration($config, $firstInstallationAccess);
|
|
|
|
// deleting the config file removes the salt, which in turns invalidates existing cookies (including the
|
|
// one for selected language), so we re-save that cookie now
|
|
$this->resetLanguageCookie();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return array|bool
|
|
*/
|
|
protected function updateComponents()
|
|
{
|
|
Access::getInstance();
|
|
|
|
return Access::doAsSuperUser(function () {
|
|
$updater = new Updater();
|
|
$componentsWithUpdateFile = $updater->getComponentUpdates();
|
|
|
|
if (empty($componentsWithUpdateFile)) {
|
|
return false;
|
|
}
|
|
$result = $updater->updateComponents($componentsWithUpdateFile);
|
|
return $result;
|
|
});
|
|
}
|
|
|
|
private function getSystemCheckTextareaValue(DiagnosticReport $diagnosticReport)
|
|
{
|
|
$view = new \Piwik\View('@Installation/_systemCheckSection');
|
|
$view->diagnosticReport = $diagnosticReport;
|
|
return $view->render();
|
|
}
|
|
|
|
private function checkInstallationIsNotExpired(): void
|
|
{
|
|
$config = Config::getInstance();
|
|
|
|
if (
|
|
empty($config->General['installation_first_accessed'])
|
|
|| !is_numeric($config->General['installation_first_accessed'])
|
|
) {
|
|
$this->setUpInstallationExpiration($config, Date::getNowTimestamp());
|
|
return;
|
|
}
|
|
|
|
$firstAccess = (int) $config->General['installation_first_accessed'];
|
|
$threeDaysAgo = Date::getNowTimestamp() - (3 * 24 * 60 * 60);
|
|
|
|
if ($firstAccess < $threeDaysAgo) {
|
|
Piwik::exitWithErrorMessage(
|
|
Piwik::translate('Installation_ErrorExpired1') .
|
|
"\n<br/>" .
|
|
Piwik::translate('Installation_ErrorExpired2') .
|
|
"\n<ul>" .
|
|
"\n<li>" . Piwik::translate('Installation_ErrorExpired3', ['<strong>', '</strong>']) . '</li>' .
|
|
"\n<li>" . Piwik::translate('Installation_ErrorExpired4', ['<strong>', '</strong>']) . '</li>' .
|
|
"\n<li>" . Piwik::translate('Installation_ErrorExpired5') . '</li>' .
|
|
"\n</ul>" .
|
|
Piwik::translate('Installation_ErrorExpired6') .
|
|
"\n<br/>" .
|
|
Piwik::translate('Installation_ErrorExpired7', [
|
|
'<a href="' . Url::addCampaignParametersToMatomoLink('https://matomo.org/faq/how-to-install/manage-secure-access-to-the-matomo-installer/') . '" rel="noreferrer noopener" target="_blank">',
|
|
'</a>'
|
|
])
|
|
);
|
|
}
|
|
}
|
|
|
|
private function setUpInstallationExpiration(Config $config, int $timestamp): void
|
|
{
|
|
if (
|
|
!empty($config->General['installation_first_accessed'])
|
|
&& is_numeric($config->General['installation_first_accessed'])
|
|
) {
|
|
return;
|
|
}
|
|
|
|
$config->General['installation_first_accessed'] = $timestamp;
|
|
$config->forceSave();
|
|
}
|
|
}
|