/** * 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); }
/** * (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'] . ')'); }
/** * Executes a backup check. * * @param \phpbu\App\Backup\Check $check * @param \phpbu\App\Configuration\Backup\Check $config * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Backup\Collector $collector * @param \phpbu\App\Result $result */ public function run(CheckExe $check, CheckConfig $config, Target $target, Collector $collector, Result $result) { try { $result->checkStart($config); if ($check->pass($target, $config->value, $collector, $result)) { $result->checkEnd($config); } else { $this->failure = true; $result->checkFailed($config); } } catch (Exception $e) { $this->failure = true; $result->addError($e); $result->checkFailed($config); } }
/** * 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(); } } }
/** * 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(); } } }
/** * (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())); } }
/** * 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(); } } }
/** * 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; }
/** * Execute the cleanup. * * @param \phpbu\App\Configuration\Backup $backup * @param \phpbu\App\Backup\Target $target * @param \phpbu\App\Backup\Collector $collector * @throws \Exception */ protected function executeCleanup(Configuration\Backup $backup, Target $target, Collector $collector) { $cleanup = $backup->getCleanup(); if (!empty($cleanup)) { try { $this->result->cleanupStart($cleanup); if ($this->failure && $cleanup->skipOnFailure) { $this->result->cleanupSkipped($cleanup); } else { $cleaner = $this->factory->createCleaner($cleanup->type, $cleanup->options); $cleaner->cleanup($target, $collector, $this->result); $this->result->cleanupEnd($cleanup); } } catch (Backup\Cleaner\Exception $e) { $this->failure = true; $this->result->addError($e); $this->result->cleanupFailed($cleanup); } } }
/** * (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'); } }
/** * Return backup information. * * @param \phpbu\App\Result $result * @return array */ protected function extractBackups(Result $result) { $output = []; $backups = $result->getBackups(); if (count($backups) > 0) { /** @var \phpbu\App\Result\Backup $backup */ foreach ($backups as $backup) { $output[] = ['name' => $backup->getName(), 'status' => $backup->wasSuccessful() ? 0 : 1, 'checks' => ['executed' => $backup->checkCount(), 'failed' => $backup->checkCountFailed()], 'crypt' => ['executed' => $backup->cryptCount(), 'skipped' => $backup->cryptCountSkipped(), 'failed' => $backup->cryptCountFailed()], 'syncs' => ['executed' => $backup->syncCount(), 'skipped' => $backup->syncCountSkipped(), 'failed' => $backup->syncCountFailed()], 'cleanups' => ['executed' => $backup->cleanupCount(), 'skipped' => $backup->cleanupCountSkipped(), 'failed' => $backup->cleanupCountFailed()]]; } } return $output; }
/** * (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'); }
/** * 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) { $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\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()); } }
/** * 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\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\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)); }
/** * (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'); }
/** * Prints 'OK' or 'FAILURE' footer. * * @param Result $result */ protected function printFooter(Result $result) { if (count($result->getBackups()) === 0) { $this->writeWithColor('fg-black, bg-yellow', 'No backups executed!'); } elseif ($result->allOk()) { $this->writeWithColor('fg-black, bg-green', sprintf('OK (%d %s, %d %s, %d %s, %d %s, %d %s)' . PHP_EOL, count($result->getBackups()), Util\Str::appendPluralS('backup', count($result->getBackups())), $this->numChecks, Util\Str::appendPluralS('check', $this->numChecks), $this->numCrypts, Util\Str::appendPluralS('crypt', $this->numCrypts), $this->numSyncs, Util\Str::appendPluralS('sync', $this->numSyncs), $this->numCleanups, Util\Str::appendPluralS('cleanup', $this->numCleanups))); } elseif ($result->backupOkButSkipsOrFails()) { $this->writeWithColor('fg-black, bg-yellow', sprintf("OK, but skipped|failed Crypts, Syncs or Cleanups!\n" . 'Backups: %d, Crypts: %d|%d, Syncs: %d|%d, Cleanups: %d|%d.' . PHP_EOL, count($result->getBackups()), $result->cryptsSkippedCount(), $result->cryptsFailedCount(), $result->syncsSkippedCount(), $result->syncsFailedCount(), $result->cleanupsSkippedCount(), $result->cleanupsFailedCount())); } else { $this->writeWithColor('fg-white, bg-red', sprintf("FAILURE!\n" . 'Backups: %d, failed Checks: %d, failed Crypts: %d, failed Syncs: %d, failed Cleanups: %d.' . PHP_EOL, count($result->getBackups()), $result->checksFailedCount(), $result->cryptsFailedCount(), $result->syncsFailedCount(), $result->cleanupsFailedCount())); } }
/** * 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); }
/** * 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\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\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; }
/** * 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()); }
/** * Return backup html information. * * @param \phpbu\App\Result $result * @return string */ protected function getInfoHtml(Result $result) { $html = ''; $backups = $result->getBackups(); if (count($backups)) { $html .= '<table ' . TPL::getSnippet('sTableBackup') . '>'; /** @var \phpbu\App\Result\Backup $backup */ foreach ($backups as $backup) { if ($backup->allOk()) { $color = TPL::getSnippet('cStatusOK'); $status = 'OK'; } elseif ($backup->okButSkipsOrFails()) { $color = TPL::getSnippet('cStatusWARN'); $status = 'WARNING'; } else { $color = TPL::getSnippet('cStatusFAIL'); $status = 'FAILURE'; } $html .= '<tr>' . '<td ' . sprintf(TPL::getSnippet('sTableBackupStatusColumn'), $color) . ' colspan="4">' . sprintf('backup <em>%s</em>', $backup->getName()) . ' <span ' . TPL::getSnippet('sTableBackupStatusText') . '>' . $status . '</span>' . '</td>' . '</tr>' . '<tr>' . '<td ' . TPL::getSnippet('sRowHead') . '> </td>' . '<td ' . TPL::getSnippet('sRowHead') . ' align="right">executed</td>' . '<td ' . TPL::getSnippet('sRowHead') . ' align="right">skipped</td>' . '<td ' . TPL::getSnippet('sRowHead') . ' align="right">failed</td>' . '</tr>'; $html .= '<tr>' . '<td ' . TPL::getSnippet('sRowCheck') . '>checks</td>' . '<td ' . TPL::getSnippet('sRowCheck') . ' align="right">' . $backup->checkCount() . ' </td>' . '<td ' . TPL::getSnippet('sRowCheck') . ' align="right"> </td>' . '<td ' . TPL::getSnippet('sRowCheck') . ' align="right">' . $backup->checkCountFailed() . '</td>' . '</tr>' . '<tr>' . '<td ' . TPL::getSnippet('sRowCrypt') . '>crypts</td>' . '<td ' . TPL::getSnippet('sRowCrypt') . ' align="right">' . $backup->cryptCount() . '</td>' . '<td ' . TPL::getSnippet('sRowCrypt') . ' align="right">' . $backup->cryptCountSkipped() . '</td>' . '<td ' . TPL::getSnippet('sRowCrypt') . ' align="right">' . $backup->cryptCountFailed() . '</td>' . '</tr>' . '<tr>' . '<td ' . TPL::getSnippet('sRowSync') . '>syncs</td>' . '<td ' . TPL::getSnippet('sRowSync') . ' align="right">' . $backup->syncCount() . '</td>' . '<td ' . TPL::getSnippet('sRowSync') . ' align="right">' . $backup->syncCountSkipped() . '</td>' . '<td ' . TPL::getSnippet('sRowSync') . ' align="right">' . $backup->syncCountFailed() . '</td>' . '</tr>' . '<tr>' . '<td ' . TPL::getSnippet('sRowCleanup') . '>cleanups</td>' . '<td ' . TPL::getSnippet('sRowCleanup') . ' align="right">' . $backup->cleanupCount() . '</td>' . '<td ' . TPL::getSnippet('sRowCleanup') . ' align="right">' . $backup->cleanupCountSkipped() . '</td>' . '<td ' . TPL::getSnippet('sRowCleanup') . ' align="right">' . $backup->cleanupCountFailed() . '</td>' . '</tr>'; } $html .= '</table>'; } return $html; }