Upload via GUI (258 Dateien)
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
// Direkter Web-Zugriff (Browser/URL) wird geblockt. Ausnahmen: echter CLI-Cronjob
|
||||
// sowie Einbindung per require_once aus dem authentifizierten Backend (staff/settings.php),
|
||||
// das vor dem require_once die Konstante DESKHUB_CRON_RUNNER definiert.
|
||||
if (php_sapi_name() !== 'cli' && !defined('DESKHUB_CRON_RUNNER')) { http_response_code(403); exit('Kein Web-Zugriff.'); }
|
||||
/**
|
||||
* Automatischer Backup-Cron
|
||||
* Crontab-Beispiele:
|
||||
* Täglich 02:00: 0 2 * * * php /pfad/zu/deskhub/cron/process_backups.php
|
||||
* Wöchentlich: 0 2 * * 1 php /pfad/zu/deskhub/cron/process_backups.php
|
||||
* Monatlich: 0 2 1 * * php /pfad/zu/deskhub/cron/process_backups.php
|
||||
*
|
||||
* Kann außerdem manuell aus dem Backend (Einstellungen → Cron-Jobs) ausgeführt werden
|
||||
* (dort wird der Zeitplan ignoriert und immer sofort ein Backup erstellt, $force=true).
|
||||
*/
|
||||
require_once __DIR__ . '/../includes/bootstrap.php';
|
||||
require_once __DIR__ . '/../includes/backup.php';
|
||||
|
||||
function bset(PDO $pdo, string $key): ?string {
|
||||
$s = $pdo->prepare('SELECT value FROM backup_settings WHERE key_name=?');
|
||||
$s->execute([$key]);
|
||||
$r = $s->fetch();
|
||||
return $r ? $r['value'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Führt das automatische Backup aus (falls laut Zeitplan fällig, oder immer bei $force=true).
|
||||
* Kann vom Cron und manuell aus settings.php aufgerufen werden.
|
||||
*
|
||||
* @return array{ran: bool, ok: bool, log: string[]}
|
||||
*/
|
||||
function run_process_backups(PDO $pdo, bool $verbose = false, bool $force = false): array
|
||||
{
|
||||
$log = [];
|
||||
|
||||
// Zeitplan prüfen
|
||||
$schedule = bset($pdo, 'schedule') ?: 'disabled';
|
||||
$lastBackup = bset($pdo, 'last_auto_backup') ?: '1970-01-01';
|
||||
$now = time();
|
||||
|
||||
$shouldRun = false;
|
||||
switch ($schedule) {
|
||||
case 'daily': $shouldRun = (strtotime($lastBackup) < strtotime('-1 day', $now)); break;
|
||||
case 'weekly': $shouldRun = (strtotime($lastBackup) < strtotime('-7 days', $now)); break;
|
||||
case 'monthly': $shouldRun = (strtotime($lastBackup) < strtotime('-30 days', $now)); break;
|
||||
default: $shouldRun = false; // disabled
|
||||
}
|
||||
|
||||
if ($force) {
|
||||
$shouldRun = true;
|
||||
}
|
||||
|
||||
if (!$shouldRun) {
|
||||
if ($schedule === 'disabled' && !$force) {
|
||||
$log[] = date('Y-m-d H:i:s') . ' – Automatische Backups sind deaktiviert (Zeitplan: disabled).';
|
||||
} else {
|
||||
$log[] = date('Y-m-d H:i:s') . " – Kein Backup nötig (Zeitplan: $schedule, letztes: $lastBackup)";
|
||||
}
|
||||
return ['ran' => false, 'ok' => true, 'log' => $log];
|
||||
}
|
||||
|
||||
$log[] = date('Y-m-d H:i:s') . ' – Starte Backup...';
|
||||
|
||||
$result = create_backup();
|
||||
|
||||
if (!$result['ok']) {
|
||||
$log[] = date('Y-m-d H:i:s') . " – FEHLER: {$result['error']}";
|
||||
return ['ran' => true, 'ok' => false, 'log' => $log];
|
||||
}
|
||||
|
||||
$log[] = date('Y-m-d H:i:s') . " – Backup erstellt: {$result['filename']} ({$result['size']} MB)";
|
||||
|
||||
// Sofort prüfen, ob sich das Backup wiederherstellen lässt (ohne etwas zu verändern)
|
||||
require_once __DIR__ . '/../includes/backup_restore.php';
|
||||
$check = backup_verify_and_record($result['path']);
|
||||
$log[] = date('Y-m-d H:i:s') . ($check['ok'] ? ' – Prüfung: Backup ist vollständig und wiederherstellbar.' : ' – WARNUNG, Backup nicht wiederherstellbar: ' . implode(' ', $check['errors']));
|
||||
|
||||
// Letztes Backup-Datum speichern
|
||||
$backupTime = date('Y-m-d H:i:s');
|
||||
$backupSettingSql = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME) === 'sqlite'
|
||||
? "INSERT INTO backup_settings (key_name, value, updated_at) VALUES ('last_auto_backup', ?, ?)
|
||||
ON CONFLICT(key_name) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at"
|
||||
: "INSERT INTO backup_settings (key_name, value, updated_at) VALUES ('last_auto_backup', ?, ?)
|
||||
ON DUPLICATE KEY UPDATE value=VALUES(value), updated_at=VALUES(updated_at)";
|
||||
$pdo->prepare($backupSettingSql)->execute([$backupTime, $backupTime]);
|
||||
|
||||
// ── FTP-Upload (optional) ────────────────────────────────────────────────────
|
||||
$ftpHost = bset($pdo, 'ftp_host');
|
||||
$ftpUser = bset($pdo, 'ftp_user');
|
||||
$ftpPass = bset($pdo, 'ftp_pass');
|
||||
$ftpPath = bset($pdo, 'ftp_path') ?: '/';
|
||||
$ftpPort = (int)(bset($pdo, 'ftp_port') ?: 21);
|
||||
$ftpTls = bset($pdo, 'ftp_tls') === '1';
|
||||
|
||||
if ($ftpHost && $ftpUser) {
|
||||
$log[] = date('Y-m-d H:i:s') . " – FTP-Upload nach $ftpHost...";
|
||||
|
||||
if (!function_exists('ftp_connect')) {
|
||||
$log[] = date('Y-m-d H:i:s') . ' – WARNUNG: PHP FTP-Erweiterung nicht verfügbar.';
|
||||
} else {
|
||||
$ftp = $ftpTls ? @ftp_ssl_connect($ftpHost, $ftpPort, 10) : @ftp_connect($ftpHost, $ftpPort, 10);
|
||||
if ($ftp && @ftp_login($ftp, $ftpUser, $ftpPass)) {
|
||||
ftp_pasv($ftp, true);
|
||||
$remotePath = rtrim($ftpPath, '/') . '/' . $result['filename'];
|
||||
if (ftp_put($ftp, $remotePath, $result['path'], FTP_BINARY)) {
|
||||
$log[] = date('Y-m-d H:i:s') . " – FTP-Upload erfolgreich: $remotePath";
|
||||
// FTP-Rotation
|
||||
$ftpKeep = (int)(bset($pdo, 'ftp_keep') ?: 5);
|
||||
$files = @ftp_nlist($ftp, $ftpPath);
|
||||
if ($files) {
|
||||
$backupFiles = array_filter($files, fn($f) => str_contains($f, 'backup_'));
|
||||
rsort($backupFiles);
|
||||
foreach (array_slice($backupFiles, $ftpKeep) as $old) {
|
||||
@ftp_delete($ftp, $old);
|
||||
$log[] = date('Y-m-d H:i:s') . " – FTP-Rotation: $old gelöscht";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$log[] = date('Y-m-d H:i:s') . ' – FTP-Upload fehlgeschlagen.';
|
||||
}
|
||||
ftp_close($ftp);
|
||||
} else {
|
||||
$log[] = date('Y-m-d H:i:s') . ' – FTP-Verbindung fehlgeschlagen.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Lokale Rotation ──────────────────────────────────────────────────────────
|
||||
$keepLocal = (int)(bset($pdo, 'rotate_keep') ?: 0);
|
||||
if ($keepLocal > 0) {
|
||||
$backupDir = realpath(__DIR__ . '/../backups');
|
||||
$files = array_merge(
|
||||
glob($backupDir . '/backup_*.zip') ?: [],
|
||||
glob($backupDir . '/backup_*.tar.gz') ?: []
|
||||
);
|
||||
usort($files, fn($a, $b) => filemtime($b) - filemtime($a));
|
||||
foreach (array_slice($files, $keepLocal) as $old) {
|
||||
unlink($old);
|
||||
$log[] = date('Y-m-d H:i:s') . ' – Rotation: ' . basename($old) . ' gelöscht';
|
||||
}
|
||||
}
|
||||
|
||||
set_setting('cron_process_backups_last_run', date('Y-m-d H:i:s'));
|
||||
$log[] = date('Y-m-d H:i:s') . ' – Fertig.';
|
||||
|
||||
return ['ran' => true, 'ok' => true, 'log' => $log];
|
||||
}
|
||||
|
||||
if (php_sapi_name() === 'cli') {
|
||||
$result = run_process_backups(get_db(), true, false);
|
||||
foreach ($result['log'] as $line) {
|
||||
echo $line . "\n";
|
||||
}
|
||||
if (!$result['ok']) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user