1
0
Files
re_capitulating_queer/site/plugins/kirby3-janitor/classes/BackupZipJob.php
2024-10-14 14:22:24 +02:00

166 lines
5.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Bnomei;
use Kirby\Cms\Page;
use Kirby\Toolkit\A;
use Kirby\Toolkit\Dir;
use Kirby\Toolkit\F;
use Symfony\Component\Finder\Finder;
use ZipArchive;
final class BackupZipJob extends JanitorJob
{
/** @var array */
private $options;
public function __construct(?Page $page = null, ?string $data = null)
{
parent::__construct($page, $data);
$this->options = [
'ulimit' => option('bnomei.janitor.backupzip.ulimit', 512), // 1024 seems to be unix default
'date' => option('bnomei.janitor.backupzip.date', null), // null to disable, 'since 1 day ago'
'roots' => option('bnomei.janitor.backupzip.roots', function () {
return [
kirby()->roots()->accounts(),
kirby()->roots()->content(),
];
}),
'target' => option('bnomei.janitor.backupzip.target', function () {
$dir = realpath(kirby()->roots()->accounts() . '/../') . '/backups';
Dir::make($dir);
$prefix = option('bnomei.janitor.backupzip.prefix', '');
return $dir . '/' . $prefix . time() . '.zip'; // date('Y-m-d')
}),
];
foreach ($this->options as $key => $value) {
if (!is_string($value) && is_callable($value)) {
$this->options[$key] = $value();
}
}
}
/**
* @param string|null $key
* @return array
*/
public function option(?string $key = null)
{
if ($key) {
return A::get($this->options, $key);
}
return $this->options;
}
public static function directory(): string
{
return \dirname((string) (new self())->option('target'));
}
/**
* @return array
*/
public function job(): array
{
$time = time();
$climate = \Bnomei\Janitor::climate();
$zipPath = (string) $this->option('target');
$zip = new ZipArchive();
if ($zip->open($zipPath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE) !== true) {
if ($climate) {
$climate->red('Failed to create: ' . $zipPath);
}
return [
'status' => 500,
];
}
$roots = $this->option('roots');
$finder = new Finder();
$finder->files()->in($roots);
if ($date = $this->option('date')) {
$finder->date($date);
}
$count = iterator_count($finder); // closing of zip
$ulimit = $this->option('ulimit');
$zipped = 0;
if ($climate) {
$climate->out('Files: ' . $count);
}
$progress = null;
if ($count && $climate) {
$progress = $climate->progress()->total($count);
}
foreach ($finder as $file) {
$filePath = $file->getPath() . DIRECTORY_SEPARATOR . $file->getFilename();
$localFilePath = $filePath;
foreach ($roots as $root) {
$localFilePath = str_replace(dirname($root), '', $localFilePath);
}
if ($zip->addFile($filePath, $localFilePath)) {
$mime = F::mime($filePath);
if (in_array($mime, [
'application/json', 'text/json',
'application/yaml', 'text/yaml',
'text/html',
'text/plain',
'text/xml',
'application/x-javascript',
'text/css',
'text/csv', 'text/x-comma-separated-values',
'text/comma-separated-values', 'application/octet-stream',
])) {
$zip->setCompressionName($filePath, ZipArchive::CM_DEFLATE);
} else {
$zip->setCompressionName($filePath, ZipArchive::CM_STORE);
}
$zipped++;
if ($progress && $climate) {
$progress->current($zipped);
}
if ($zipped % $ulimit === 0) {
$zip->close();
if ($zip->open($zipPath) === false) {
@unlink($zipPath);
if ($climate) {
$climate->red('Hit ulimit but failed to reopen zip: ' . $zipPath);
}
return [
'status' => 500,
'error' => 'Hit ulimit but failed to reopen zip: ' . $zipPath,
];
}
}
}
}
if ($climate) {
$climate->out('Closing zip...');
}
$zip->close();
if ($climate) {
$climate->out($zipPath);
}
return [
'status' => $zipped > 0 ? 200 : 204,
'duration' => time() - $time,
'filename' => \basename($zipPath, '.zip'),
'files' => $zipped,
'nicesize' => \Kirby\Toolkit\F::niceSize($zipPath),
'modified' => date('d/m/Y, H:i:s', \Kirby\Toolkit\F::modified($zipPath)),
];
}
}