Debug['allow_upgrades_to_beta']) { return 'http://builds.piwik.org/piwik-' . $newVersion . '.zip'; } return Config::getInstance()->General['latest_version_url']; } public function newVersionAvailable() { Piwik::checkUserIsSuperUser(); $newVersion = $this->checkNewVersionIsAvailableOrDie(); $view = new View('@CoreUpdater/newVersionAvailable'); $view->piwik_version = Version::VERSION; $view->piwik_new_version = $newVersion; $view->piwik_latest_version_url = self::getLatestZipUrl($newVersion); $view->can_auto_update = Filechecks::canAutoUpdate(); $view->makeWritableCommands = Filechecks::getAutoUpdateMakeWritableMessage(); echo $view->render(); } public function oneClickUpdate() { Piwik::checkUserIsSuperUser(); $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)), array('oneClick_Copy', Piwik_Translate('CoreUpdater_InstallingTheLatestVersion')), 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; } } // this is a magic template to trigger the Piwik_View_Update $view = new OneClickDone(Piwik::getCurrentUserTokenAuth()); $view->coreError = $errorMessage; $view->feedbackMessages = $messages; echo $view->render(); } public function oneClickResults() { Request::reloadAuthUsingTokenAuth($_POST); Piwik::checkUserIsSuperUser(); $view = new View('@CoreUpdater/oneClickResults'); $view->coreError = Common::getRequestVar('error', '', 'string', $_POST); $view->feedbackMessages = safe_unserialize(Common::unsanitizeInputValue(Common::getRequestVar('messages', '', 'string', $_POST))); echo $view->render(); } private function checkNewVersionIsAvailableOrDie() { $newVersion = UpdateCheck::isNewestVersionAvailable(); if (!$newVersion) { throw new Exception(Piwik_TranslateException('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_TranslateException('CoreUpdater_ExceptionArchiveIncompatible', $archive->errorInfo())); } if (0 == count($archive_files)) { throw new Exception(Piwik_TranslateException('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_TranslateException('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_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); if (function_exists('apc_clear_cache')) { apc_clear_cache(); // clear the system (aka 'opcode') cache } } private function oneClick_Finished() { } public function index() { $language = Common::getRequestVar('language', ''); if (!empty($language)) { LanguagesManager::setLanguageForSession($language); } $this->runUpdaterAndExit(); } protected function runUpdaterAndExit() { $updater = new Updater(); $componentsWithUpdateFile = CoreUpdater::getComponentUpdates($updater); if (empty($componentsWithUpdateFile)) { Piwik::redirectToModule('CoreHome'); } 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); $sqlQueries = $updater->getSqlQueriesToExecute(); if (Common::isPhpCliMode()) { $this->doWelcomeUpdates($viewWelcome, $componentsWithUpdateFile); echo $viewWelcome->render(); if (!$this->coreError && Piwik::getModule() == 'CoreUpdater') { $this->doExecuteUpdates($viewDone, $updater, $componentsWithUpdateFile); echo $viewDone->render(); } } else { if (Common::getRequestVar('updateCorePlugins', 0, 'integer') == 1) { $this->warningMessages = array(); $this->doExecuteUpdates($viewDone, $updater, $componentsWithUpdateFile); if (count($sqlQueries) == 1 && !$this->coreError) { Piwik::redirectToModule('CoreHome'); } echo $viewDone->render(); } else { $viewWelcome->queries = $sqlQueries; $viewWelcome->isMajor = $updater->hasMajorDbUpdate(); $this->doWelcomeUpdates($viewWelcome, $componentsWithUpdateFile); echo $viewWelcome->render(); } } exit; } private function doWelcomeUpdates($view, $componentsWithUpdateFile) { $view->new_piwik_version = Version::VERSION; $view->commandUpgradePiwik = "
php " . Filesystem::getPathToPiwikRoot() . "/index.php -- \"module=CoreUpdater\" "; $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 = Piwik_GetOption('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) { $this->loadAndExecuteUpdateFiles($updater, $componentsWithUpdateFile); Filesystem::deleteAllCacheOnUpdate(); $view->coreError = $this->coreError; $view->warningMessages = $this->warningMessages; $view->errorMessages = $this->errorMessages; $view->deactivatedPlugins = $this->deactivatedPlugins; } private function loadAndExecuteUpdateFiles($updater, $componentsWithUpdateFile) { // if error in any core update, show message + help message + EXIT // if errors in any plugins updates, show them on screen, disable plugins that errored + CONTINUE // if warning in any core update or in any plugins update, show message + CONTINUE // if no error or warning, success message + CONTINUE foreach ($componentsWithUpdateFile as $name => $filenames) { try { $this->warningMessages = array_merge($this->warningMessages, $updater->update($name)); } catch (Updater_UpdateErrorException $e) { $this->errorMessages[] = $e->getMessage(); if ($name == 'core') { $this->coreError = true; break; } else { \Piwik\PluginsManager::getInstance()->deactivatePlugin($name); $this->deactivatedPlugins[] = $name; } } } } }