public function testCopy() { $handler = new UpdateHelper($this->application); $tmpName = 'test-update-copy' . rand(1, 5000000); $tmp = ClassLoader::getRealPath('cache.') . $tmpName; file_put_contents($tmp, 'test'); $res = $handler->copyFile($tmp, 'module/' . $tmpName); $expected = ClassLoader::getRealPath('module.') . $tmpName; if (file_exists($expected)) { $response = new JSONResponse(array(), 'success', $this->translate('_test_copy_success')); } else { $response = new JSONResponse(array(), 'failure', $this->translate('_test_copy_failure')); } $handler->deleteFile('module/' . $tmp); unlink($tmp); return $response; }
/** * @param $manifestData * @param $sourceTempFolder * @param $handle * * @return bool */ public static function doFileUpdate($manifestData, $sourceTempFolder, $handle) { if ($handle == 'craft') { $destDirectory = craft()->path->getAppPath(); $sourceFileDirectory = 'app/'; } else { $destDirectory = craft()->path->getPluginsPath() . $handle . '/'; $sourceFileDirectory = ''; } try { foreach ($manifestData as $row) { if (static::isManifestVersionInfoLine($row)) { continue; } $folder = false; $rowData = explode(';', $row); if (static::isManifestLineAFolder($rowData[0])) { $folder = true; $tempPath = static::cleanManifestFolderLine($rowData[0]); } else { $tempPath = $rowData[0]; } $destFile = IOHelper::normalizePathSeparators($destDirectory . $tempPath); $sourceFile = IOHelper::getRealPath(IOHelper::normalizePathSeparators($sourceTempFolder . '/' . $sourceFileDirectory . $tempPath)); switch (trim($rowData[1])) { // update the file case PatchManifestFileAction::Add: if ($folder) { Craft::log('Updating folder: ' . $destFile, LogLevel::Info, true); $tempFolder = rtrim($destFile, '/') . StringHelper::UUID() . '/'; $tempTempFolder = rtrim($destFile, '/') . '-tmp/'; IOHelper::createFolder($tempFolder); IOHelper::copyFolder($sourceFile, $tempFolder); IOHelper::rename($destFile, $tempTempFolder); IOHelper::rename($tempFolder, $destFile); IOHelper::clearFolder($tempTempFolder); IOHelper::deleteFolder($tempTempFolder); } else { Craft::log('Updating file: ' . $destFile, LogLevel::Info, true); IOHelper::copyFile($sourceFile, $destFile); } break; } } } catch (\Exception $e) { Craft::log('Error updating files: ' . $e->getMessage(), LogLevel::Error); UpdateHelper::rollBackFileChanges($manifestData, $handle); return false; } return true; }
/** * Performs maintenance and clean up tasks after an update. * * Called during both a manual and auto-update. * * @return null */ public function actionCleanUp() { $this->requirePostRequest(); $this->requireAjaxRequest(); $data = craft()->request->getRequiredPost('data'); if ($this->_isManualUpdate($data)) { $uid = false; } else { // If it's not a manual update, make sure they have auto-update permissions. craft()->userSession->requirePermission('performUpdates'); if (!craft()->config->get('allowAutoUpdates')) { $this->returnJson(array('alive' => true, 'errorDetails' => Craft::t('Auto-updating is disabled on this system.'), 'finished' => true)); } $uid = $data['uid']; } $handle = $this->_getFixedHandle($data); $oldVersion = false; // Grab the old version from the manifest data before we nuke it. $manifestData = UpdateHelper::getManifestData(UpdateHelper::getUnzipFolderFromUID($uid)); if ($manifestData) { $oldVersion = UpdateHelper::getLocalVersionFromManifest($manifestData); } craft()->updates->updateCleanUp($uid, $handle); if ($oldVersion && version_compare($oldVersion, craft()->getVersion(), '<')) { $returnUrl = UrlHelper::getUrl('whats-new'); } else { $returnUrl = craft()->userSession->getReturnUrl(); } $this->returnJson(array('alive' => true, 'finished' => true, 'returnUrl' => $returnUrl)); }
/** * @param $uid * @param bool $dbBackupPath * @return array */ public function rollbackUpdate($uid, $dbBackupPath = false) { try { craft()->config->maxPowerCaptain(); if ($dbBackupPath && craft()->config->get('backupDbOnUpdate') && craft()->config->get('restoreDbOnUpdateFailure')) { Craft::log('Rolling back any database changes.', LogLevel::Info, true); UpdateHelper::rollBackDatabaseChanges($dbBackupPath); Craft::log('Done rolling back any database changes.', LogLevel::Info, true); } // If uid !== false, it's an auto-update. if ($uid !== false) { Craft::log('Rolling back any file changes.', LogLevel::Info, true); $manifestData = UpdateHelper::getManifestData(UpdateHelper::getUnzipFolderFromUID($uid)); if ($manifestData) { UpdateHelper::rollBackFileChanges($manifestData); } Craft::log('Done rolling back any file changes.', LogLevel::Info, true); } Craft::log('Finished rolling back changes.', LogLevel::Info, true); return array('success' => true); } catch (\Exception $e) { return array('success' => false, 'message' => $e->getMessage()); } }
<?php define('DIRECT_ACCESS_CHECK', true); define('BASE_PATH', '../../'); require_once '../updatehelper.php'; require_once BASE_PATH . 'includes/reporthelper.class.php'; $mUpdateHelper = new UpdateHelper(); $mUpdateHelper->begin(); $mUpdateHelper->applySQLUpdateFile(); $mUpdateHelper->exitOnError(); $mUpdateHelper->printStartNextStepMsg("Start updating issues table"); $succeeded = true; $packages = DbHelper::selectRows(TBL_REPORTS, null, REPORT_PACKAGE_NAME, REPORT_ISSUE . ', ' . REPORT_PACKAGE_NAME, REPORT_ISSUE, null, false); foreach ($packages as $package) { $issueId = $package[0]; $packageName = $package[1]; // skip empty package name if (strlen($packageName) == 0) { $mUpdateHelper->printStepMsg("Found empty package name !", true, false); continue; } $appId = DbHelper::fetchOrInsertApplication($packageName, ReportHelper::formatPackageName($packageName, true)); if ($appId == -1) { $succeeded = false; } $mUpdateHelper->printStepMsg("Inserted application " . $packageName . ", id is " . $appId, $appId == -1, false); $mUpdateHelper->printStepMsg('Update issued #' . $issueId . ' with application id #' . $appId, false, false); DbHelper::exec('UPDATE ' . TBL_ISSUES . ' SET ' . ISSUE_APP_ID . '=' . $appId . ' WHERE ' . ISSUE_ID . '=' . $issueId, false); } $mUpdateHelper->printEndStepMsg($succeeded, null, false); $mUpdateHelper->printEndStepMsg(true, null, true);
/** * @param string $uid * @param string $handle * @param bool $dbBackupPath * * @return array */ public function rollbackUpdate($uid, $handle, $dbBackupPath = false) { try { // Fire an 'onEndUpdate' event and pass in that the update failed. $this->onEndUpdate(new Event($this, array('success' => false))); craft()->config->maxPowerCaptain(); if ($dbBackupPath && craft()->config->get('backupDbOnUpdate') && craft()->config->get('restoreDbOnUpdateFailure')) { Craft::log('Rolling back any database changes.', LogLevel::Info, true); UpdateHelper::rollBackDatabaseChanges($dbBackupPath); Craft::log('Done rolling back any database changes.', LogLevel::Info, true); } // If uid !== false, it's an auto-update. if ($uid !== false) { Craft::log('Rolling back any file changes.', LogLevel::Info, true); $manifestData = UpdateHelper::getManifestData(UpdateHelper::getUnzipFolderFromUID($uid), $handle); if ($manifestData) { UpdateHelper::rollBackFileChanges($manifestData, $handle); } Craft::log('Done rolling back any file changes.', LogLevel::Info, true); } Craft::log('Finished rolling back changes.', LogLevel::Info, true); Craft::log('Taking the site out of maintenance mode.', LogLevel::Info, true); craft()->disableMaintenanceMode(); return array('success' => true); } catch (\Exception $e) { return array('success' => false, 'message' => $e->getMessage()); } }
<?php define('DIRECT_ACCESS_CHECK', true); define('BASE_PATH', '../../'); define('_REPORT_ID', 0); define('_APP_VERSION_CODE', 1); define('_APP_VERSION_NAME', 2); define('_PACKAGE_NAME', 3); define('_STACK_TRACE', 4); define('_REPORT_STATE', 5); define('_CRASH_DATE', 6); require_once '../updatehelper.php'; $mUpdateHelper = new UpdateHelper(); $mUpdateHelper->begin(); $mUpdateHelper->applySQLUpdateFile(); $mUpdateHelper->exitOnError(); $mUpdateHelper->printStartNextStepMsg('Populate increments table'); // populate table increments for ($i = 0; $i <= 180; ++$i) { $mUpdateHelper->execSQL('INSERT INTO ' . DBHelper::getTblName(TBL_INCREMENTS) . '(' . INC_VALUE . ') VALUES (' . $i . ');'); } // recreate issue keys with new algorithm $mUpdateHelper->printStartNextStepMsg('Get reports'); $reports = DBHelper::selectRows(TBL_REPORTS, null, null, 'report_id, app_version_code, app_version_name, package_name, stack_trace, report_state, user_crash_date', null, null, false); $mUpdateHelper->printStartNextStepMsg('Walk through reports array to create issues'); $issues = array(); try { foreach ($reports as $report) { $arr = explode("\n", $report[_STACK_TRACE]); $cause = $arr[0]; // create a key to identify the issue from all reports
/** * Performs maintenance and clean up tasks after an update. * * Called during both a manual and auto-update. * * @return null * @throws Exception */ public function actionCleanUp() { $this->requirePostRequest(); $this->requireAjaxRequest(); $data = craft()->request->getRequiredPost('data'); if ($this->_isManualUpdate($data)) { $uid = false; } else { $uid = craft()->security->validateData($data['uid']); if (!$uid) { throw new Exception('Could not validate UID'); } } $handle = $this->_getFixedHandle($data); $oldVersion = false; // Grab the old version from the manifest data before we nuke it. $manifestData = UpdateHelper::getManifestData(UpdateHelper::getUnzipFolderFromUID($uid), $handle); if ($manifestData && $handle == 'craft') { $oldVersion = UpdateHelper::getLocalVersionFromManifest($manifestData); } craft()->updates->updateCleanUp($uid, $handle); // New major Craft CMS version? if ($handle == 'craft' && $oldVersion && AppHelper::getMajorVersion($oldVersion) < AppHelper::getMajorVersion(craft()->getVersion())) { $returnUrl = UrlHelper::getUrl('whats-new'); } else { $returnUrl = craft()->config->get('postCpLoginRedirect'); } $this->returnJson(array('alive' => true, 'finished' => true, 'returnUrl' => $returnUrl)); }
if (ViewHelper::$mod_rewrite && strlen($requestUrl) > 1 && substr($requestUrl, -1) != '/') { header('HTTP/1.1 301 Moved Permanently'); header('Location: /' . BASE_PATH . $requestUrl . '/'); exit; } // strip any leading/trailing slashes $requestUrl = trim($requestUrl, '/'); } // if mod_rewrite is available and we're on a legacy url, redirect to the new, nicer one if (ViewHelper::$mod_rewrite && isset($_GET['p'])) { header('HTTP/1.1 301 Moved Permanently'); header('Location: /' . BASE_PATH . $requestUrl); exit; } // checks for new updates and installs them if updates are enabled if (UpdateHelper::check()) { // if it did install updates, redirects to this page again to make sure nothing gets broken as files are changed header('Location: /' . BASE_PATH . '/' . $requestUrl . '?updated=1'); exit; } ob_start(); if (!ErrorHelper::hasErrors()) { $presskit = new PresskitController(); } if (!ErrorHelper::hasErrors()) { if (isset($_POST['email'])) { $presskit->email($requestUrl); } else { if ($requestUrl == '') { $presskit->index(); } else {
/** * Performs maintenance and clean up tasks after an update. */ public function actionCleanUp() { $this->requirePostRequest(); $this->requireAjaxRequest(); $data = craft()->request->getRequiredPost('data'); if ($this->_isManualUpdate($data)) { $uid = false; } else { // If it's not a manual update, make sure they have auto-update permissions. craft()->userSession->requirePermission('performUpdates'); $uid = $data['uid']; } $handle = $this->_getFixedHandle($data); $oldVersion = false; // Grab the old version from the manifest data before we nuke it. $manifestData = UpdateHelper::getManifestData(UpdateHelper::getUnzipFolderFromUID($uid)); if ($manifestData) { $oldVersion = UpdateHelper::getLocalVersionFromManifest($manifestData); } $return = craft()->updates->updateCleanUp($uid, $handle); if (!$return['success']) { $this->returnJson(array('error' => $return['message'])); } if ($oldVersion && version_compare($oldVersion, '1.1', '<')) { $returnUrl = UrlHelper::getUrl('whats-new'); } else { $returnUrl = craft()->userSession->getReturnUrl(); } $this->returnJson(array('success' => true, 'finished' => true, 'returnUrl' => $returnUrl)); }
public function fetch() { require_once ClassLoader::getRealPath('library.pclzip') . '/pclzip.lib.php'; $id = unserialize(base64_decode($this->request->get('module'))); $repos = json_decode(base64_decode($this->request->get('repos')), true); $repo = $repos[$id[0]]; $this->request->set('repo', $repo['repo']); $this->request->set('handshake', $repo['handshake']); $this->request->set('id', $id[1]); $tmpFile = ClassLoader::getRealPath('cache.') . 'install' . rand(1, 5000000) . '.zip'; file_put_contents($tmpFile, $this->getRepoResponse('package/downloadInstall', array(), true)); if (!filesize($tmpFile)) { return new JSONResponse(array('error' => $this->translate('_err_download_package'))); } $tmpDir = substr($tmpFile, 0, -4); mkdir($tmpDir); $archive = new PclZip($tmpFile); $archive->extract($tmpDir); unlink($tmpFile); $update = new UpdateHelper($this->application); $moduleDir = ClassLoader::getRealPath('module.' . $id[1]); $copy = $update->copyDirectory($tmpDir, $moduleDir); if ($copy !== true) { return new JSONResponse(array('error' => $this->maketext('_err_update_copy_msg', array($copy)))); } $this->application->getConfigContainer()->addModule('module.' . $id[1]); $module = $this->application->getConfigContainer()->getModule('module.' . $id[1]); $module->install($this->application); $module->setStatus(true); $this->request->set('id', 'module.' . $id[1]); return $this->node(); }
<?php define('DIRECT_ACCESS_CHECK', true); define('BASE_PATH', '../'); require_once 'updatehelper.php'; $mUpdateHelper = new UpdateHelper(); $mUpdateHelper->begin(); $mUpdateHelper->applySQLUpdateFile('db-install.sql'); $mUpdateHelper->exitOnError(); $mUpdateHelper->printStartNextStepMsg('Populate increments table'); // populate table increments for ($i = 0; $i <= 180; ++$i) { $mUpdateHelper->execSQL('INSERT INTO ' . TBL_INCREMENTS . '(' . INC_VALUE . ') VALUES (' . $i . ');'); } $mUpdateHelper->printEndStepMsg(true, null, true); $mUpdateHelper->end();
<?php define('DIRECT_ACCESS_CHECK', true); define('BASE_PATH', '../../'); require_once '../updatehelper.php'; require_once BASE_PATH . 'includes/reporthelper.class.php'; $mUpdateHelper = new UpdateHelper(); $mUpdateHelper->begin(); $mUpdateHelper->applySQLUpdateFile(); $mUpdateHelper->exitOnError(); $mUpdateHelper->printEndStepMsg(true, null, true); $mUpdateHelper->end();
/** * Performs maintenance and clean up tasks after an update. * * Called during both a manual and auto-update. * * @return null */ public function actionCleanUp() { $this->requirePostRequest(); $this->requireAjaxRequest(); $data = craft()->request->getRequiredPost('data'); if ($this->_isManualUpdate($data)) { $uid = false; } else { $uid = $data['uid']; } $handle = $this->_getFixedHandle($data); $oldVersion = false; // Grab the old version from the manifest data before we nuke it. $manifestData = UpdateHelper::getManifestData(UpdateHelper::getUnzipFolderFromUID($uid), $handle); if ($manifestData && $handle == 'craft') { $oldVersion = UpdateHelper::getLocalVersionFromManifest($manifestData); } craft()->updates->updateCleanUp($uid, $handle); if ($handle == 'craft' && $oldVersion && version_compare($oldVersion, craft()->getVersion(), '<')) { $returnUrl = UrlHelper::getUrl('whats-new'); } else { $returnUrl = craft()->config->get('postCpLoginRedirect'); } $this->returnJson(array('alive' => true, 'finished' => true, 'returnUrl' => $returnUrl)); }
public function applyUpdate($dir) { $update = new UpdateHelper($this->application); $copy = $update->copyDirectory($dir, $this->directory); if ($copy !== true) { return array(self::ERR_COPY, $copy); } // import SQL foreach (glob($dir . '/update/*/*.sql') as $file) { try { $this->loadSQL($file); } catch (Exception $e) { return array(self::ERR_DB, $e->getMessage()); } } // custom scripts $this->application->getConfigContainer()->clearCache(); return true; }
/** * Attempt to backup each of the update manifest files by copying them to a file with the same name with a .bak * extension. If there is an exception thrown, we attempt to roll back all of the changes. * * @param string $unzipFolder * @param string $handle * * @return bool */ private function _backupFiles($unzipFolder, $handle) { $manifestData = UpdateHelper::getManifestData($unzipFolder, $handle); try { foreach ($manifestData as $row) { if (UpdateHelper::isManifestVersionInfoLine($row)) { continue; } // No need to back up migration files. if (UpdateHelper::isManifestMigrationLine($row)) { continue; } $rowData = explode(';', $row); $filePath = IOHelper::normalizePathSeparators(($handle == 'craft' ? craft()->path->getAppPath() : craft()->path->getPluginsPath() . $handle . '/') . $rowData[0]); // It's a folder if (UpdateHelper::isManifestLineAFolder($filePath)) { $folderPath = UpdateHelper::cleanManifestFolderLine($filePath); if (IOHelper::folderExists($folderPath)) { Craft::log('Backing up folder ' . $folderPath, LogLevel::Info, true); IOHelper::createFolder($folderPath . '.bak'); IOHelper::copyFolder($folderPath . '/', $folderPath . '.bak/'); } } else { // If the file doesn't exist, it's probably a new file. if (IOHelper::fileExists($filePath)) { Craft::log('Backing up file ' . $filePath, LogLevel::Info, true); IOHelper::copyFile($filePath, $filePath . '.bak'); } } } } catch (\Exception $e) { Craft::log('Error updating files: ' . $e->getMessage(), LogLevel::Error); UpdateHelper::rollBackFileChanges($manifestData, $handle); return false; } return true; }
private static function getUpdateIterator($childFirst) { // deleting needs to be child first, copying self first $mode = $childFirst ? RecursiveIteratorIterator::CHILD_FIRST : RecursiveIteratorIterator::SELF_FIRST; return new RecursiveIteratorIterator(new RecursiveDirectoryIterator(UpdateHelper::getTempPath(), RecursiveDirectoryIterator::SKIP_DOTS), $mode); }