Debug['allow_upgrades_to_beta']) { return 'http://builds.piwik.org/piwik-' . $newVersion . '.zip'; } return Config::getInstance()->General['latest_version_url']; } public function newVersionAvailable() { Piwik::checkUserHasSuperUserAccess(); $newVersion = $this->checkNewVersionIsAvailableOrDie(); $view = new View('@CoreUpdater/newVersionAvailable'); $view->piwik_version = Version::VERSION; $view->piwik_new_version = $newVersion; $incompatiblePlugins = $this->getIncompatiblePlugins($newVersion); $marketplacePlugins = array(); try { if (!empty($incompatiblePlugins)) { $marketplace = new Marketplace(); $marketplacePlugins = $marketplace->getAllAvailablePluginNames(); } } catch (\Exception $e) {} $view->marketplacePlugins = $marketplacePlugins; $view->incompatiblePlugins = $incompatiblePlugins; $view->piwik_latest_version_url = self::getLatestZipUrl($newVersion); $view->can_auto_update = Filechecks::canAutoUpdate(); $view->makeWritableCommands = Filechecks::getAutoUpdateMakeWritableMessage(); return $view->render(); } public function oneClickUpdate() { Piwik::checkUserHasSuperUserAccess(); $this->newVersion = $this->checkNewVersionIsAvailableOrDie(); SettingsServer::setMaxExecutionTime(0); $url = self::getLatestZipUrl($this->newVersion); $steps = array( array('oneClick_Download', Piwik::translate('CoreUpdater_DownloadingUpdateFromX', $url)), array('oneClick_Unpack', Piwik::translate('CoreUpdater_UnpackingTheUpdate')), array('oneClick_Verify', Piwik::translate('CoreUpdater_VerifyingUnpackedFiles')), array('oneClick_CreateConfigFileBackup', Piwik::translate('CoreUpdater_CreatingBackupOfConfigurationFile', self::CONFIG_FILE_BACKUP)) ); $incompatiblePlugins = $this->getIncompatiblePlugins($this->newVersion); if (!empty($incompatiblePlugins)) { $namesToDisable = array(); foreach ($incompatiblePlugins as $incompatiblePlugin) { $namesToDisable[] = $incompatiblePlugin->getPluginName(); } $steps[] = array('oneClick_DisableIncompatiblePlugins', Piwik::translate('CoreUpdater_DisablingIncompatiblePlugins', implode(', ', $namesToDisable))); } $steps[] = array('oneClick_Copy', Piwik::translate('CoreUpdater_InstallingTheLatestVersion')); $steps[] = array('oneClick_Finished', Piwik::translate('CoreUpdater_PiwikUpdatedSuccessfully')); $errorMessage = false; $messages = array(); foreach ($steps as $step) { try { $method = $step[0]; $message = $step[1]; $this->$method(); $messages[] = $message; } catch (Exception $e) { $errorMessage = $e->getMessage(); break; } } $view = new OneClickDone(Piwik::getCurrentUserTokenAuth()); $view->coreError = $errorMessage; $view->feedbackMessages = $messages; return $view->render(); } public function oneClickResults() { $view = new View('@CoreUpdater/oneClickResults'); $view->coreError = Common::getRequestVar('error', '', 'string', $_POST); $view->feedbackMessages = safe_unserialize(Common::unsanitizeInputValue(Common::getRequestVar('messages', '', 'string', $_POST))); return $view->render(); } protected function redirectToDashboardWhenNoError($updater) { if (count($updater->getSqlQueriesToExecute()) == 1 && !$this->coreError && empty($this->warningMessages) && empty($this->errorMessages) && empty($this->deactivatedPlugins) ) { Piwik::redirectToModule('CoreHome'); } } protected static function clearPhpCaches() { if (function_exists('apc_clear_cache')) { apc_clear_cache(); // clear the system (aka 'opcode') cache } if (function_exists('opcache_reset')) { opcache_reset(); // reset the opcode cache (php 5.5.0+) } } private function checkNewVersionIsAvailableOrDie() { $newVersion = UpdateCheck::isNewestVersionAvailable(); if (!$newVersion) { throw new Exception(Piwik::translate('CoreUpdater_ExceptionAlreadyLatestVersion', Version::VERSION)); } return $newVersion; } private function oneClick_Download() { $pathPiwikZip = PIWIK_USER_PATH . self::PATH_TO_EXTRACT_LATEST_VERSION . 'latest.zip'; $this->pathPiwikZip = SettingsPiwik::rewriteTmpPathWithHostname($pathPiwikZip); Filechecks::dieIfDirectoriesNotWritable(array(self::PATH_TO_EXTRACT_LATEST_VERSION)); // we catch exceptions in the caller (i.e., oneClickUpdate) $url = self::getLatestZipUrl($this->newVersion) . '?cb=' . $this->newVersion; Http::fetchRemoteFile($url, $this->pathPiwikZip); } private function oneClick_Unpack() { $pathExtracted = PIWIK_USER_PATH . self::PATH_TO_EXTRACT_LATEST_VERSION; $pathExtracted = SettingsPiwik::rewriteTmpPathWithHostname($pathExtracted); $this->pathRootExtractedPiwik = $pathExtracted . 'piwik'; if (file_exists($this->pathRootExtractedPiwik)) { Filesystem::unlinkRecursive($this->pathRootExtractedPiwik, true); } $archive = Unzip::factory('PclZip', $this->pathPiwikZip); if (0 == ($archive_files = $archive->extract($pathExtracted))) { throw new Exception(Piwik::translate('CoreUpdater_ExceptionArchiveIncompatible', $archive->errorInfo())); } if (0 == count($archive_files)) { throw new Exception(Piwik::translate('CoreUpdater_ExceptionArchiveEmpty')); } unlink($this->pathPiwikZip); } private function oneClick_Verify() { $someExpectedFiles = array( '/config/global.ini.php', '/index.php', '/core/Piwik.php', '/piwik.php', '/plugins/API/API.php' ); foreach ($someExpectedFiles as $file) { if (!is_file($this->pathRootExtractedPiwik . $file)) { throw new Exception(Piwik::translate('CoreUpdater_ExceptionArchiveIncomplete', $file)); } } } private function oneClick_CreateConfigFileBackup() { $configFileBefore = PIWIK_USER_PATH . '/config/global.ini.php'; $configFileAfter = PIWIK_USER_PATH . self::CONFIG_FILE_BACKUP; Filesystem::copy($configFileBefore, $configFileAfter); } private function oneClick_DisableIncompatiblePlugins() { $plugins = $this->getIncompatiblePlugins($this->newVersion); foreach ($plugins as $plugin) { PluginManager::getInstance()->deactivatePlugin($plugin->getPluginName()); } } private function oneClick_Copy() { /* * Make sure the execute bit is set for this shell script */ if (!Rules::isBrowserTriggerEnabled()) { @chmod($this->pathRootExtractedPiwik . '/misc/cron/archive.sh', 0755); } /* * Copy all files to PIWIK_INCLUDE_PATH. * These files are accessed through the dispatcher. */ Filesystem::copyRecursive($this->pathRootExtractedPiwik, PIWIK_INCLUDE_PATH); /* * These files are visible in the web root and are generally * served directly by the web server. May be shared. */ if (PIWIK_INCLUDE_PATH !== PIWIK_DOCUMENT_ROOT) { /* * Copy PHP files that expect to be in the document root */ $specialCases = array( '/index.php', '/piwik.php', '/js/index.php', ); foreach ($specialCases as $file) { Filesystem::copy($this->pathRootExtractedPiwik . $file, PIWIK_DOCUMENT_ROOT . $file); } /* * Copy the non-PHP files (e.g., images, css, javascript) */ Filesystem::copyRecursive($this->pathRootExtractedPiwik, PIWIK_DOCUMENT_ROOT, true); } /* * Config files may be user (account) specific */ if (PIWIK_INCLUDE_PATH !== PIWIK_USER_PATH) { Filesystem::copyRecursive($this->pathRootExtractedPiwik . '/config', PIWIK_USER_PATH . '/config'); } Filesystem::unlinkRecursive($this->pathRootExtractedPiwik, true); self::clearPhpCaches(); } private function oneClick_Finished() { } public function index() { $language = Common::getRequestVar('language', ''); if (!empty($language)) { LanguagesManager::setLanguageForSession($language); } try { return $this->runUpdaterAndExit(); } catch(NoUpdatesFoundException $e) { Piwik::redirectToModule('CoreHome'); } } public function runUpdaterAndExit($doDryRun = null) { $updater = new Updater(); $componentsWithUpdateFile = CoreUpdater::getComponentUpdates($updater); if (empty($componentsWithUpdateFile)) { throw new NoUpdatesFoundException("Everything is already up to date."); } SettingsServer::setMaxExecutionTime(0); $cli = Common::isPhpCliMode() ? '_cli' : ''; $welcomeTemplate = '@CoreUpdater/runUpdaterAndExit_welcome' . $cli; $doneTemplate = '@CoreUpdater/runUpdaterAndExit_done' . $cli; $viewWelcome = new View($welcomeTemplate); $viewDone = new View($doneTemplate); $doExecuteUpdates = Common::getRequestVar('updateCorePlugins', 0, 'integer') == 1; if(is_null($doDryRun)) { $doDryRun = !$doExecuteUpdates; } if($doDryRun) { $viewWelcome->queries = $updater->getSqlQueriesToExecute(); $viewWelcome->isMajor = $updater->hasMajorDbUpdate(); $this->doWelcomeUpdates($viewWelcome, $componentsWithUpdateFile); return $viewWelcome->render(); } // CLI if (Common::isPhpCliMode()) { $this->doWelcomeUpdates($viewWelcome, $componentsWithUpdateFile); $output = $viewWelcome->render(); // Proceed with upgrade in CLI only if user specifically asked for it, or if running console command $isUpdateRequested = Common::isRunningConsoleCommand() || Piwik::getModule() == 'CoreUpdater'; if (!$this->coreError && $isUpdateRequested) { $this->doExecuteUpdates($viewDone, $updater, $componentsWithUpdateFile); $output .= $viewDone->render(); } return $output; } // Web if ($doExecuteUpdates) { $this->warningMessages = array(); $this->doExecuteUpdates($viewDone, $updater, $componentsWithUpdateFile); $this->redirectToDashboardWhenNoError($updater); return $viewDone->render(); } exit; } private function doWelcomeUpdates($view, $componentsWithUpdateFile) { $view->new_piwik_version = Version::VERSION; $view->commandUpgradePiwik = "
php " . Filesystem::getPathToPiwikRoot() . "/console core:update "; $pluginNamesToUpdate = array(); $coreToUpdate = false; // handle case of existing database with no tables if (!DbHelper::isInstalled()) { $this->errorMessages[] = Piwik::translate('CoreUpdater_EmptyDatabaseError', Config::getInstance()->database['dbname']); $this->coreError = true; $currentVersion = 'N/A'; } else { $this->errorMessages = array(); try { $currentVersion = Option::get('version_core'); } catch (Exception $e) { $currentVersion = '<= 0.2.9'; } foreach ($componentsWithUpdateFile as $name => $filenames) { if ($name == 'core') { $coreToUpdate = true; } else { $pluginNamesToUpdate[] = $name; } } } // check file integrity $integrityInfo = Filechecks::getFileIntegrityInformation(); if (isset($integrityInfo[1])) { if ($integrityInfo[0] == false) { $this->warningMessages[] = Piwik::translate('General_FileIntegrityWarningExplanation'); } $this->warningMessages = array_merge($this->warningMessages, array_slice($integrityInfo, 1)); } Filesystem::deleteAllCacheOnUpdate(); $view->coreError = $this->coreError; $view->warningMessages = $this->warningMessages; $view->errorMessages = $this->errorMessages; $view->current_piwik_version = $currentVersion; $view->pluginNamesToUpdate = $pluginNamesToUpdate; $view->coreToUpdate = $coreToUpdate; } private function doExecuteUpdates($view, $updater, $componentsWithUpdateFile) { $result = CoreUpdater::updateComponents($updater, $componentsWithUpdateFile); $this->coreError = $result['coreError']; $this->warningMessages = $result['warnings']; $this->errorMessages = $result['errors']; $this->deactivatedPlugins = $result['deactivatedPlugins']; $view->coreError = $this->coreError; $view->warningMessages = $this->warningMessages; $view->errorMessages = $this->errorMessages; $view->deactivatedPlugins = $this->deactivatedPlugins; } private function getIncompatiblePlugins($piwikVersion) { return PluginManager::getInstance()->getIncompatiblePlugins($piwikVersion); } }