/** * Cleanup your backup directory. * * @see \phpbu\App\Backup\Cleanup::cleanup() * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Backup\Collector $collector * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Cleaner\Exception */ public function cleanup(Target $target, Collector $collector, Result $result) { $files = $collector->getBackupFiles(); if ($this->isCapacityExceeded($files)) { // oldest backups first ksort($files); while ($this->isCapacityExceeded($files)) { $file = array_shift($files); $result->debug(sprintf('delete %s', $file->getPathname())); if (!$file->isWritable()) { throw new Exception(sprintf('can\'t delete file: %s', $file->getPathname())); } $result->debug(sprintf('delete %s', $file->getPathname())); $file->unlink(); } } }
/** * Compress the configured directory. * * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @throws \phpbu\App\Exception */ public function compress(Target $target, Result $result) { if (!$target->shouldBeCompressed()) { throw new Exception('target should not be compressed'); } $res = $this->execute($target); $result->debug($res->getCmd()); if (0 !== $res->getCode()) { throw new Exception('Failed to \'compress\' file: ' . $this->path); } }
/** * Compress the configured directory. * * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @return string * @throws \phpbu\App\Exception */ public function compress(Target $target, Result $result) { if (!$target->shouldBeCompressed()) { throw new Exception('target should not be compressed'); } if (!$this->isPathValid($this->path)) { throw new Exception('path to compress should be valid'); } $res = $this->execute($target); $result->debug($res->getCmd()); if (0 !== $res->getCode()) { throw new Exception('Failed to \'compress\' file: ' . $this->path); } return $this->getArchiveFile($target); }
/** * Cleanup your backup directory. * * @see \phpbu\App\Backup\Cleanup::cleanup() * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Backup\Collector $collector * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Cleaner\Exception */ public function cleanup(Target $target, Collector $collector, Result $result) { $minTime = time() - $this->offsetSeconds; $files = $collector->getBackupFiles(); /** @var \phpbu\App\Backup\File $file */ foreach ($files as $file) { // last mod date < min date? delete! if ($file->getMTime() < $minTime) { if (!$file->isWritable()) { throw new Exception(sprintf('can\'t delete file: %s', $file->getPathname())); } $result->debug(sprintf('delete %s', $file->getPathname())); $file->unlink(); } } }
/** * Execute the backup. * * @see \phpbu\App\Backup\Source * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @return \phpbu\App\Backup\Source\Status * @throws \phpbu\App\Exception */ public function backup(Target $target, Result $result) { // set uncompressed default MIME type $target->setMimeType('application/octet-stream'); $redisSave = $this->getExecutable($target); $redisLast = $this->getRedisLastSave($redisSave); $lastBackupTimestamp = $this->getLastBackupTime($redisLast); $saveResult = $redisSave->run(); $result->debug($saveResult->getCmd()); if (!$saveResult->wasSuccessful()) { throw new Exception('redis-cli BGSAVE failed'); } $this->isDumpCreatedYet($lastBackupTimestamp, $redisLast); $pathToDump = $this->copyDumpToTargetDir($target); return Status::create()->uncompressed($pathToDump); }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Sync::sync() * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Sync\Exception */ public function sync(Target $target, Result $result) { $sourcePath = $target->getPathname(); $yandexDiskPath = $this->path . $target->getFilename(); $this->disk = new Disk($this->token); $size = null; if (stream_is_local($sourcePath)) { $size = filesize($sourcePath); } $file = $this->disk->resource(); $this->createFolders(); try { $file = $this->disk->resource($yandexDiskPath); $file->getContents(); } catch (NotFoundException $exc) { $file->upload($sourcePath, true); } if ($file->has()) { $result->debug('upload: done (' . $size . ')'); } else { $result->debug('upload: error while uploading file'); } }
/** * Tests debug. */ public function testDebug() { $conf = new Configuration('/tmp/foo.xml'); $backup = new Configuration\Backup('test-backup', false); $result = new Result(); $result->phpbuStart($conf); $result->debug('debug'); $result->backupStart($backup); $result->backupEnd($backup); $result->phpbuEnd(); }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Crypter * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @throws Exception */ public function crypt(Target $target, Result $result) { $mcrypt = $this->execute($target); $result->debug('mcrypt:' . $mcrypt->getCmd()); if (!$mcrypt->wasSuccessful()) { throw new Exception('mcrypt failed:' . PHP_EOL . $mcrypt->getOutputAsString()); } }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Sync::sync() * @param \phpbu\App\backup\Target $target * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Sync\Exception */ public function sync(Target $target, Result $result) { $sourcePath = $target->getPathname(); $targetPath = $this->path . $target->getFilename(); $options = array('adapter' => ObjectStorage_Http_Client::SOCKET, 'timeout' => 20); $objectStorage = new ObjectStorage($this->host, $this->user, $this->secret, $options); $result->debug('softlayer source: ' . $sourcePath); $result->debug('softlayer target: ' . $targetPath); try { /** @var \ObjectStorage_Container $container */ $container = $objectStorage->with($this->container . $targetPath)->setLocalFile($sourcePath)->setMeta('description', 'PHPBU Backup: ' . date('r', time()))->setHeader('Content-Type', $target->getMimeType()); $container->create(); } catch (\Exception $e) { throw new Exception($e->getMessage(), null, $e); } $result->debug('upload: done'); }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Source * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @return \phpbu\App\Backup\Source\Status * @throws \phpbu\App\Exception */ public function backup(Target $target, Result $result) { $elasticdump = $this->execute($target); $result->debug($elasticdump->getCmd()); if (!$elasticdump->wasSuccessful()) { throw new Exception('elasticdump failed'); } return Status::create()->uncompressed($target->getPathnamePlain()); }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Source * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @return \phpbu\App\Backup\Source\Status * @throws \phpbu\App\Exception */ public function backup(Target $target, Result $result) { // setup dump location and execute the dump $this->dumpPathname = $target->getPathnamePlain(); $mysqldump = $this->execute($target); $result->debug($mysqldump->getCmd()); if (!$mysqldump->wasSuccessful()) { throw new Exception('mysqldump failed'); } return Status::create()->uncompressed()->dataPath($this->dumpPathname); }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Sync::sync() * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Sync\Exception */ public function sync(Target $target, Result $result) { if ($this->args) { // pro mode define all arguments yourself // WARNING! no escaping is done by phpbu $result->debug('WARNING: phpbu uses your rsync args without escaping'); } $rsync = $this->execute($target); $result->debug($rsync->getCmd()); if (!$rsync->wasSuccessful()) { throw new Exception('rsync failed: ' . PHP_EOL . $rsync->getOutputAsString()); } }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Sync::sync() * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Sync\Exception */ public function sync(Target $target, Result $result) { $sourcePath = $target->getPathname(); $dropboxPath = $this->path . $target->getFilename(); $client = new DropboxApi\Client($this->token, "phpbu/1.1.0"); $pathError = DropboxApi\Path::findErrorNonRoot($dropboxPath); if (substr(__FILE__, 0, 7) == 'phar://') { DropboxApi\RootCertificates::useExternalPaths(); } if ($pathError !== null) { throw new Exception(sprintf('Invalid \'dropbox-path\': %s', $pathError)); } $size = null; if (stream_is_local($sourcePath)) { $size = filesize($sourcePath); } try { $fp = fopen($sourcePath, 'rb'); $res = $client->uploadFile($dropboxPath, DropboxApi\WriteMode::add(), $fp, $size); fclose($fp); } catch (\Exception $e) { throw new Exception($e->getMessage(), null, $e); } $result->debug('upload: done (' . $res['size'] . ')'); }
/** * Cleanup your backup directory. * * @see \phpbu\App\Backup\Cleanup::cleanup() * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Backup\Collector $collector * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Cleaner\Exception */ public function cleanup(Target $target, Collector $collector, Result $result) { $files = $collector->getBackupFiles(); $size = $target->getSize(); /** @var \phpbu\App\Backup\File $file */ foreach ($files as $file) { $size += $file->getSize(); } // backups exceed capacity? if ($size > $this->capacityBytes) { // oldest backups first ksort($files); while ($size > $this->capacityBytes && count($files) > 0) { $file = array_shift($files); $size -= $file->getSize(); if (!$file->isWritable()) { throw new Exception(sprintf('can\'t delete file: %s', $file->getPathname())); } $result->debug(sprintf('delete %s', $file->getPathname())); $file->unlink(); } // deleted all old backups but still exceeding the space limit // delete the currently created backup as well if ($this->deleteTarget && $size > $this->capacityBytes) { $target->unlink(); } } }
/** * Execute the compressor. * Returns the path to the created archive file. * * @param \phpbu\App\Backup\Compressor\Executable $compressor * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @return string */ private function executeCompressor(Compressor\Executable $compressor, Target $target, Result $result) { // if this is a simulation just debug the command that would have been executed if ($this->isSimulation) { $result->debug($compressor->getExecutable($target)->getCommandLine()); return $compressor->getArchiveFile($target); } else { return $compressor->compress($target, $result); } }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Source * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @return \phpbu\App\Backup\Source\Status * @throws \phpbu\App\Exception */ public function backup(Target $target, Result $result) { // set uncompressed default MIME type $target->setMimeType('application/x-tar'); $status = Status::create(); $tar = $this->execute($target); // if tar doesn't handle the compression mark status uncompressed so the app can take care of compression if (!$this->executable->handlesCompression()) { $status->uncompressed($target->getPathnamePlain()); } $result->debug($tar->getCmd()); if (!$tar->wasSuccessful()) { throw new Exception('tar failed'); } return $status; }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Sync::sync() * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Sync\Exception */ public function sync(Target $target, Result $result) { $sourcePath = $target->getPathname(); $targetPath = $this->path . $target->getFilename(); $copy = new CopycomApi($this->appKey, $this->appSecret, $this->userKey, $this->userSecret); try { // open a file to upload $fh = fopen($sourcePath, 'rb'); // upload the file in 1MB chunks $parts = array(); while ($data = fread($fh, 1024 * 1024)) { $part = $copy->sendData($data); array_push($parts, $part); } fclose($fh); // finalize the file $copy->createFile($targetPath, $parts); } catch (\Exception $e) { throw new Exception($e->getMessage(), null, $e); } $result->debug('upload: done'); }
/** * Execute the sync * * @see \phpbu\App\Backup\Sync::sync() * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Sync\Exception */ public function sync(Target $target, Result $result) { $sourcePath = $target->getPathname(); $targetPath = $this->path . $target->getFilename(); $s3 = S3Client::factory(array('signature' => 'v4', 'region' => $this->region, 'credentials' => array('key' => $this->key, 'secret' => $this->secret))); try { $fh = fopen($sourcePath, 'r'); $s3->upload($this->bucket, $targetPath, $fh, $this->acl); } catch (\Exception $e) { throw new Exception($e->getMessage(), null, $e); } $result->debug('upload: done'); }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Source * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @return \phpbu\App\Backup\Source\Status * @throws \phpbu\App\Exception */ public function backup(Target $target, Result $result) { $innobackupex = $this->execute($target); $result->debug($innobackupex->getCmd()); if (!$innobackupex->wasSuccessful()) { throw new Exception('XtraBackup failed'); } return Status::create()->uncompressed()->dataPath($this->getDumpDir($target)); }
/** * In here you should create your backup. * * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * * @return \phpbu\App\Backup\Source\Status * @throws \phpbu\App\Exception; */ public function backup(Target $target, Result $result) { $status = Status::create(); // use these methods to store the backup at the configured location // $target->getPath() // $target->getPathname() // $target->getFilename() // to know if the backup should be compressed use // $target->shouldBeCompressed() // to get the compression settings use // $target->getCompressor() // if you want to log some debug information use // $result->debug('some message'); // anything bad happens throw a \phpbu\App\Exception // Clone target class for the archiving part // $tarTarget = clone $target; // Rsync to a temporary directory // $date = new \DateTime(); // $target->setPath('/tmp/phpbu-rsync-' . $date->format('Ymd-His')); // Execute the sync $rsync = $this->execute($target); $result->debug($rsync->getCmd()); // if (!$rsync->wasSuccessful()) { throw new Exception('rsync failed: ' . PHP_EOL . $rsync->getOutputAsString()); } // Archive the synced files // $tarOptions = [ // 'path' => $target->getPath(), // // FIXME: removeDir boolean doesn't work. Value in Source/Tar class is not used or passed along to the executable // 'removeDir' => true, // 'showStdErr' => true, // ]; // // $tar = new Source\Tar(); // $tar->setup($tarOptions); // $tarResult = $tar->backup($tarTarget, $result); // // // If tar doesn't handle the compression mark status // // uncompressed so the app can take care of compression // if (!$tarResult->handledCompression()) { // $status->uncompressed()->dataPath($target->getPathnamePlain()); // } return $status; }
/** * Run phpbu * * @param \phpbu\App\Configuration $configuration * @param \phpbu\App\Factory * @return \phpbu\App\Result */ public function run(Configuration $configuration) { // TODO: don't rely on static/global settings this is ugly Util\Cli::registerBase('configuration', $configuration->getWorkingDirectory()); $stop = false; $this->result = new Result(); $this->configuration = $configuration; $this->setupEnvironment($configuration); $this->setupLoggers($configuration); $this->result->phpbuStart($configuration); // create backups /** @var \phpbu\App\Configuration\Backup $backup */ foreach ($configuration->getBackups() as $backup) { if ($stop) { break; } // setup target and collector, reset failure state $target = $this->createTarget($backup->getTarget()); $collector = new Collector($target); $this->failure = false; try { /* ___ ___ _______ ____ _____ * / _ )/ _ |/ ___/ //_/ / / / _ \ * / _ / __ / /__/ ,< / /_/ / ___/ * /____/_/ |_\___/_/|_|\____/_/ */ $this->executeSource($backup, $target); /* _______ _____________ ______ * / ___/ // / __/ ___/ //_/ __/ * / /__/ _ / _// /__/ ,< _\ \ * \___/_//_/___/\___/_/|_/___/ */ $this->executeChecks($backup, $target, $collector); /* __________ _____ ______ * / ___/ _ \ \/ / _ \/_ __/ * / /__/ , _/\ / ___/ / / * \___/_/|_| /_/_/ /_/ */ $this->executeCrypt($backup, $target); /* ______ ___ ___________ * / __/\ \/ / |/ / ___/ __/ * _\ \ \ / / /___\ \ * /___/ /_/_/|_/\___/___/ */ $this->executeSyncs($backup, $target); /* _______ _______ _ ____ _____ * / ___/ / / __/ _ | / |/ / / / / _ \ * / /__/ /__/ _// __ |/ / /_/ / ___/ * \___/____/___/_/ |_/_/|_/\____/_/ */ $this->executeCleanup($backup, $target, $collector); } catch (\Exception $e) { $this->result->debug('exception: ' . $e->getMessage()); $this->result->addError($e); $this->result->backupFailed($backup); if ($backup->stopOnFailure()) { $stop = true; } } } $this->result->phpbuEnd(); return $this->result; }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Source * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @return \phpbu\App\Backup\Source\Status * @throws \phpbu\App\Exception */ public function backup(Target $target, Result $result) { // setup dump location and execute the dump $mongodump = $this->execute($target); $result->debug($mongodump->getCmd()); if (!$mongodump->wasSuccessful()) { throw new Exception('Mongodump failed'); } return Status::create()->uncompressed($this->getDumpDir($target)); }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Sync::sync() * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Sync\Exception */ public function sync(Target $target, Result $result) { // silence ftp errors $old = error_reporting(0); if (!($ftpConnection = ftp_connect($this->host))) { throw new Exception(sprintf('Unable to connect to ftp server %s', $this->host)); } if (!ftp_login($ftpConnection, $this->user, $this->password)) { error_reporting($old); throw new Exception(sprintf('authentication failed for %s@%s%s', $this->user, $this->host, empty($this->password) ? '' : ' with password ****')); } $remoteFilename = $target->getFilename(); $localFile = $target->getPathname(); if ('' !== $this->remotePath) { $remoteDirs = explode('/', $this->remotePath); foreach ($remoteDirs as $dir) { if (!ftp_chdir($ftpConnection, $dir)) { $result->debug(sprintf('creating remote dir \'%s\'', $dir)); ftp_mkdir($ftpConnection, $dir); ftp_chdir($ftpConnection, $dir); } else { $result->debug(sprintf('change to remote dir \'%s\'', $dir)); } } } $result->debug(sprintf('store file \'%s\' as \'%s\'', $localFile, $remoteFilename)); if (!ftp_put($ftpConnection, $remoteFilename, $localFile, FTP_BINARY)) { $error = error_get_last(); $message = $error['message']; throw new Exception(sprintf('error uploading file: %s - %s', $localFile, $message)); } error_reporting($old); }
/** * (non-PHPDoc) * * @see \phpbu\App\Backup\Sync::sync() * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @throws \phpbu\App\Backup\Sync\Exception */ public function sync(Target $target, Result $result) { // silence phpseclib $old = error_reporting(0); $sftp = new phpseclib\Net\SFTP($this->host); if (!$sftp->login($this->user, $this->password)) { error_reporting($old); throw new Exception(sprintf('authentication failed for %s@%s%s', $this->user, $this->host, empty($this->password) ? '' : ' with password ****')); } error_reporting($old); $remoteFilename = $target->getFilename(); $localFile = $target->getPathname(); if ('' !== $this->remotePath) { $remoteDirs = explode('/', $this->remotePath); foreach ($remoteDirs as $dir) { if (!$sftp->is_dir($dir)) { $result->debug(sprintf('creating remote dir \'%s\'', $dir)); $sftp->mkdir($dir); } $result->debug(sprintf('change to remote dir \'%s\'', $dir)); $sftp->chdir($dir); } } $result->debug(sprintf('store file \'%s\' as \'%s\'', $localFile, $remoteFilename)); $result->debug(sprintf('last error \'%s\'', $sftp->getLastSFTPError())); /** @noinspection PhpInternalEntityUsedInspection */ if (!$sftp->put($remoteFilename, $localFile, phpseclib\Net\SFTP::SOURCE_LOCAL_FILE)) { throw new Exception(sprintf('error uploading file: %s - %s', $localFile, $sftp->getLastSFTPError())); } }
/** * Simulate the backup execution. * * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Result $result * @return \phpbu\App\Backup\Source\Status */ public function simulate(Target $target, Result $result) { $result->debug($this->getExecutable($target)->getCommandLine()); }