Upload via GUI (258 Dateien)

This commit is contained in:
2026-10-16 19:12:15 +00:00
parent 491b87f468
commit 56deade877
50 changed files with 23552 additions and 0 deletions
+157
View File
@@ -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);
}
}