# Backup-Quellen und Ziele ## Überblick Was gesichert wird, steht in `MANAGE_BACKUP_SOURCES`. Optional kommt ein MySQL-Dump dazu. Wohin gesichert wird, steuern `MANAGE_BACKUP_UPLOAD` und `MANAGE_BACKUP_REMOTE_TARGETS`. Relevante Dateien: - `manage-client/lib/backup.php` – Sammeln, Archivieren, Aufbewahrung, Upload - `manage-client/lib/zip.php` – ZIP-Erzeugung ohne externe Bibliothek - `manage-client/lib/mysql.php` – optionaler Datenbank-Dump - `manage-client/lib/remote.php` – zusätzliche Ziele ## Quellen deklarieren Alle Pfade sind relativ zu `MANAGE_APP_ROOT`. Jeder Eintrag verwendet genau eine der drei Formen: ```php define("MANAGE_BACKUP_SOURCES", [ // Nicht-rekursives Glob-Muster ["as" => "data", "glob" => "data/*.json"], // Verzeichnis, rekursiv ["as" => "data/uploads", "dir" => "data/uploads"], // Einzelne Datei ["as" => "config", "file" => "config.dist.php"], ]); ``` `as` ist das Präfix im Archiv. Ohne `as` landet der Eintrag auf oberster Ebene – bei `dir` wird der Verzeichnisname als Präfix verwendet. Das obige Beispiel erzeugt: ```text data/orders.json data/settings.json data/uploads/2026/bild.jpg config/config.dist.php ``` ### Was automatisch übersprungen wird - Dateien, deren Name mit einem Punkt beginnt - Dateien mit den Endungen `.tmp` und `.part` - nicht lesbare Dateien Ergeben zwei Quellen denselben Archivpfad, gewinnt die erste. Ein Archiv enthält nie zwei Einträge mit gleichem Namen. ### Was **nicht** hineingehört - `config.php` mit echten Zugangsdaten – ein Backup wird an den Server übertragen und dort heruntergeladen; siehe [10_SECURITY](10_SECURITY.md) - das Backup-Verzeichnis selbst - Protokolle und Cache-Verzeichnisse - die Anwendungsdateien: Die kommen aus dem Release-Paket, nicht aus dem Backup Ein Backup sichert **Betriebsdaten**, kein vollständiges Systemabbild. ## Datenbank-Dump Nur aktiv, wenn `MANAGE_BACKUP_DATABASE` gesetzt ist: ```php define("MANAGE_BACKUP_DATABASE", [ "dsn" => "mysql:host=localhost;dbname=meinprojekt;charset=utf8mb4", "user" => "meinprojekt", "password" => "…", // Optional: von diesen Tabellen nur die Struktur sichern, nicht die Zeilen. "skip_data_tables" => ["sessions", "cache"], // Optional: Name im Archiv, falls SELECT DATABASE() nichts liefert. "name" => "meinprojekt", ]); ``` Der Dump landet im Archiv als `database/.sql` und enthält für jede Tabelle `DROP TABLE IF EXISTS`, das `CREATE TABLE` aus `SHOW CREATE TABLE` und die Zeilen als einzelne `INSERT`-Anweisungen. `SET FOREIGN_KEY_CHECKS=0` steht am Anfang, am Ende wird wieder auf `1` gesetzt. Eigenschaften und Grenzen: - Nur PDO, kein `mysqldump`-Aufruf – das ist auf vielen Shared-Hostern die einzige Möglichkeit, funktioniert aber nur für MySQL und MariaDB. - Die Zeilen werden in Blöcken von 500 gelesen und sofort geschrieben, sodass der Speicherbedarf nicht mit der Tabellengröße wächst. - Binärwerte werden als `0x…`-Literal geschrieben, damit der Dump gültiges ASCII bleibt. - Views werden als Struktur gesichert, aber nicht mit Daten. - Der Dump ist **nicht** transaktional konsistent. Für eine Anwendung mit gleichzeitigem Schreibverkehr sollte das Backup in einer ruhigen Zeit laufen. Wiederherstellung von Hand: ```bash unzip -p backup-20260820-092104.zip database/meinprojekt.sql | mysql meinprojekt ``` ## Kompression `MANAGE_BACKUP_COMPRESS` (Standard `true`) schaltet Deflate ein. Der Unterschied ist bei SQL-Dumps und JSON groß, bei bereits komprimierten Bildern praktisch null. Fehlt zlib, schreibt der Client unkomprimiert weiter statt abzubrechen. Grenzen des ZIP-Formats ohne Zip64: 4 GB pro Datei, 4 GB pro Archiv, 65535 Einträge. Wird eine Grenze überschritten, bricht das Backup mit einer klaren Meldung ab. ## Ziele ### Manage-Server Standardziel, aktiv über `MANAGE_BACKUP_UPLOAD` (Standard `true`). Konfiguriert wird nichts weiter: Es gelten `MANAGE_SERVER_URL`, `MANAGE_INSTANCE` und `MANAGE_TOKEN`. Der Server prüft die mitgesendete Prüfsumme erneut und lehnt abweichende Uploads ab. Für rein lokale Backups: ```php define("MANAGE_BACKUP_UPLOAD", false); ``` ### Zusätzliche Ziele Jedes Ziel wird unabhängig versucht. Ein Fehlschlag macht weder das lokale Archiv noch die anderen Ziele ungültig. S3-kompatibler Speicher: ```php define("MANAGE_BACKUP_REMOTE_TARGETS", [ [ "name" => "S3 Archiv", "type" => "s3", "bucket" => "example-bucket", "region" => "eu-central-1", "prefix" => "meinprojekt", "access_key" => "AKIA…", "secret_key" => "…", // Für S3-kompatible Anbieter: // "endpoint" => "https://fsn1.your-objectstorage.com", ], ]); ``` Signiert wird mit AWS Signature V4 über normale PHP-HTTPS-Streams; eine Bibliothek wird nicht benötigt. Das Archiv wird für die Signatur vollständig in den Speicher geladen – ein Backup größer als `memory_limit` kann dieses Ziel nicht nutzen. SFTP (benötigt die PHP-Erweiterung `ssh2`): ```php [ "name" => "SFTP Backup", "type" => "sftp", "host" => "backup.example.org", "port" => 22, "username" => "backup-user", "password" => "…", "path" => "/backups/meinprojekt", ] ``` Mit Schlüssel statt Passwort: ```php [ "type" => "sftp", "host" => "backup.example.org", "username" => "backup-user", "public_key" => "/pfad/zu/backup.pub", "private_key" => "/pfad/zu/backup", "password" => "", // Passphrase des Schlüssels, sonst leer "path" => "/backups/meinprojekt", ] ``` Das Zielverzeichnis muss existieren und beschreibbar sein; es wird nicht angelegt. Eigener Uploader: ```php [ "name" => "Eigenes Ziel", "type" => "custom", "file" => MANAGE_APP_ROOT . "/includes/backup-uploader.php", "callback" => "myProjectUploadBackup", ] ``` ```php function myProjectUploadBackup(string $archivePath, array $metadata, array $target) { // $metadata: filename, created_at, trigger, sha256, file_count, source_bytes // Erfolg: true oder ein Array zurückgeben. // Fehler: Exception werfen oder ["success" => false, "error" => "…"]. return ["remote_path" => "…"]; } ``` ## Protokollierung und Geheimnisse Fehlgeschlagene Uploads werden mit HTTP-Status und Antwortauszug protokolliert. Zugangsdaten sind davon ausgenommen: Aus der Zielkonfiguration wird nur eine Positivliste unkritischer Schlüssel übernommen (`name`, `type`, `url`, `bucket`, `region`, `prefix`, `endpoint`, `host`, `port`, `username`, `path`, `file`, `callback`, `timeout`). `access_key`, `secret_key` und `password` erscheinen nie im Protokoll. ## Weiter - [04_FUNCTION_API](04_FUNCTION_API.md) – `manageBackupCreate()` und Rückgabewerte - [09_TROUBLESHOOTING](09_TROUBLESHOOTING.md) – Fehlermeldungen beim Backup