/** * Sends the given file by whatever method is appropriate. Uses php's * header() instead of silverstripe's HTTPResponse class to prevent other * headers from being added and so we can just use readfile() instead of * pulling the whole file into a string for setBody(). * * @param File $file */ protected function sendFile(File $file) { // this is for optional compatibility with markguinn/silverstripe-cloudassets if ($file->hasExtension('CloudFileExtension') && $file->CloudStatus === 'Live') { header('Location: ' . $file->getAbsoluteURL()); exit; } // this is the normal way to send the files header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . $file->Name . '"'); if (Config::inst()->get('Downloadable', 'use_xsendfile')) { header('X-Sendfile: ' . $file->getURL()); } else { header('Content-Length: ' . $file->getAbsoluteSize()); readfile($file->getFullPath()); } exit; }
/** * Completes the job by zipping up the generated export and creating an * export record for it. */ protected function complete() { $siteTitle = SiteConfig::current_site_config()->Title; $filename = preg_replace('/[^a-zA-Z0-9-.+]/', '-', sprintf('%s-%s.zip', $siteTitle, date('c'))); $dir = Folder::findOrMake(SiteExportExtension::EXPORTS_DIR); $dirname = ASSETS_PATH . '/' . SiteExportExtension::EXPORTS_DIR; $pathname = "{$dirname}/{$filename}"; SiteExportUtils::zip_directory($this->tempDir, "{$dirname}/{$filename}"); Filesystem::removeFolder($this->tempDir); $file = new File(); $file->ParentID = $dir->ID; $file->Title = $siteTitle . ' ' . date('c'); $file->Filename = $dir->Filename . $filename; $file->write(); $export = new SiteExport(); $export->ParentClass = $this->rootClass; $export->ParentID = $this->rootId; $export->Theme = $this->theme; $export->BaseUrlType = ucfirst($this->baseUrlType); $export->BaseUrl = $this->baseUrl; $export->ArchiveID = $file->ID; $export->write(); if ($this->email) { $email = new Email(); $email->setTo($this->email); $email->setTemplate('SiteExportCompleteEmail'); $email->setSubject(sprintf('Site Export For "%s" Complete', $siteTitle)); $email->populateTemplate(array('SiteTitle' => $siteTitle, 'Link' => $file->getAbsoluteURL())); $email->send(); } }
/** * Backs up database and/or assets to a designated folder, * and packs up the files into a single sspak. * * @param DNDataTransfer $dataTransfer * @param DeploynautLogFile $log */ protected function dataTransferBackup(DNDataTransfer $dataTransfer, DeploynautLogFile $log) { $environmentObj = $dataTransfer->Environment(); $project = $environmentObj->Project(); $projectName = $project->Name; $environmentName = $environmentObj->Name; $env = $project->getProcessEnv(); $project = DNProject::get()->filter('Name', $projectName)->first(); $name = $projectName . ':' . $environmentName; // Associate a new archive with the transfer. // Doesn't retrieve a filepath just yet, need to generate the files first. $dataArchive = DNDataArchive::create(); $dataArchive->Mode = $dataTransfer->Mode; $dataArchive->AuthorID = $dataTransfer->AuthorID; $dataArchive->OriginalEnvironmentID = $dataTransfer->Environment()->ID; $dataArchive->EnvironmentID = $dataTransfer->Environment()->ID; $dataArchive->IsBackup = $dataTransfer->IsBackupDataTransfer(); // Generate directory structure with strict permissions (contains very sensitive data) $filepathBase = $dataArchive->generateFilepath($dataTransfer); mkdir($filepathBase, 0700, true); $databasePath = $filepathBase . DIRECTORY_SEPARATOR . 'database.sql'; // Backup database if (in_array($dataTransfer->Mode, array('all', 'db'))) { $log->write('Backup of database from "' . $name . '" started'); $args = array('data_path' => $databasePath); $command = $this->getCommand("data:getdb", 'db', $name, $args, $env, $log); $command->run(function ($type, $buffer) use($log) { $log->write($buffer); }); if (!$command->isSuccessful()) { throw new RuntimeException($command->getErrorOutput()); } $log->write('Backup of database from "' . $name . '" done'); } // Backup assets if (in_array($dataTransfer->Mode, array('all', 'assets'))) { $log->write('Backup of assets from "' . $name . '" started'); $args = array('data_path' => $filepathBase); $command = $this->getCommand("data:getassets", 'web', $name, $args, $env, $log); $command->run(function ($type, $buffer) use($log) { $log->write($buffer); }); if (!$command->isSuccessful()) { throw new RuntimeException($command->getErrorOutput()); } $log->write('Backup of assets from "' . $name . '" done'); } $log->write('Creating *.sspak file'); $sspakFilename = sprintf('%s.sspak', $dataArchive->generateFilename($dataTransfer)); $sspakCmd = sprintf('cd %s && sspak saveexisting %s 2>&1', $filepathBase, $sspakFilename); if ($dataTransfer->Mode == 'db') { $sspakCmd .= sprintf(' --db=%s', $databasePath); } elseif ($dataTransfer->Mode == 'assets') { $sspakCmd .= sprintf(' --assets=%s/assets', $filepathBase); } else { $sspakCmd .= sprintf(' --db=%s --assets=%s/assets', $databasePath, $filepathBase); } $process = new Process($sspakCmd); $process->setTimeout(3600); $process->run(); if (!$process->isSuccessful()) { $log->write('Could not package the backup via sspak'); throw new RuntimeException($process->getErrorOutput()); } // HACK: find_or_make() expects path relative to assets/ $sspakFilepath = ltrim(str_replace(array(ASSETS_PATH, realpath(ASSETS_PATH)), '', $filepathBase . DIRECTORY_SEPARATOR . $sspakFilename), DIRECTORY_SEPARATOR); try { $folder = Folder::find_or_make(dirname($sspakFilepath)); $file = new File(); $file->Name = $sspakFilename; $file->Filename = $sspakFilepath; $file->ParentID = $folder->ID; $file->write(); // "Status" will be updated by the job execution $dataTransfer->write(); // Get file hash to ensure consistency. // Only do this when first associating the file since hashing large files is expensive. $dataArchive->ArchiveFileHash = md5_file($file->FullPath); $dataArchive->ArchiveFileID = $file->ID; $dataArchive->DataTransfers()->add($dataTransfer); $dataArchive->write(); } catch (Exception $e) { $log->write('Failed to add sspak file: ' . $e->getMessage()); throw new RuntimeException($e->getMessage()); } // Remove any assets and db files lying around, they're not longer needed as they're now part // of the sspak file we just generated. Use --force to avoid errors when files don't exist, // e.g. when just an assets backup has been requested and no database.sql exists. $process = new Process(sprintf('rm -rf %s/assets && rm -f %s', $filepathBase, $databasePath)); $process->run(); if (!$process->isSuccessful()) { $log->write('Could not delete temporary files'); throw new RuntimeException($process->getErrorOutput()); } $log->write(sprintf('Creating *.sspak file done: %s', $file->getAbsoluteURL())); }
/** * Adds new properties to the parent (KickAssets) file JSON * * @return array */ protected function buildJSON() { $json = $this->parent->createFileJSON($this->file); $json['created'] = $this->file->obj('Created')->FormatFromSettings(); $json['lastEdited'] = $this->file->obj('LastEdited')->FormatFromSettings(); $json['url'] = $this->file->getAbsoluteURL(); $json['size'] = $this->file->getSize(); $json['folder'] = $this->file->Parent()->Filename; if ($this->file instanceof Image) { $json['previewImage'] = $this->file->CroppedImage(400, 133)->URL; $json['detailImage'] = $this->file->getKickAssetsDetailImage()->URL; } return $json; }
public function getAbsoluteURL() { $this->createLocalIfNeeded(); return $this->CloudStatus == 'Live' ? $this->getCloudURL() : parent::getAbsoluteURL(); }