| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| 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; |
|
|
| |
| |
| |
| 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', |
| ); |
|
|
| |
| |
| |
| |
| |
| public function getInstallationSteps() |
| { |
| return $this->steps; |
| } |
|
|
| |
| |
| |
| |
| |
| public function getDefaultAction() |
| { |
| $steps = array_keys($this->steps); |
| return $steps[0]; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function welcome($possibleErrorMessage = null) |
| { |
| |
| Filesystem::deleteAllCacheOnUpdate(); |
|
|
| $this->checkPiwikIsNotInstalled($possibleErrorMessage); |
| $this->checkInstallationIsNotExpired(); |
|
|
| $view = new View( |
| '@Installation/welcome', |
| $this->getInstallationSteps(), |
| __FUNCTION__ |
| ); |
|
|
| $view->showNextStep = true; |
| return $view->render(); |
| } |
|
|
| |
| |
| |
| public function systemCheck() |
| { |
| $this->checkPiwikIsNotInstalled(); |
| $this->deleteConfigFileIfNeeded(); |
| $this->checkInstallationIsNotExpired(); |
|
|
| $view = new View( |
| '@Installation/systemCheck', |
| $this->getInstallationSteps(), |
| __FUNCTION__ |
| ); |
|
|
| |
| |
| $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(); |
|
|
| |
| $view->showNextStepAtTop = $view->showNextStep && !$view->diagnosticReport->hasWarnings(); |
|
|
| return $view->render(); |
| } |
|
|
| |
| |
| |
| |
| 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(); |
| $this->createConfigFile($dbInfos); |
|
|
| DbHelper::checkDatabaseVersion(); |
|
|
| Db::get()->checkClientVersion(); |
|
|
| $this->redirectToNextStep(__FUNCTION__); |
| } catch (Exception $e) { |
| $view->errorMessage = Common::sanitizeInputValue($e->getMessage()); |
| } |
| } |
| $view->addForm($form); |
|
|
| return $view->render(); |
| } |
|
|
| |
| |
| |
| 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) { |
| |
| $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(); |
| } |
|
|
| |
| |
| |
| 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(); |
| } |
|
|
| |
| |
| |
| public function firstWebsiteSetup() |
| { |
| $this->checkPiwikIsNotInstalled(); |
| $this->checkInstallationIsNotExpired(); |
|
|
| ServerFilesGenerator::createFilesForSecurity(); |
|
|
| $siteIdsCount = Access::doAsSuperUser(function () { |
| return count(APISitesManager::getInstance()->getAllSitesId()); |
| }); |
|
|
| if ($siteIdsCount > 0) { |
| |
| $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(); |
| } |
| } |
|
|
| |
| if (count($form->getErrorMessages()) == 0) { |
| $view->displayGeneralSetupSuccess = true; |
| } |
|
|
| $view->addForm($form); |
| return $view->render(); |
| } |
|
|
| |
| |
| |
| 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()); |
|
|
| |
| $emailBody = Access::doAsSuperUser( |
| function () use ($idSite) { |
| return SitesManager::renderTrackingCodeEmail($idSite); |
| } |
| ); |
|
|
| |
| $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(); |
| } |
|
|
| |
| |
| |
| public function finished() |
| { |
| $this->checkPiwikIsNotInstalled(); |
| $this->checkInstallationIsNotExpired(); |
|
|
| $view = new View( |
| '@Installation/finished', |
| $this->getInstallationSteps(), |
| __FUNCTION__ |
| ); |
|
|
| $form = new FormDefaultSettings(); |
|
|
| |
| |
| |
| |
| |
| Piwik::postEvent('Installation.defaultSettingsForm.init', array($form)); |
|
|
| $form->addElement('submit', 'submit', array('value' => Piwik::translate('General_ContinueToPiwik') . ' »', 'class' => 'btn')); |
|
|
| if ($form->validate()) { |
| try { |
| |
| |
| |
| |
| |
| 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; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public function getEmptyPageForSystemCheck() |
| { |
| return 'Hello, world!'; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function systemCheckPage() |
| { |
| Piwik::checkUserHasSuperUserAccess(); |
|
|
| $view = new View( |
| '@Installation/systemCheckPage', |
| $this->getInstallationSteps(), |
| __FUNCTION__ |
| ); |
| $this->setBasicVariablesView($view); |
|
|
| |
| $diagnosticService = StaticContainer::get('Piwik\Plugins\Diagnostics\DiagnosticService'); |
| $view->diagnosticReport = $diagnosticService->runDiagnostics(); |
| $view->systemCheckInfo = $this->getSystemCheckTextareaValue($view->diagnosticReport); |
| return $view->render(); |
| } |
|
|
| |
| |
| |
| public function saveLanguage() |
| { |
| if (DbHelper::isInstalled()) { |
| $this->checkTokenInUrl(); |
| } |
| $language = $this->getParam('language'); |
| LanguagesManager::setLanguageForSession($language); |
| Url::redirectToReferrer(); |
| } |
|
|
| |
| |
| |
| |
| |
| 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); |
| } |
|
|
| |
| |
| |
| |
| |
| 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'); |
| } |
|
|
| |
| |
| |
| private function createConfigFile($dbInfos) |
| { |
| $config = Config::getInstance(); |
|
|
| |
| 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 (count($headers = ProxyHeaders::getProxySchemeHeaders()) > 0) { |
| $config->General['proxy_scheme_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(); |
|
|
| |
| |
| $this->resetLanguageCookie(); |
| } |
|
|
| private function resetLanguageCookie() |
| { |
| |
| $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); |
| } |
|
|
| |
| |
| |
| private function markInstallationAsCompleted() |
| { |
| $config = Config::getInstance(); |
| unset($config->General['installation_in_progress']); |
| unset($config->General['installation_first_accessed']); |
| $config->forceSave(); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| private function redirectToNextStep($currentStep, $parameters = array()) |
| { |
| $steps = array_keys($this->steps); |
| $nextStep = $steps[1 + array_search($currentStep, $steps)]; |
| Piwik::redirectToModule('Installation', $nextStep, $parameters); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| 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; |
| } |
|
|
| |
| |
| |
| private function setTrustedHost(Config $config): void |
| { |
| $host = Url::getHost(false); |
|
|
| |
| 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); |
| }); |
| } |
|
|
| |
| 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); |
|
|
| |
| |
| $this->resetLanguageCookie(); |
| } |
| } |
|
|
| |
| |
| |
| 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', [ |
| Url::getExternalLinkTag('https://matomo.org/faq/how-to-install/manage-secure-access-to-the-matomo-installer/'), |
| '</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(); |
| } |
| } |
|
|