Skip to content

Releases: malziland/Seafile-Updraft-Backup-Uploader

v1.0.7 — Worker-Crash-Notbremse gegen 17h-Resume-Loops

25 May 10:07

Choose a tag to compare

Fix: Worker-Crash-Notbremse

Verhindert, dass ein einzelner Chunk, der den PHP-Prozess wiederholt killt, die gesamte Upload-Queue stundenlang blockiert.

Konkret beobachtet in Produktion: eine 172 MB große uploads.zip blieb wiederholt bei genau 120 MB stehen (PHP-Prozess wurde vom Hoster mitten im Chunk-PUT abgeschossen), Resume nahm korrekt bei 120 MB wieder auf — und starb dort sofort wieder. 17,8 Stunden verschwendet, bis der Queue-Gesamttimeout griff. Die nachfolgende wpcore.zip wurde nie hochgeladen.

Neue dreistufige Eskalation

  1. Erster Crash → Retry mit exponentiellem Backoff (bestand schon).
  2. Zweiter Crash am selben Byte → Chunk-Größe für diese eine Datei wird automatisch halbiert (per-File-Override, Untergrenze 4 MiB). Andere Dateien der Queue bleiben unberührt.
  3. Chunk schon am Floor und immer noch derselbe Crash, oder >5 Crash-Wiederaufnahmen pro Datei → Datei als Fehler markiert, die Queue läuft mit den nächsten Dateien weiter. Besser eine fehlgeschlagene Datei als ein 17-h-Stillstand der gesamten Backup-Übertragung.

Diagnose im Aktivitätsprotokoll

Zwei neue Log-Einträge machen die Eskalation sichtbar:

  • WARNUNG: Worker still abgestürzt vor X min an gleicher Stelle — Chunk-Größe auf Y MB reduziert, Wiederaufnahme bei …
  • FEHLER: Datei nach wiederholten Worker-Abstürzen übersprungen: … — Queue läuft mit den nächsten Dateien weiter

Tests

Drei neue Unit-Tests in CrashDetectionGateTest (Retry-Cap-Skip, Same-Offset-Chunk-Halbierung, Floor-erreicht-Skip). 123 Tests / 343 Assertions grün, PHPStan ohne Befund.

Installation

Zip herunterladen und über WP-Admin → Plugins → Neu hinzufügen → Plugin hochladen installieren oder aktualisieren. Keine Migration nötig.

Vollständige Änderungsliste siehe CHANGELOG.md.

v1.0.6 — Einzeldatei-Download entfernen (UI-Aufräumen)

19 Apr 12:00

Choose a tag to compare

Was sich ändert

Der Einzeldatei-Download-Button im „Dateien anzeigen"-Panel ist weg. Das Panel zeigt jetzt nur noch Dateiname und Größe — eine reine Inhaltsliste ohne Aktionen.

Warum

Der Button hieß „Download", triggerte aber keinen Browser-Download:

  • Serverseitige Kopie statt Browser-Download. SBU_Plugin::ajax_download() lud die Datei von Seafile in den lokalen wp-content/updraft/-Ordner. Der Browser zeigte keinen Download-Balken, weil nichts zum Browser geschickt wurde.
  • Erfolgsmeldung außerhalb des Sichtfelds. Die Meldung „In UpdraftPlus auf 'Lokalen Ordner neu scannen' klicken" landete im gemeinsam genutzten #sr-Statusfeld zwei Panels höher — bei gescrollter Seite schlicht nicht sichtbar. Das erzeugte den „nichts passiert"-Eindruck.
  • Confirm-Dialog ohne Erklärung. confirm(f) fragte nur den rohen Dateinamen (z. B. backup_2026-04-17-1630_INTERIORISTA_1d2b1dcea52d-db.gz) ab, ohne zu sagen, was OK auslöst.

Warum entfernt statt repariert

  • Kein realistischer Use-Case. UpdraftPlus-Chunks (uploads7.zip, uploads14.zip, …) sind semantisch undurchsichtig — eine einzelne Datei aus dem Set ist ohne Kontext nicht restore-fähig.
  • „Wiederherstellen" deckt den Restore-Fall ab. Der bestehende Restore-Pfad erkennt „Teilweise lokal"-Sets und zieht genau die fehlenden Dateien nach — gezielter Re-Download ist also schon drin.
  • Seafile-Weboberfläche deckt den Inspektions-Fall ab. Wer eine einzelne .gz außerhalb von WordPress untersuchen will, lädt sie direkt aus der Seafile-Weboberfläche.

Aufgeräumt (tote Code-Pfade)

  • SBU_Plugin::ajax_download() — Handler vollständig entfernt.
  • 'download' aus der AJAX-Hook-Registrierung — wp_ajax_sbu_download ist weg.
  • SBU_Seafile_API::download_file() — nur von ajax_download() gerufen, jetzt tot, raus.
  • SBU_Seafile_API::DEFAULT_DOWNLOAD_CHUNK — nur von download_file() referenziert, raus.
  • window.sDl + 'download-file'-Event-Delegation-Eintrag in admin.js — raus.
  • <button data-sbu-action=\"download-file\"> in SBU_Plugin::ajax_list() — raus.

Der im Restore-Flow aktive Download-Pfad (download_whole_file_stream + download_chunks_parallel) bleibt unverändert.

Migration

Keine. Einstellungen, Queue-State und Protokoll-Einträge bleiben intakt. Upload über Plugins → Hochladen in WP-Admin.

Tests

121 Tests / 333 Assertions — unverändert. PHPCS, PHPStan Level 5 und PHPUnit 11 grün auf PHP 8.2 / 8.3 / 8.4.

v1.0.5 — Breaking: PHP 8.2 + PHPUnit 11 + erweiterte Testsuite

19 Apr 11:49

Choose a tag to compare

Breaking

  • PHP-Mindestanforderung 7.4 → 8.2. Plugin-Header, composer.json und readme.txt sind jetzt konsistent auf 8.2. WordPress blockiert die Aktivierung auf älteren PHP-Versionen mit eigenem Hinweis. Supporte PHP-Matrix: 8.2 / 8.3 / 8.4 (alle drei in CI getestet). Vor dem Update die PHP-Version des Hosts prüfen.

Geändert

  • PHPUnit 9.6 → 11.5. Alle 12 bestehenden Test-Dateien von @covers-Docblocks auf PHP-8-Attribute (#[CoversClass] / #[CoversMethod]) migriert — null Deprecations mehr.
  • CI-Matrix auf PHP 8.2 / 8.3 / 8.4 umgestellt.

Hinzugefügt

  • tests/unit/SeafileApiTest.php — 17 HTTP-gemockte Tests für SBU_Seafile_API (Token-Cache, Library-Resolve, Upload-/Download-Link, Directory-Ops).
  • tests/unit/LogSanitizerTest.php — 12 Tests für den anonymisierten Log-Export (Host-, UUID-, Ordner-, E-Mail-, IP-, Nonce-Maskierung) plus End-zu-End-Leak-Check.
  • Neue Screenshots für readme.txt und README.md: Einstellungsseite (Backup-Browser + Aktivitätsprotokoll) und Dashboard-Widget mit Demo-Daten.

Dokumentation

  • README.md, ARCHITECTURE.md, CONTRIBUTING.md auf den aktuellen Code-Stand gezogen: Modul-Boundaries-Tabelle, Test-Surface-Tabelle, reproduzierbarer Release-Workflow (rsync + zip), explizite Quality-Gate-Befehle.

Tests

121 Tests / 333 Assertions (vorher 92 / 263). PHPCS (WordPress-Standard, Plugin-Source), PHPStan Level 5 und PHPUnit 11 grün auf PHP 8.2 / 8.3 / 8.4.

Upgrade-Hinweis

Vor dem Update die PHP-Version des Hosts prüfen (mindestens 8.2). Danach keine manuelle Migration nötig — Upload über Plugins → Hochladen in WP-Admin.

v1.0.4 — ARCH-001 abgeschlossen

19 Apr 11:12

Choose a tag to compare

ARCH-001 ist mit diesem Release komplett durch: die beiden letzten Monolith-Fragmente sind raus aus der God-Class. Reines Refactoring, Verhalten 1:1, 92 PHPUnit-Tests / 263 Assertions grün.

Refaktoriert

  • Schritt 4 — SBU_Admin_Ajax als Trait — alle 24 Ajax-Handler (Verbindungstest, Upload-/Restore-Queue-Kontrolle, Backup-Liste, Download-Stream, Log-Export, Settings-Autosave, Cron-Endpoints) liegen jetzt in includes/trait-sbu-admin-ajax.php. Trait-Komposition zur Compile-Zeit hält die Zugriffe auf private Plugin-Helfer (verify_ajax_request, get_picker_credentials, format_progress, sanitize_path_segment …) intakt — keine Visibility-Promotion, keine fragile Plugin-Referenz.
  • Schritt 5 — SBU_Upload_Flow + SBU_Restore_Flow als Traits — der komplette Upload-Lebenszyklus (on_backup_complete, create_upload_queue, process_queue_tick, upload_one_chunk, finish_queue, verify_backup, persist_backup_hashes, enforce_retention, cleanup_updraft_history, find_backup_files, extract_backup_nonce) wohnt in includes/trait-sbu-upload-flow.php. Der Restore-Lebenszyklus (verify_restored_file, process_restore_tick) in includes/trait-sbu-restore-flow.php. Gemeinsame Helfer (safe_queue_update, detect_worker_crash_and_defer, maybe_notify_stall, get_adaptive_limits, tick_budget_exhausted, is_aborted, log_failed_files, get_updraft_dir, get_memory_limit) bleiben in SBU_Plugin, weil beide Flows sie brauchen.
  • SBU_Plugin jetzt ~1100 Zeilen — von ursprünglich 4201 Zeilen (−74 %). Die Klasse ist wieder als Koordinationslayer lesbar: Settings, Admin-UI, Cron-Auth, Tick-Sizing, Queue-Lifecycle-Helfer, Trait-Komposition.

Geändert

  • SBU_Queue_Engine::tick_is_gated() als @phpstan-impure markiert — die Methode liest SBU_QUEUE bei jedem Aufruf frisch via wp_cache_delete. PHPStan hielt wiederholte Aufrufe nach der Trait-Komposition für redundant (if.alwaysTrue in ajax_cron_ping). Der Analyzer kannte die Mutations-Semantik nicht; die Annotation dokumentiert sie.

Tests & Qualität

  • 92 PHPUnit-Tests / 263 Assertions — alle grün.
  • PHPCS (WordPress-Standard, Plugin-Source) sauber.
  • PHPStan Level 5 sauber.
  • Keine Test-Anpassungen nötig — Traits komponieren zur Compile-Zeit in SBU_Plugin, die bestehenden SBU_Plugin::*-Referenzen in den Tests funktionieren unverändert.

Upgrade Notice

Reines Refactoring, keine Migration nötig. Download-Asset: seafile-updraft-backup-uploader-1.0.4.zip.

v1.0.3 — Cron-Key-Header, Brute-Force-Schutz, ARCH-001 Schritte 1-3

19 Apr 10:39

Choose a tag to compare

Zweiter Audit-Durchgang: UI-Feinschliff, Härtung des internen Cron-Pfads, drei Services aus der God-Class rausgezogen.

Sicherheit

  • Cron-Key im Header statt im POST-Body — der interne Loopback-Spawn sendet den Schlüssel jetzt über den X-SBU-Cron-Key-Header. Er taucht damit nicht mehr in Debug-/Error-Tracker-Dumps auf, die Request-Bodies mitloggen. Rückwärtskompatibel: der Empfänger prüft weiterhin Header, Query-Param und Body in dieser Reihenfolge.
  • Brute-Force-Signal im Aktivitätsprotokoll — fünf ungültige Versuche innerhalb einer Stunde lösen einmalig eine WARNUNG-Zeile aus (1-Stunden-Transient als Zähler). Vorher: stumme 403s.

UI

  • Status-Pillen zentriertLokal vollständig / Teilweise lokal / Nur remote und der Verify-Status sitzen jetzt auf einer sauberen Baseline statt treppenartig versetzt. Fix im Flex-Layout: align-items:center statt baseline.
  • 24 weitere Inline-onclick entfernt — die Buttons in der Backup-Liste nutzen jetzt ebenfalls data-sbu-action. Kombiniert mit 1.0.2 ist das Plugin damit vollständig inline-JavaScript-frei.

Betrieb

  • Zero-Traffic-Backstop für das Log-Pruning — zusätzlich zum täglichen WP-Cron räumt die Retention jetzt auch beim ersten admin_init pro Admin-Zugriff auf. Idle-Sites bleiben im Retention-Fenster.

Refaktoriert (ARCH-001 Schritte 1–3)

  • SBU_Activity_Log als eigene Klasse (Log-Schreiben, Retention, Cron, Render). 77 Aufrufstellen umgestellt, Verhalten identisch.
  • SBU_Mail_Notifier als eigene Klasse (Admin-Mails Erfolg/Fehler/Stillstand).
  • SBU_Queue_Engine als eigene Klasse (atomares Lock, Lock-TTL, Gate-Check, Loopback-Spawn, WP-Cron-Scheduling).

Konstruktor-DI via Callables, damit die Services nicht auf SBU_Plugin koppeln.

Schritte 4 + 5 verschoben auf v1.0.4 — die Ajax-Controller-Extraktion (24 Handler) und die Upload-/Restore-Flow-Trennung brauchen einen isolierten Release, damit Regressions-Risiken in produktiven Backup-Pfaden gezielt reviewbar bleiben.

Tests

92 PHPUnit-Tests / 263 Assertions — alle grün. PHPCS (WordPress-Standard) und PHPStan (Level 5) sauber.


Installation: seafile-updraft-backup-uploader-1.0.3.zip herunterladen → WordPress → Plugins → Plugin hochladen.

v1.0.2 — Audit-Umsetzung (Datenschutz, Wartbarkeit, CI)

19 Apr 09:45

Choose a tag to compare

Audit-Umsetzung: Datenschutz, Wartbarkeit, CI-Schärfe.

Hinzugefügt

  • Zeit-basierte Aufbewahrung für das Aktivitätsprotokoll (Default 30 Tage, konfigurierbar 7–365 Tage oder 0 = deaktiviert). Alte Einträge werden einmal täglich per Cron und opportunistisch beim Schreiben gelöscht. Das bisherige Zeilen-Limit (500 Zeilen) bleibt als zusätzliche Obergrenze erhalten.
  • Warn-Header im Log-Export (unmaskierte Variante) weist jetzt unübersehbar darauf hin, dass der Export identifizierende Daten (Host, Bibliothek, Pfade, E-Mail) enthält — für Support-Weitergabe wird „Anonymisiert exportieren" empfohlen.
  • Neue Einstellung „Aktivitätsprotokoll aufbewahren" auf der Plugin-Seite mit Laien-Erklärung (Standard-Empfehlung 30 Tage, Hinweis auf DSGVO-Datensparsamkeit).
  • 5 neue Unit-Tests für die Retention-Logik.

Geändert

  • Inline-onclick-Handler aus dem Admin-Template entfernt — 9 Buttons nutzen jetzt data-sbu-action-Attribute, ein zentraler Event-Delegate in admin.js routet auf die Funktionen. Erleichtert künftige Wartung und strengere Content-Security-Policies.
  • CI-Pipeline scharf gestellt — PHPCS und PHPStan brechen den Build jetzt bei Fehlern ab (vorher mit || true maskiert). PHPStan läuft mit --memory-limit=2G.
  • Ein Code-Review-Durchlauf mit echten Bugfixes: wp_unslash() vor sanitize_path_segment() in Ajax-Download/Delete, gecachte count()-Aufrufe, translators-Kommentare für komplexe i18n-Strings, Parameter-Rename.

Sicherheit

  • Retention-Clamp gegen Panik-Eingaben — Werte zwischen 1 und 6 Tagen werden automatisch auf 7 angehoben, damit ein Fehlklick im Admin das Protokoll nicht in einem Tick vollständig leert. 0 bleibt als explizite Deaktivierung.
  • Datenminimierung im Default-Fall — Aktivitätsprotokoll-Einträge älter als 30 Tage werden ohne weitere Konfiguration entfernt. Unterstützt die DSGVO-Forderung nach Datensparsamkeit.

Tests

92 PHPUnit-Tests / 263 Assertions, alle grün. PHPCS (WordPress-Standard) und PHPStan (Level 5) sauber.

Upgrade

Keine Migration nötig. Aktivitätsprotokoll wird automatisch nach 30 Tagen aufgeräumt (konfigurierbar).

v1.0.1 — UI-Politur der Einstellungsseite

18 Apr 18:12

Choose a tag to compare

Kleine Optik-Release, keine Code-Logik geändert.

Geändert

  • Integritätsprüfungs-Hinweis verschoben — aus dem Einstellungsblock (wo er neben Checkboxen keinen Mehrwert hatte) in den Erklär-Bereich „So funktioniert das Plugin". Dort jetzt als eigener hervorgehobener Absatz mit grünem Rand und 🔒-Icon, direkt unter der Upload/Restore-Zweispaltigkeit.
  • Toolbar im Aktivitätsprotokoll aufgeräumt — Filter-Dropdown und die drei Aktions-Buttons (Export / Anonymisiert exportieren / Log leeren) sind jetzt in zwei Flex-Gruppen aufgeteilt. Auf schmalen Bildschirmen (< 600 px) stapeln die Gruppen sauber untereinander, Buttons teilen sich die Breite gleichmäßig — kein chaotisches Umbrechen mehr mitten in den Buttons.

Upgrade

Drop-in. Kein Migrations-Aufwand, keine neuen Settings, keine Datenbank-Änderungen. 87 Tests / 257 Assertions weiterhin grün.

v1.0.0 — Erste öffentliche Version

18 Apr 18:03

Choose a tag to compare

Erste öffentliche Version des Seafile Updraft Backup Uploader.

Das Plugin koppelt UpdraftPlus an einen selbst gehosteten Seafile-Server über die native Seafile-Upload-API — nicht über WebDAV. Das ist notwendig, weil WebDAV auf Seafile keine Chunked Uploads unterstützt: Dateien größer als das Reverse-Proxy-Limit (etwa 100 MB bei Cloudflare Tunnel Free Tier) lassen sich über WebDAV schlicht nicht hochladen.

Funktionsumfang

  • Chunked Upload (Default 40 MB, konfigurierbar 5–90 MB) — bypasst 100-MB-Reverse-Proxy-Limits. Bei Fehler wird nur der fehlgeschlagene Chunk wiederholt.
  • Stream-First-Restore — Downloads nutzen zuerst denselben Pfad wie die Seafile-Web-Oberfläche (ein HTTP-GET ohne Range-Header). Für Dateien über 500 MB oder bei Stream-Fehlern fällt das Plugin automatisch auf parallele Range-Chunks zurück.
  • Adaptive Konfiguration ohne Einstellungen — Tick-Länge, Parallelität und Chunk-Größe werden beim Restore automatisch aus max_execution_time und memory_limit berechnet.
  • Exponentielles Backoff mit zwei Kurven — unterscheidet zwischen leeren Server-Antworten (Backend kalt) und echten Transportfehlern (Netz wackelt). Obergrenze 1 Stunde.
  • AIMD-Rate-Controller — Chunk-Größe und Parallelität schrumpfen nach Fehlern und wachsen gestaffelt zurück.
  • Stillstand-Meldung per Mail ohne Abbruch — bei 1 h Stillstand geht eine Info-Mail raus, Folge-Mails alle 4 h. Die Queue läuft weiter.
  • Integritätsprüfung ohne Extra-Bandbreite — beim Upload wird pro Datei streamend eine SHA1-Prüfsumme berechnet; beim Restore aus dem Download-Stream verglichen.
  • Pause & Resume — Uploads und Restores lassen sich an exakt derselben Byte-Position fortsetzen.
  • Zero-Traffic-Betrieb — läuft ohne Besucher, ohne WP-Cron-Dependency, ohne externe Dienste. Interner WordPress-Loopback zieht jeden Tick nach.
  • Optionaler externer Heartbeat — schlüsselgeschützte Ping-URL mit Crontab-Beispiel für Umgebungen, die Loopbacks blockieren.
  • Lokal-Status-Badges im Backup-Browser — „Lokal vollständig / Teilweise lokal / Nur remote". Bei vollständig lokalem Set wird der Wiederherstellen-Button durch „In UpdraftPlus öffnen" ersetzt.
  • Erfolgs-Banner nach Restore mit UpdraftPlus-Deeplink.
  • Anonymisierter Log-Export — Host, Library-ID, Ordnerpfad, E-Mails, IPs und UUIDs werden maskiert.
  • Dashboard-Widget, E-Mail-Benachrichtigungen, Retention-Management (Default 4, 0 = alle behalten).
  • AES-256-CBC Passwortverschlüsselung mit zufälligem IV.
  • Mehrsprachig (Deutsch + Englisch, über WordPress-Locale).

Anforderungen

  • WordPress 6.0+
  • PHP 7.4+
  • UpdraftPlus (Free oder Premium)
  • Ein Seafile-Server (self-hosted oder Cloud)

Installation

  1. seafile-updraft-backup-uploader_1.0.0.zip aus den Release-Assets herunterladen.
  2. In WordPress unter Plugins → Installieren → Plugin hochladen einspielen und aktivieren.
  3. Einstellungen → Seafile Backup öffnen, Seafile-URL, Zugangsdaten, Bibliothek und Unterordner eintragen, „Verbindung testen" klicken.
  4. In UpdraftPlus den Remote-Speicher auf „Keine" setzen — dieses Plugin übernimmt den Upload.

Tests

87 PHPUnit-Tests / 257 Assertions, alle grün.