forgelab-me/ci4-updater

Self-update system for CodeIgniter 4 apps: an admin panel that checks a remote update server for new releases, downloads, diffs, backs up, and applies them, with automatic DB migrations. No SSH/git pull required.

Maintainers

Package info

github.com/forgelab-me/ci4-updater

pkg:composer/forgelab-me/ci4-updater

Transparency log

Statistics

Installs: 200

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

2.11.0 2026-08-20 19:13 UTC

This package is auto-updated.

Last update: 2026-08-20 19:13:44 UTC


README

Tests Latest Version License

A drop-in self-update system for CodeIgniter 4 apps: an admin panel that checks a remote update server (or GitHub releases) for new versions, downloads the release ZIP, diffs it against the live install (SHA-256 manifest), backs up changed files, applies the update, and runs pending DB migrations — all from the browser, no SSH/git pull required.

Every update leaves a backup the panel restores in one click, and releases can be signed so a compromised update server can't publish code to your apps.

Dashboard Current version, PHP/CI/DB info, migration status Update available A new release was found
Diff review File-level diff, before anything is written Update applied Applied, with the DB migration run automatically

Requirements

PHP 8.2+ · ext-zip · CodeIgniter 4.4+

Install

composer require forgelab-me/ci4-updater
php spark updater:setup

updater:setup is a one-time step per app. It publishes an editable app/Config/Updater.php, adds service('updater')->routes($routes); to app/Config/Routes.php, and creates writable/updater_settings.json with the two keys you have to fill in. Re-running it is safe: existing files are only replaced after confirmation (or with -f), the routes line is added once, and settings already set are left alone.

The panel itself is rendered from the package, so its improvements arrive with composer update; point $layout at your admin layout and set $appName. Pass --views if you'd rather own the markup.

Then, at minimum:

  1. Set VERSION, DATE and USER_AGENT in app/Config/Updater.php.

  2. Set $layout to your admin layout and $appName in the same file.

  3. Make sure the route filter really restricts access — read Security first.

  4. Point the app at a feed. Either run:

    php spark updater:config --url https://updates.example.com/api/my-app

    or edit writable/updater_settings.json directly:

    {
        "update_server_url": "https://updates.example.com/api/my-app",
        "update_server_token": ""
    }

    Leave the token empty for a public feed. updater:config with no options prints what is currently set — the quickest answer to "why does the panel say no update server is configured?". See Update server for what that URL has to serve.

If your app uses Shield, running migrations creates a settings table — that belongs to codeigniter4/settings, a Shield dependency, and has nothing to do with this package. ci4-updater ships no migrations and creates no tables.

Full details: Configuration.

Security

These routes can overwrite any file under app//public/ and run DB migrations. Treat them as deploy access, not as an ordinary admin page: the filter you pass to routes() is the entire boundary, so gate it on an admin-only group or permission rather than "is logged in", and serve update_server_url over HTTPS only — everything it returns gets written over your application files.

The manifest's SHA-256 check catches a corrupted download, not a malicious server — it comes from that same server. To close that gap, sign your releases: set Config\Updater::$publicKeys and unsigned releases are refused from then on. See Signing releases and Security.

How it works

  1. Before cutting a release you run php spark update:manifest. It hashes every file in SCAN_DIRS (SHA-256), writes manifest.json — recording which directories the release covers — and bundles a release_X.Y.Z_*.zip with the manifest embedded.
  2. You publish that ZIP and a latest.json describing it — ci4-update-server is a ready-made server for this, or use GitHub Releases.
  3. In the app, /admin/updates checks the feed, downloads and diffs the release, and applies it on confirmation — backing up every changed file to writable/backups/ and running pending migrations.
  4. If it goes wrong, the same panel restores that backup: files go back as they were and files the update added are removed. Older backups are pruned automatically ($keepBackups, five by default). A restore reverts code and never the database — the panel flags backups whose update shipped migrations.

A release covers app/ and public/ by default and says so in its manifest, so an app only ever touches what a release actually declares. Dependencies can be shipped too — see Shipping vendor/.

Step by step: Releasing an update.

Documentation

Contributing

Issues and PRs are welcome.

composer install
composer test
composer validate --strict

Keep changes focused, add or update tests for behavior changes, and note anything user-facing in CHANGELOG.md.

License

MIT — see LICENSE.