PHPackages                             dappcore/php-install - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. dappcore/php-install

ActiveLibrary

dappcore/php-install
====================

Installer and schema-baseline module for CorePHP — fresh install, upgrade, and recovery

v0.1.0(yesterday)020↑2750%EUPL-1.2PHPPHP ^8.2CI failing

Since Jul 27Pushed todayCompare

[ Source](https://github.com/dAppCore/php-install)[ Packagist](https://packagist.org/packages/dappcore/php-install)[ RSS](/packages/dappcore-php-install/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (2)Versions (2)Used By (0)

dappcore/php-install
====================

[](#dappcorephp-install)

Installer and schema-baseline module for CorePHP applications.

```
composer require dappcore/php-install
```

Register `\Core\Mod\Install\Boot::class` in the application's provider list. To remove it, drop the provider and `composer remove` the package — nothing else in the application depends on it.

Why it exists
-------------

[](#why-it-exists)

A fresh install should not replay the migration history. History is edited: a create migration gets updated in place, and every migration after it then assumes a schema that no clean database has ever had. The run dies there, and it dies only on new installs, so nobody notices until someone installs.

This package keeps a flattened baseline of the schema and folds new migrations into it, so a fresh install loads one file and stops.

The install screen
------------------

[](#the-install-screen)

Visit `/install` on a fresh checkout. Three steps: **requirements → database → run**.

- **Requirements** checks PHP version, extensions, writable paths, `.env` and `APP_KEY` *before* anything is written, and every failure carries the command that fixes it.
- **Database** tests credentials before saving them, and again on save — writing credentials that do not work leaves an application that cannot boot, which is worse than a failed form. `.env` is edited key by key, through a temporary file and a rename, so comments and unrelated settings survive and an interrupted write cannot corrupt it.
- **Run** shows the plan before executing it: load the baseline, run *N* pending migrations, or — in recovery — list the tables that are missing. It never drops anything.

### It closes itself

[](#it-closes-itself)

The installer writes `.env` and runs migrations, so it must not stay reachable. Once the schema is up to date the routes answer **404** — not a redirect, which would confirm they exist. Set `INSTALLER_ENABLED=true` to reopen it deliberately for a repair.

### Known exposure: the connection test reaches where you point it

[](#known-exposure-the-connection-test-reaches-where-you-point-it)

The database step connects to a host and port the request supplies. That is the feature — an installer cannot know your database's address — but it does mean that while the installer is open, whoever can reach it can ask the server to open TCP connections, and the deliberately specific error messages ("could not reach the server" versus "reached the server, but could not open the database") distinguish an open port from a closed one.

This is inherent to installing anything, and is bounded rather than eliminated: the installer answers 404 unless the database genuinely needs work, so the window is a box mid-setup, not a running application. Do not put a box on a public address while its installer is open, and do not leave `INSTALLER_ENABLED=true` set.

Values bound for `.env` are refused if they contain line breaks or control characters — a password of `x\nAPP_DEBUG=true` would otherwise write a second setting — and the file is written through a mode-600 temporary file that preserves the original permissions rather than widening them.

### Why it does not use the `web` middleware group

[](#why-it-does-not-use-the-web-middleware-group)

The application's own middleware is what is not working yet when someone opens the installer. It takes only cookies, a session and CSRF, and forces three settings on its own requests:

forcedbecause`session.driver=file`, `cache.default=file`an app configured for redis cannot render a screen that needs a session while redis is down — and that screen is where you go to fix it`session.domain=null`a configured `SESSION_DOMAIN` stops the browser returning the cookie when the installer is opened on an IP or provisional hostname, and the form then rejects itself with a CSRF mismatch it can never get past`session.secure` follows the requesta secure-only cookie over plain HTTP on a box whose TLS is not up yet — which is the box being installedEverything is styled inline: on a fresh checkout `public/build` does not exist, and an unstyled page is the last thing wanted at the moment it has to be read.

Commands
--------

[](#commands)

### `schema:rebase`

[](#schemarebase)

Rebuilds `database/schema/{connection}-schema.sql` from the current migrations.

flaguse*(none)*fold in newly added migrations; no-ops when current`--force`rebuild after editing a migration **in place** — the migration names are unchanged, so nothing else can detect it`--check`report only; exits non-zero when the baseline has fallen behind. Run this in CI`--database=NAME`build in an existing throwaway database instead of creating oneThe baseline is always built by migrating an **empty** database, never by dumping a working one — a working database carries data and whatever drift it has picked up.

Safety:

- A rebase targeting the configured (live) database is refused.
- By default a `_schema_rebase` database is created and dropped. Where the application user has no `CREATE DATABASE` right — which in production it should not — pass `--database` and an existing throwaway database is wiped and reused.
- The connection is restored in a `finally`, so a failed dump cannot leave the application pointed at the scratch database.
- Stored routines are included when the server can enumerate them and skipped with a warning when it cannot, rather than failing the rebuild. (A MariaDB upgraded without `mariadb-upgrade` cannot: `mysql.proc` has the wrong column count.)

Add the check to CI so drift fails a pull request instead of someone's first install:

```
- name: Check the schema baseline is current
  run: php artisan schema:rebase --check
```

### `install:status`

[](#installstatus)

Reports which of three routes a database needs, and exits non-zero unless it is ready.

statemeaning**fresh**no schema — load the baseline, then anything published since**upgrade**consistent but behind — run the outstanding migrations, data untouched**recovery**the migrations ledger records work the schema does not have**ready**consistent, nothing pending**Recovery** is the state a plain "is it installed?" check cannot see. A migration run that dies partway leaves the earlier migrations recorded, so the ledger claims work the schema is missing. The database looks installed and is not.

Programmatic use
----------------

[](#programmatic-use)

`SchemaInspector` answers the same questions without a console, for an install screen or a health endpoint. Every method is safe against a database that does not exist yet — that is the normal case on a new box, not an error.

```
use Core\Mod\Install\Schema\InstallState;
use Core\Mod\Install\Schema\SchemaInspector;

$inspector = app(SchemaInspector::class);

match ($inspector->state()) {
    InstallState::Fresh    => /* run the installer */,
    InstallState::Upgrade  => /* offer the pending migrations */,
    InstallState::Recovery => /* show $inspector->missingTables() */,
    InstallState::Ready    => /* carry on */,
};
```

Licence
-------

[](#licence)

EUPL-1.2.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance100

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity35

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

1d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/268332193?v=4)[dappcore](/maintainers/dappcore)[@dAppCore](https://github.com/dAppCore)

---

Top Contributors

[![Snider](https://avatars.githubusercontent.com/u/631881?v=4)](https://github.com/Snider "Snider (4 commits)")

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/dappcore-php-install/health.svg)

```
[![Health](https://phpackages.com/badges/dappcore-php-install/health.svg)](https://phpackages.com/packages/dappcore-php-install)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
