# Backup Sources and Targets ## Overview What gets backed up lives in `MANAGE_BACKUP_SOURCES`. A MySQL dump can be added optionally. Where it gets backed up to is controlled by `MANAGE_BACKUP_UPLOAD` and `MANAGE_BACKUP_REMOTE_TARGETS`. Relevant files: - `manage-client/lib/backup.php` – collecting, archiving, retention, upload - `manage-client/lib/zip.php` – ZIP creation without an external library - `manage-client/lib/mysql.php` – optional database dump - `manage-client/lib/remote.php` – extra targets ## Declaring sources All paths are relative to `MANAGE_APP_ROOT`. Every entry uses exactly one of three forms: ```php define("MANAGE_BACKUP_SOURCES", [ // Non-recursive glob pattern ["as" => "data", "glob" => "data/*.json"], // Directory, recursive ["as" => "data/uploads", "dir" => "data/uploads"], // Single file ["as" => "config", "file" => "config.dist.php"], ]); ``` `as` is the prefix inside the archive. Without `as`, the entry lands at the top level — for `dir`, the directory name is used as the prefix. The example above produces: ```text data/orders.json data/settings.json data/uploads/2026/image.jpg config/config.dist.php ``` ### What gets skipped automatically - files whose name starts with a dot - files with the extensions `.tmp` and `.part` - unreadable files If two sources produce the same archive path, the first one wins. An archive never contains two entries with the same name. ### What does **not** belong in it - `config.php` with real credentials — a backup gets transferred to the server and downloaded there; see [10_SECURITY](10_SECURITY.md) - the backup directory itself - logs and cache directories - the application files: those come from the release package, not from the backup A backup secures **operational data**, not a complete system image. ## Database dump Only active when `MANAGE_BACKUP_DATABASE` is set: ```php define("MANAGE_BACKUP_DATABASE", [ "dsn" => "mysql:host=localhost;dbname=myproject;charset=utf8mb4", "user" => "myproject", "password" => "…", // Optional: back up only the structure of these tables, not their rows. "skip_data_tables" => ["sessions", "cache"], // Optional: name inside the archive, if SELECT DATABASE() returns nothing. "name" => "myproject", ]); ``` The dump lands in the archive as `database/.sql` and contains, for every table, `DROP TABLE IF EXISTS`, the `CREATE TABLE` from `SHOW CREATE TABLE`, and the rows as individual `INSERT` statements. `SET FOREIGN_KEY_CHECKS=0` sits at the top, set back to `1` at the end. Properties and limits: - PDO only, no `mysqldump` call — on many shared hosts that's the only option available, but it only works for MySQL and MariaDB. - Rows are read in blocks of 500 and written immediately, so memory use doesn't grow with table size. - Binary values are written as `0x…` literals, so the dump stays valid ASCII. - Views are backed up as structure, but without data. - The dump is **not** transactionally consistent. For an application with concurrent writes, the backup should run during a quiet period. Manual restore: ```bash unzip -p backup-20260820-092104.zip database/myproject.sql | mysql myproject ``` ## Compression `MANAGE_BACKUP_COMPRESS` (default `true`) turns on deflate. The difference is large for SQL dumps and JSON, practically zero for already-compressed images. If zlib is missing, the client keeps writing uncompressed instead of aborting. Limits of the ZIP format without Zip64: 4 GB per file, 4 GB per archive, 65535 entries. If a limit is exceeded, the backup aborts with a clear message. ## Targets ### Manage server Default target, active via `MANAGE_BACKUP_UPLOAD` (default `true`). Nothing else needs configuring: `MANAGE_SERVER_URL`, `MANAGE_INSTANCE` and `MANAGE_TOKEN` apply. The server re-checks the submitted checksum and rejects a mismatching upload. For purely local backups: ```php define("MANAGE_BACKUP_UPLOAD", false); ``` ### Extra targets Every target is attempted independently. A failure invalidates neither the local archive nor the other targets. S3-compatible storage: ```php define("MANAGE_BACKUP_REMOTE_TARGETS", [ [ "name" => "S3 Archive", "type" => "s3", "bucket" => "example-bucket", "region" => "eu-central-1", "prefix" => "myproject", "access_key" => "AKIA…", "secret_key" => "…", // For S3-compatible providers: // "endpoint" => "https://fsn1.your-objectstorage.com", ], ]); ``` Signing uses AWS Signature V4 over plain PHP HTTPS streams; no library is required. The archive is loaded fully into memory for signing — a backup larger than `memory_limit` cannot use this target. SFTP (needs the PHP `ssh2` extension): ```php [ "name" => "SFTP Backup", "type" => "sftp", "host" => "backup.example.org", "port" => 22, "username" => "backup-user", "password" => "…", "path" => "/backups/myproject", ] ``` With a key instead of a password: ```php [ "type" => "sftp", "host" => "backup.example.org", "username" => "backup-user", "public_key" => "/path/to/backup.pub", "private_key" => "/path/to/backup", "password" => "", // key passphrase, empty otherwise "path" => "/backups/myproject", ] ``` The target directory must exist and be writable; it is not created. Custom uploader: ```php [ "name" => "Custom Target", "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 // Success: return true or an array. // Failure: throw an exception, or return ["success" => false, "error" => "…"]. return ["remote_path" => "…"]; } ``` ## Logging and secrets Failed uploads are logged with HTTP status and a response excerpt. Credentials are excluded from that: only an allowlist of non-sensitive keys is taken from the target configuration (`name`, `type`, `url`, `bucket`, `region`, `prefix`, `endpoint`, `host`, `port`, `username`, `path`, `file`, `callback`, `timeout`). `access_key`, `secret_key` and `password` never appear in the log. ## Next - [04_FUNCTION_API](04_FUNCTION_API.md) – `manageBackupCreate()` and its return values - [09_TROUBLESHOOTING](09_TROUBLESHOOTING.md) – error messages during backup