xref: /plugin/sitebackup/README.md (revision b484d5bce5caf8c82fc4f2172009f85da67a1001)
18d8c8007Stracker-user# Site Backup plugin for DokuWiki
28d8c8007Stracker-user
38d8c8007Stracker-userAn admin plugin for [DokuWiki](https://www.dokuwiki.org/) that builds a `tar.gz` of selected wiki content and code, streams it to your browser, and deletes it from the server. Nothing persists on disk after the download finishes.
48d8c8007Stracker-user
58d8c8007Stracker-userBuilt for and tested against DokuWiki `2025-05-14b "Librarian"`.
68d8c8007Stracker-user
78d8c8007Stracker-user## Why another backup plugin?
88d8c8007Stracker-user
98d8c8007Stracker-userDokuWiki has the well-known [`backup`](https://www.dokuwiki.org/plugin:backup) plugin by Terence J. Grant, which solves the same problem. This plugin exists because:
108d8c8007Stracker-user
118d8c8007Stracker-user- **The archive is never left on the server.** The `backup` plugin writes the tar to `data/media/wiki/backup/` and relies on the admin correctly configuring an ACL on that namespace; the plugin page warns that "It is important to secure the backup namespace by ACLs otherwise your backup files can be downloaded by anyone". Site Backup instead writes to `data/tmp/` (which DokuWiki already protects with a deny-all `.htaccess`), with a random filename, and `unlink()`s the file as soon as the download completes (or the connection is aborted, or PHP crashes).
128d8c8007Stracker-user- **The upstream `backup` plugin's author [retired](https://www.freelists.org/post/dokuwiki/Fwd-Retiring-my-DW-plugins) and archived the repo in 2020.** It still works via DokuWiki's legacy class alias, but it's no longer maintained.
13*b484d5bcStracker-user- **Minimal footprint.** `admin.php` plus a small `PatchedTar.php` shim and language files for four locales (en, de, ru, ja). No external assets, no preference store. Easy to audit before installing on a wiki you share with other admins.
148d8c8007Stracker-user
158d8c8007Stracker-userIf you don't share the "ephemeral archive" requirement and you prefer something with a longer track record, the upstream `backup` plugin is a perfectly reasonable choice.
168d8c8007Stracker-user
178d8c8007Stracker-user## What it backs up
188d8c8007Stracker-user
198d8c8007Stracker-userEach option is an independent checkbox. The first three columns are usually all you want; the rest are situational.
208d8c8007Stracker-user
218d8c8007Stracker-user| Option | Path inside archive | Notes |
228d8c8007Stracker-user| --- | --- | --- |
238d8c8007Stracker-user| Pages | `data/pages/` | Current wiki text. |
248d8c8007Stracker-user| Media | `data/media/` | Uploaded files. |
258d8c8007Stracker-user| Page metadata | `data/meta/` | Last-edit, subscriptions, changelogs. |
268d8c8007Stracker-user| Media metadata | `data/media_meta/` | |
278d8c8007Stracker-user| Page revisions | `data/attic/` | Old versions of pages. Can be large. |
288d8c8007Stracker-user| Media revisions | `data/media_attic/` | |
298d8c8007Stracker-user| Search index | `data/index/` | Rebuildable; off by default. |
308d8c8007Stracker-user| Configuration | `conf/` | Includes secrets — see below. `*.dist`, `*.example`, `*.bak` are filtered. |
318d8c8007Stracker-user| Plugins source | `lib/plugins/` | Useful for capturing local modifications. |
328d8c8007Stracker-user| Templates source | `lib/tpl/` | |
338d8c8007Stracker-user
348d8c8007Stracker-userAlways excluded: `data/cache/`, `data/tmp/`, `data/locks/`, `data/log/`, `_dummy` placeholders, `.DS_Store`, `Thumbs.db`, and `.git` / `.svn` / `.hg` directories anywhere.
358d8c8007Stracker-user
368d8c8007Stracker-userTo restore from an archive, follow the standard DokuWiki procedure: install a fresh DokuWiki of the same version, then untar your backup over the install root, overwriting existing files. You should be able to log in immediately with your previous credentials.
378d8c8007Stracker-user
388d8c8007Stracker-user## Security model
398d8c8007Stracker-user
408d8c8007Stracker-user- **Admin-only.** DokuWiki's `AdminPlugin` framework enforces `auth_isadmin()` before `handle()` or `html()` is invoked, because the plugin declares `forAdminOnly()`. A second explicit check in the streaming method catches any framework bypass.
418d8c8007Stracker-user- **CSRF-protected.** Every action submission is validated with DokuWiki's `checkSecurityToken()`.
428d8c8007Stracker-user- **POST-only downloads.** The Download button submits as POST; GET / HEAD / pre-fetch requests are rejected. A stray link or curious co-admin pasting a URL cannot trigger a backup.
438d8c8007Stracker-user- **Random filename.** Temp archives are named `sitebackup_tmp_<16 hex chars>.tar.gz` — 64 bits of CSPRNG entropy.
448d8c8007Stracker-user- **Locked-down storage.** The archive is written to `$conf['tmpdir']` (default `data/tmp/`), which DokuWiki protects with a deny-all `.htaccess`. The file is `chmod 0600` immediately after creation, with a `umask(0077)` set during writes.
458d8c8007Stracker-user- **Auto-deleted.** The temp file is removed both at the end of the stream and via a `register_shutdown_function` callback, so it disappears even on connection abort or fatal PHP error.
468d8c8007Stracker-user- **Stale sweep.** Every page load deletes any leftover `sitebackup_tmp_*` files older than 1 hour, in case a previous run died before reaching its shutdown handler.
478d8c8007Stracker-user
488d8c8007Stracker-user**The archive itself is sensitive.** If you include `conf/`, it may contain password hashes (`conf/users.auth.php`), ACL rules, and any credentials stored in `conf/local.php` (DB connection strings, SMTP passwords, API keys). Treat the downloaded file the same way you would treat your wiki's credentials and delete it from your local machine when you're done.
498d8c8007Stracker-user
508d8c8007Stracker-user## Install
518d8c8007Stracker-user
528d8c8007Stracker-userIn your wiki:
538d8c8007Stracker-user
548d8c8007Stracker-user1. **Admin → Extension Manager → Manual Install**
558d8c8007Stracker-user2. Upload `sitebackup.zip`, click **Install**
568d8c8007Stracker-user3. Refresh the Admin page; a **Site Backup** entry appears in the Additional Plugins section
578d8c8007Stracker-user
588d8c8007Stracker-userOr extract the zip into `lib/plugins/sitebackup/` directly if you have file access.
598d8c8007Stracker-user
608d8c8007Stracker-user## Use
618d8c8007Stracker-user
628d8c8007Stracker-user1. Open **Site Backup** from the Admin menu.
638d8c8007Stracker-user2. Tick the components you want.
648d8c8007Stracker-user3. Click **Preview** to see the file list and total size per section.
658d8c8007Stracker-user4. Click **Download tar.gz** to receive the archive in your browser. The download filename is `<hostname>-backup-<timestamp>.tar.gz`; the same directory structure appears as a single top-level directory inside the archive.
668d8c8007Stracker-user
678d8c8007Stracker-userFor very large wikis where the request might time out, run two passes — for example, one without `attic`/`media_attic`, then a second pass with only those checked.
688d8c8007Stracker-user
698d8c8007Stracker-user## Uninstall
708d8c8007Stracker-user
718d8c8007Stracker-userSame path: **Admin → Extension Manager**, find **Site Backup** under Installed Extensions, click **Uninstall**.
728d8c8007Stracker-user
738d8c8007Stracker-user## Compatibility
748d8c8007Stracker-user
758d8c8007Stracker-userTested on DokuWiki `2025-05-14b "Librarian"`. Should work on Greebo / Hogfather / Igor / Jack Jackrum / Kaos as well — the only DokuWiki APIs used are `AdminPlugin`, `dokuwiki\Form\Form`, `auth_isadmin()`, `checkSecurityToken()`, `msg()`, and the bundled `splitbrain\PHPArchive\Tar`, all of which have been stable. No external dependencies; uses only what ships with DokuWiki.
768d8c8007Stracker-user
778d8c8007Stracker-userPHP 7.4 or newer (uses array destructuring in `foreach` and `??`).
788d8c8007Stracker-user
79a33f8e80Stracker-user## Notes on bundled patches
80a33f8e80Stracker-user
81a33f8e80Stracker-user`PatchedTar.php` is a 30-line subclass of `splitbrain\PHPArchive\Tar` that fixes a bug in the version of `splitbrain/php-archive` vendored with DokuWiki Librarian: `Tar::writeRawFileHeader()` overwrites the mtime with the size, so every file in a generated tar reads as 1970-01-01 with a size-derived offset. Fixed in [splitbrain/php-archive PR #38](https://github.com/splitbrain/php-archive/pull/38) but DokuWiki hasn't bumped the vendor lib yet. Once it does, `PatchedTar.php` can be deleted and `admin.php` switched back to using `splitbrain\PHPArchive\Tar` directly.
82a33f8e80Stracker-user
838d8c8007Stracker-user## License
848d8c8007Stracker-user
858d8c8007Stracker-userGPL-2.0-or-later, matching DokuWiki itself.
86