/** * Create an archive of the project. */ public function showBundle() { $this->addMainMenu(); $this->addMessage('You can install this bundle using <a href="' . url('', array('module', 'view' => 'InstallScript')) . '">this installation script</a>.', self::MSG_NOTICE, false); $form = new Curry_Form(array('action' => url('', array("module", "view")), 'method' => 'post', 'elements' => array('project' => array('checkbox', array('label' => 'Project', 'value' => true)), 'www' => array('checkbox', array('label' => 'WWW folder', 'value' => true)), 'base' => array('checkbox', array('label' => 'Curry Core', 'value' => true)), 'database' => array('checkbox', array('label' => 'Database', 'value' => true)), 'compression' => array('select', array('label' => 'Compression', 'multiOptions' => array(Curry_Archive::COMPRESSION_NONE => 'None', Curry_Archive::COMPRESSION_GZ => 'Gzip'))), 'save' => array('submit', array('label' => 'Create bundle'))))); if (isPost() && $form->isValid($_POST)) { // create archive @set_time_limit(0); $compression = $form->compression->getValue(); $tar = new Curry_Archive('', $compression); // set up file list $options = array(array('pattern' => '*.svn*', 'pattern_subject' => 'path', 'skip' => true), array('pattern' => '*.git*', 'pattern_subject' => 'path', 'skip' => true), array('pattern' => '.DS_Store', 'skip' => true), array('pattern' => 'Thumbs.db', 'skip' => true), array('pattern' => '._*', 'skip' => true)); if ($form->project->isChecked()) { $tar->add(Curry_Core::$config->curry->projectPath, 'cms/', array_merge($options, array(array('path' => 'data/', 'pattern' => 'data/*/*', 'pattern_subject' => 'path', 'skip' => true)))); } if ($form->www->isChecked()) { $tar->add(Curry_Core::$config->curry->wwwPath, 'www/', array_merge($options, array(array('path' => 'shared', 'skip' => true), array('path' => 'shared/', 'skip' => true)))); } if ($form->base->isChecked()) { $sharedPath = realpath(Curry_Core::$config->curry->wwwPath . '/shared'); if ($sharedPath) { $tar->add($sharedPath, 'www/shared/', $options); } $tar->add(Curry_Core::$config->curry->basePath . '/include', 'curry/include/', $options); $tar->add(Curry_Core::$config->curry->basePath . '/propel', 'curry/propel/', $options); $tar->add(Curry_Core::$config->curry->basePath . '/vendor', 'curry/vendor/', $options); $tar->add(Curry_Core::$config->curry->basePath . '/.htaccess', 'curry/', $options); } if ($form->database->isChecked()) { $fiveMBs = 5 * 1024 * 1024; $fp = fopen("php://temp/maxmemory:{$fiveMBs}", 'r+'); if (!Curry_Backend_DatabaseHelper::dumpDatabase($fp)) { throw new Exception('Aborting: There was an error when dumping the database.'); } fseek($fp, 0); $tar->addString('db.txt', stream_get_contents($fp)); fclose($fp); } $filename = str_replace(" ", "_", Curry_Core::$config->curry->name) . "-bundle-" . date("Ymd") . ".tar" . ($compression ? ".{$compression}" : ''); header("Content-type: " . Curry_Archive::getCompressionMimeType($compression)); header("Content-disposition: attachment; filename=" . Curry_String::escapeQuotedString($filename)); // do not use output buffering while (ob_end_clean()) { } $tar->stream(); exit; } $this->addMainContent($form); }
/** * Show view to unpack bundle. */ protected static function showUnpack() { echo '<div id="unpack">'; echo '<h2>Select bundle</h2>'; $bundles = glob('*.tar'); if ($bundles === false) { if (!is_readable('bundle.tar')) { echo '<div class="error"><p>Failed to scan directory for bundle files, please name the file bundle.tar for successful detection.</p></div>'; } $bundles = array('bundle.tar'); } if (!count($bundles)) { echo '<p>Please upload your bundle file to the same folder as this script (install.php). You should then be able to select your bundle for unpacking if you reload the page.</p>'; } else { if (!isset($_POST['bundle'])) { echo '<p>The selected bundle will be unpacked to this directory, no files will be overwritten.'; echo '<form action="" method="POST">'; $options = ''; foreach ($bundles as $bundle) { $options .= '<option value="' . htmlspecialchars($bundle) . '">' . htmlspecialchars($bundle) . '</option>'; } echo '<select name="bundle">' . $options . '</select><br/>'; echo '<input class="button unpack-button" type="submit" name="unpack" value="Unpack" /><br/>'; echo '</form>'; } else { echo "<p>Extracting files...</p>"; $bundle = $_POST['bundle']; if (!in_array($bundle, $bundles)) { echo '<div class="error"><p>Invalid bundle name.</p></div>'; return; } @set_time_limit(300); $symlinkFallback = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' || !function_exists('symlink'); $symlinks = array(); $tar = new Curry_Archive($bundle); $tar->extract(array(array('callback' => function ($file, $options) use(&$symlinks, $symlinkFallback) { if ($file->isLink() && $symlinkFallback) { $symlinks[] = $file; return false; } return true; }, 'overwrite' => function ($file, $options) { echo "Warning, file {$file->getPathname()} already exists, skipping<br />"; return false; }), array('path' => 'www/', 'target' => './'))); self::fixSymlinks($symlinks); echo '<div class="success"><p>Bundle unpacked successfully.</p></div>'; $success = self::writeInit(); $success = self::writeConfig() && $success; if ($success) { echo '<div class="success"><p>Curry configuration written.</p></div>'; } echo '<p><a href="admin.php">Continue setup</a>.</p>'; } } echo '</div>'; }
/** * Create iterator instance. * * @param Curry_Archive $archive * @param array $options */ public function __construct(Curry_Archive $archive, $options = array()) { parent::__construct($archive->getFilename(), $archive->getCompression()); $this->options = $options; }
/** * Upgrade package. * * @param string $name * @param bool $simulate * @return bool */ public static function upgradePackage($name, $simulate = false) { $package = Curry_PackageManager::getPackage($name); if (!$package) { return false; } $installedPackage = PackageQuery::create()->findPk($name); if (!$installedPackage) { return false; } $oldPackage = Curry_PackageManager::getPackage($installedPackage->getName(), $installedPackage->getVersion()); if (!$oldPackage) { return false; } // make sure we are trying to install a newer package if (version_compare($package['version'], $installedPackage->getVersion()) <= 0) { return false; } // run preUpgrade task if (!$simulate && !self::execTask($package, 'preUpgrade', true, array('fromVersion' => $installedPackage->getVersion(), 'toVersion' => $package['version']))) { return false; } $diff = '/usr/bin/diff'; $patch = '/usr/bin/patch'; $installedFiles = Curry_Array::objectsToArray($installedPackage->getPackageFiles(), 'getFilename'); $tar = new Curry_Archive($package['source']); $oldTar = new Curry_Archive($oldPackage['source']); $tempFile = tempnam('/tmp', 'curry'); foreach ($tar as $tarFile) { $file = $tarFile->getPathname(); try { $target = PackageFile::mapFile($file); } catch (Exception $e) { self::log('Skipping: ' . $file); continue; } // create directory if ($tarFile->isDir()) { if (!$simulate) { if (!file_exists($target)) { mkdir($target, 0777, true); } } continue; } // file is already installed? if (array_key_exists($file, $installedFiles)) { $packageFile = $installedFiles[$file]; unset($installedFiles[$file]); // do not remove this file // read checksum of new file if ($tarFile->getSize() > 102400) { $tarFile->extract($tempFile); $newChecksum = sha1_file($tempFile); } else { $newChecksum = sha1($tarFile->getContents()); } if (!file_exists($target)) { // Installed file is missing self::log('Re-installing: ' . $file, Curry_Backend::MSG_WARNING); if (!$simulate) { $tarFile->extract($target); $packageFile->setChecksum($newChecksum); $packageFile->save(); } } else { if ($packageFile->getChecksum() == $newChecksum) { // File hasnt changed in package, so skip it self::log('Unchanged: ' . $file); } else { if ($packageFile->fileIsModified()) { // Installed file was modified self::log('Updating modified: ' . $file, Curry_Backend::MSG_SUCCESS); if (!$simulate) { $backupFile = $packageFile->backup(); $tarFile->extract($target); $packageFile->setChecksum($newChecksum); $packageFile->save(); // Diff $oldTar->getFile($file)->extract($tempFile); $command = $diff . ' -u ' . escapeshellarg($tempFile) . ' ' . escapeshellarg($backupFile); $p = `{$command}`; // Patch file file_put_contents($tempFile, $p); $command = $patch . ' ' . escapeshellarg($target) . ' ' . escapeshellarg($tempFile); $d = `{$command}`; } } else { // file is not modified so we should be able to just delete it and install the new one self::log('Updating: ' . $file); if (!$simulate) { unlink($target); $tarFile->extract($target); $packageFile->setChecksum(sha1_file($target)); $packageFile->save(); } } } } } else { self::log('Adding: ' . $file, Curry_Backend::MSG_SUCCESS); if (!$simulate) { if (file_exists($target)) { // backup file before overwriting $backupTarget = $target . "." . date("Ymd_His"); if (file_exists($backupTarget)) { throw new Exception('Unable to backup existing file.'); } rename($target, $backupTarget); } $tarFile->extract($target); $packageFile = new PackageFile(); $packageFile->setPackage($installedPackage); $packageFile->setFilename($file); $packageFile->setChecksum(sha1_file($target)); $packageFile->save(); } } } // remove remaining files in $installedFiles foreach ($installedFiles as $installedFile) { self::log('Remove: ' . $installedFile->getFilename(), Curry_Backend::MSG_WARNING); if (!$simulate) { if (!$installedFile->fileIsModified()) { $installedFile->backup(); } else { unlink($installedFile->getRealpath()); } $installedFile->delete(); } } if (!$simulate) { $installedPackage->setVersion($package['version']); $installedPackage->save(); } if (!$simulate) { self::execTaskWithReload($package, 'postUpgrade', true, array('fromVersion' => $installedPackage->getVersion(), 'toVersion' => $package['version'])); } self::$installed = null; return true; }
/** * Read an entry from the archive and return a Curry_Archive_FileInfo. * Null will be returned on read-errors or EOF. * * @param array $options * @return Curry_Archive_FileInfo|null */ protected function readEntry($options) { if ($this->nextPos) { $position = $this->call('tell', $this->file); if ($position !== $this->nextPos) { $this->call('seek', $this->file, $this->nextPos); } $this->nextPos = null; } while (strlen($data = $this->readBlock()) != 0) { $header = $this->readHeader($data); if (!$header) { return null; } if ($header['filename'] == '') { continue; } $fileOptions = Curry_Archive::getPathOptions($header['filename'], $options); $position = $this->call('tell', $this->file); $this->nextPos = $position + ceil($header['size'] / 512) * 512; if ($fileOptions['skip']) { $this->call('seek', $this->file, $this->nextPos); continue; } $type = Curry_Archive_FileInfo::TYPE_FILE; if ($header['typeflag'] == '5') { $type = Curry_Archive_FileInfo::TYPE_DIR; } else { if ($header['typeflag'] == '2') { $type = Curry_Archive_FileInfo::TYPE_LINK; } } return new Curry_Archive_FileInfo($header['filename'], $type, $header['size'], $header['mtime'], $header['link'], $header['mode'], $header['uid'], $header['gid'], $this, $position, $fileOptions); } return null; }