# Funktions-API ## Überblick Alle Funktionen stehen nach einem einzigen `require` zur Verfügung: ```php require_once __DIR__ . "/manage-client/lib/client.php"; ``` Die Kommandozeile (`bin/manage-client.php`) und die Oberfläche (`ui/panel.php`) enthalten **keine eigene Logik**, sondern rufen genau diese Funktionen auf. Eine Funktion verhält sich deshalb identisch, egal wie sie ausgelöst wird. Fehler werden als `RuntimeException` geworfen. Ausnahmen von dieser Regel sind ausdrücklich vermerkt. ## Status ### `manageClientStatus(): array` Sammelaufruf für Oberflächen. **Wirft nie**: Jeder Fehler landet im Rückgabewert, damit eine Einstellungsseite auch bei nicht erreichbarem Server rendert. ```php [ "instance" => "mein-projekt-prod", "server_url" => "https://manage.example.org", "configured" => true, "version" => "v1.2.3", // "" wenn nicht ermittelbar "php_version" => "8.3.6", "update" => [...], // Rückgabe von manageUpdateCheck(), oder null "update_error" => null, // Fehlermeldung, wenn die Prüfung scheiterte "backups" => [...], // Rückgabe von manageBackupList() "last_backup_at" => "2026-08-20T09:21:04+00:00", "pending_migrations" => [...], "errors" => [], // nicht-fatale Warnungen ] ``` ### `manageClientVersion(): string` Installierte Version, zum Beispiel `"v1.2.3"`. Gibt `""` zurück, wenn sie nicht ermittelbar ist; das ist kein Fehler, sondern "unbekannt". ### `manageClientConfigured(): bool` Ob Server-URL, Instanz und Token gesetzt sind. ## Update ### `manageUpdateCheck(): array` Holt das Manifest und vergleicht die Versionen. ```php [ "current" => "v1.2.3", "latest" => "v1.3.0", "available" => true, "manifest" => [ "version" => "v1.3.0", "package_url" => "https://…/api/v1/package.php?version=v1.3.0", "sha256" => "…", "size" => 421337, "published_at" => "2026-08-20T09:20:43+00:00", ], ] ``` Ist die installierte Version unbekannt, gilt `available => true`, damit eine Installation ohne lesbare Versionsdatei nicht dauerhaft blockiert. ### `manageUpdateApply(array $options = []): array` Lädt das Paket, prüft Größe und SHA-256, entpackt es, rollt es aus und führt anschließend den Post-Update-Schritt aus. Optionen: | Option | Bedeutung | |---|---| | `force` | Auch ausrollen, wenn keine neuere Version vorliegt | | `skip_hook` | Nur Dateien ausrollen, weder Migrationen noch Callback ausführen | Rückgabe: ```php [ "deployed" => true, "from_version" => "v1.2.3", "to_version" => "v1.3.0", "copied" => 128, "backed_up" => 126, "skipped" => 2, // geschützte Pfade "removed_backups" => 1, "backup_dir" => "/…/data/manage/updates/20260820-092114-v1.3.0", "hook" => [...], // siehe unten ] ``` Wirft, wenn das **Ausrollen** scheitert. Scheitert nur der Post-Update-Schritt, kehrt die Funktion normal zurück und `hook["success"]` ist `false` – die Dateien sind dann bereits ausgerollt. Aufrufer müssen beides unterscheiden; siehe [07_POST_UPDATE_HOOKS](07_POST_UPDATE_HOOKS.md). Wichtig: Das Ausrollen überschreibt Dateien im laufenden Betrieb. Es gibt keine Wartungsseite und keine Rücknahme. Die überschriebenen Dateien liegen als Kopie in `backup_dir`, aber ausschließlich für die manuelle Wiederherstellung. ### `manageUpdatePendingMigrations(): array` Noch nicht ausgeführte Migrationen in Ausführungsreihenfolge: ```php [["id" => "2026-08-20-01-add-index", "path" => "/…/migrations/2026-08-20-01-add-index.php"]] ``` ### `manageUpdateRunMigrations(array $context = []): array` Führt die offenen Migrationen aus. **Wirft nicht**, sondern meldet: ```php [ "success" => false, "applied" => ["2026-08-20-01-add-index"], "failed" => "2026-08-20-02-backfill", "error" => "SQLSTATE[42S22]: …", "pending" => 2, // inklusive der fehlgeschlagenen ] ``` ## Backup ### `manageBackupCreate(string $trigger = "manual"): array` Erstellt ein lokales Archiv und lädt es hoch, sofern `MANAGE_BACKUP_UPLOAD` aktiv ist. `$trigger` ist frei wählbar; üblich sind `manual`, `automatic`, `cron`, `update`. Nur `automatic` und `cron` zählen für die Intervallprüfung. ```php [ "filename" => "backup-20260820-092104.zip", "created_at" => "2026-08-20T09:21:04+00:00", "trigger" => "cron", "size" => 427, "file_count" => 3, "source_bytes" => 63, "sha256" => "…", "app_version" => "v1.2.3", "database" => null, // oder ["tables" => 12, "rows" => 4711, …] "remote_uploads" => [ ["target" => "Manage-Server", "type" => "manage", "success" => true, …], ], ] ``` Ein fehlgeschlagener Upload macht das lokale Archiv **nicht** ungültig: Der Fehler steht in `remote_uploads[].error` und im Protokoll, die Funktion wirft nicht. Wirft sie doch, ist das Archiv selbst nicht zustande gekommen. Gleichzeitige Läufe werden über eine Sperrdatei verhindert; der zweite Lauf wirft sofort `Es läuft bereits ein Backup.` ### `manageBackupCreateAutomaticIfDue(): ?array` Erstellt ein Backup, wenn seit dem letzten automatischen Backup `MANAGE_BACKUP_AUTO_INTERVAL_SECONDS` vergangen sind, sonst `null`. Für Hosting ohne Cron gedacht; gehört auf eine selten geladene Adminseite. ### `manageBackupList(): array` Lokale Archive, neuestes zuerst. Selbstheilend: Einträge ohne Datei werden entfernt, Größen werden von der Festplatte aktualisiert. ### `manageBackupUpload(string $archivePath, array $meta = []): array` Lädt ein vorhandenes Archiv zum Manage-Server. Wird von `manageBackupCreate()` automatisch aufgerufen und ist nur für Sonderfälle einzeln nötig – etwa um ein Archiv nach einem Serverausfall nachzureichen. ### `manageBackupPath(string $filename): string` Absoluter Pfad eines lokalen Archivs. Validiert den Dateinamen streng, damit ein Download-Formular keinen beliebigen Pfad ausliefern kann. ## Heartbeat ### `manageHeartbeatSend(): array` Meldet Version, PHP-Version, freien Speicher, offene Migrationen und den Zeitpunkt des letzten Backups. Die Antwort enthält nebenbei die Update-Information: ```php ["success" => true, "latest" => "v1.3.0", "update_available" => true, "server_time" => "…"] ``` ### `manageHeartbeatSendQuietly(): ?array` Wie oben, wirft aber nie und gibt bei Fehlern `null` zurück. Für Aufrufe innerhalb des Projekts, in denen ein nicht erreichbarer Server folgenlos bleiben soll. ## Hilfsfunktionen | Funktion | Zweck | |---|---| | `manageFormatBytes(int $bytes): string` | `1.234.567` → `1,18 MB` | | `manageClientLog(string $level, string $message, array $context = []): void` | Eine Zeile ins Client-Protokoll. Wirft nie | | `manageRemoteCapabilities(): array` | Welche konfigurierten Zieltypen dieses System unterstützt | ## Beispiel ```php require_once __DIR__ . "/manage-client/lib/client.php"; $check = manageUpdateCheck(); if ($check["available"]) { manageBackupCreate("update"); // vor dem Update sichern $result = manageUpdateApply(); if (!$result["hook"]["success"]) { // Dateien sind ausgerollt, der Post-Update-Schritt nicht. error_log("Migration fehlgeschlagen: " . $result["hook"]["error"]); } } ``` Ein Backup vor dem Update ist bewusst **nicht** eingebaut, sondern eine Zeile im Projekt – so bleibt sichtbar, dass es passiert.