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 7*340c9205Stracker-user 8*340c9205Stracker-user 98d8c8007Stracker-user## Why another backup plugin? 108d8c8007Stracker-user 118d8c8007Stracker-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: 128d8c8007Stracker-user 138d8c8007Stracker-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). 148d8c8007Stracker-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. 15b484d5bcStracker-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. 168d8c8007Stracker-user 178d8c8007Stracker-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. 188d8c8007Stracker-user 198d8c8007Stracker-user## What it backs up 208d8c8007Stracker-user 218d8c8007Stracker-userEach option is an independent checkbox. The first three columns are usually all you want; the rest are situational. 228d8c8007Stracker-user 238d8c8007Stracker-user| Option | Path inside archive | Notes | 248d8c8007Stracker-user| --- | --- | --- | 258d8c8007Stracker-user| Pages | `data/pages/` | Current wiki text. | 268d8c8007Stracker-user| Media | `data/media/` | Uploaded files. | 278d8c8007Stracker-user| Page metadata | `data/meta/` | Last-edit, subscriptions, changelogs. | 288d8c8007Stracker-user| Media metadata | `data/media_meta/` | | 298d8c8007Stracker-user| Page revisions | `data/attic/` | Old versions of pages. Can be large. | 308d8c8007Stracker-user| Media revisions | `data/media_attic/` | | 318d8c8007Stracker-user| Search index | `data/index/` | Rebuildable; off by default. | 328d8c8007Stracker-user| Configuration | `conf/` | Includes secrets — see below. `*.dist`, `*.example`, `*.bak` are filtered. | 338d8c8007Stracker-user| Plugins source | `lib/plugins/` | Useful for capturing local modifications. | 348d8c8007Stracker-user| Templates source | `lib/tpl/` | | 358d8c8007Stracker-user 368d8c8007Stracker-userAlways excluded: `data/cache/`, `data/tmp/`, `data/locks/`, `data/log/`, `_dummy` placeholders, `.DS_Store`, `Thumbs.db`, and `.git` / `.svn` / `.hg` directories anywhere. 378d8c8007Stracker-user 388d8c8007Stracker-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. 398d8c8007Stracker-user 408d8c8007Stracker-user## Security model 418d8c8007Stracker-user 428d8c8007Stracker-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. 438d8c8007Stracker-user- **CSRF-protected.** Every action submission is validated with DokuWiki's `checkSecurityToken()`. 448d8c8007Stracker-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. 458d8c8007Stracker-user- **Random filename.** Temp archives are named `sitebackup_tmp_<16 hex chars>.tar.gz` — 64 bits of CSPRNG entropy. 468d8c8007Stracker-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. 478d8c8007Stracker-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. 488d8c8007Stracker-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. 498d8c8007Stracker-user 508d8c8007Stracker-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. 518d8c8007Stracker-user 528d8c8007Stracker-user## Install 538d8c8007Stracker-user 548d8c8007Stracker-userIn your wiki: 558d8c8007Stracker-user 568d8c8007Stracker-user1. **Admin → Extension Manager → Manual Install** 578d8c8007Stracker-user2. Upload `sitebackup.zip`, click **Install** 588d8c8007Stracker-user3. Refresh the Admin page; a **Site Backup** entry appears in the Additional Plugins section 598d8c8007Stracker-user 608d8c8007Stracker-userOr extract the zip into `lib/plugins/sitebackup/` directly if you have file access. 618d8c8007Stracker-user 628d8c8007Stracker-user## Use 638d8c8007Stracker-user 648d8c8007Stracker-user1. Open **Site Backup** from the Admin menu. 658d8c8007Stracker-user2. Tick the components you want. 668d8c8007Stracker-user3. Click **Preview** to see the file list and total size per section. 678d8c8007Stracker-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. 688d8c8007Stracker-user 698d8c8007Stracker-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. 708d8c8007Stracker-user 718d8c8007Stracker-user## Uninstall 728d8c8007Stracker-user 738d8c8007Stracker-userSame path: **Admin → Extension Manager**, find **Site Backup** under Installed Extensions, click **Uninstall**. 748d8c8007Stracker-user 758d8c8007Stracker-user## Compatibility 768d8c8007Stracker-user 778d8c8007Stracker-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. 788d8c8007Stracker-user 79c874c2c0Stracker-userPHP 7.4 or newer (uses array destructuring in `foreach` and `??`). `str_starts_with()` is also used, but DokuWiki polyfills it in `inc/compatibility.php`, so PHP 8.0 is not required. 808d8c8007Stracker-user 81a33f8e80Stracker-user## Notes on bundled patches 82a33f8e80Stracker-user 83a33f8e80Stracker-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. 84a33f8e80Stracker-user 858d8c8007Stracker-user## License 868d8c8007Stracker-user 878d8c8007Stracker-userGPL-2.0-or-later, matching DokuWiki itself. 88