Skip to content

Commit c15553b

Browse files
fix(install): repair web+CLI installer flow and harden install endpoint
The web installer was unusable: Install::index() redirected to install/dbsetup via HTTP 302 (GET) but the route was registered POST-only, producing "404 Can't find a route for 'GET: install/dbsetup'" on every fresh installation. Refactored index() to invoke dbsetup() directly in the same request — no HTTP redirect, no flashdata round-trip — and removed the install/dbsetup route entirely. dbsetup() is now private and accepts the installation payload as a typed array parameter, eliminating the externally callable seed endpoint and shrinking the installer's attack surface to a single InstallFilter-protected route. The CLI installer (php spark ci4ms:setup) aborted at Step 5/6 with "BLOB, TEXT, GEOMETRY or JSON column 'profileIMG' can't have a default value" because the users table migration declared profileIMG as TEXT with a string default — rejected by MySQL/MariaDB in strict mode (the default on most distros). Changed the column to VARCHAR(255) NULL so the default URL is preserved and the migration succeeds on every supported server version. Bumped app.version to 0.31.11.0 in both installer paths so freshly written .env files report the correct release. Files changed: - modules/Install/Controllers/Install.php — dbsetup() private + direct call - modules/Install/Config/Routes.php — removed install/dbsetup route - modules/Auth/Database/Migrations/2026-02-25-062805_CreateUsersTable.php — profileIMG TEXT → VARCHAR(255) NULL - modules/Backend/Commands/Ci4msSetup.php — app.version bump - CHANGELOG.md, docs/codebase-walkthrough.md — release docs
1 parent b8a9848 commit c15553b

6 files changed

Lines changed: 23 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) conventions adapted to the existing four-component version numbers.
66

7+
## [0.31.11.0] - 2026-05-24
8+
9+
### Fixed
10+
11+
- **CRITICAL — Web Installer Broken (404 on `/install/dbsetup`):** `Install::index()` redirected the browser to `install/dbsetup` after writing `.env`, but the route was registered as `POST`-only. The 302 redirect issued a `GET` request, producing `404 — Can't find a route for 'GET: install/dbsetup'` and aborting every web installation. The two-step request flow also relied on flashdata that was lost across the redirect on some session drivers. `index()` now invokes the migration + seed pipeline directly in the same request (no HTTP redirect, no flashdata), and the `install/dbsetup` route was removed entirely to eliminate the dead public endpoint. Reported by community installation feedback.
12+
- **CRITICAL — CLI Installer Migration Failure (`profileIMG` Default Value):** The `users` table migration declared `profileIMG` as `TEXT NOT NULL` with a string `default`. MySQL/MariaDB reject this with `BLOB, TEXT, GEOMETRY or JSON column 'profileIMG' can't have a default value` on every server version that does not silently relax the rule (most Linux distros, all default strict-mode installs), so `php spark ci4ms:setup` aborted at Step 5/6 before the database was usable. Changed the column to `VARCHAR(255) NULL` so the default URL is preserved and the migration succeeds on every supported MySQL/MariaDB version.
13+
14+
### Changed
15+
16+
- **Install Controller Hardening:** `dbsetup()` is now `private` and accepts the installation payload as a typed `array` parameter, removing the externally callable seed endpoint, the flashdata round-trip, and the empty-payload guard. The `install_dbsetup` route alias and its `role=create` permission are gone, shrinking the installer's attack surface to a single endpoint protected by `InstallFilter` (which returns `404` once `writable/install.lock` exists).
17+
- **Version Bump:** `app.version` advanced to `0.31.11.0` in both `Install::index()` and `Ci4msSetup::run()` so freshly written `.env` files report the correct release.
18+
719
## [0.31.10.0] - 2026-05-23
820

921
### Fixed

docs/codebase-walkthrough.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ All settings methods clear the `settings` cache after saving.
397397
2. `copyEnvFile()` copies `env``.env`
398398
3. `updateEnvSettings()` writes all config values to `.env` (regex-based key=value replacement)
399399
4. `generateEncryptionKey()` creates `hex2bin:` prefixed random key
400-
5. Redirects to `/install/dbsetup` with user data in query params
400+
5. `index()` invokes the private `dbsetup($installData)` directly in the same request — no HTTP redirect, no flashdata, no public endpoint
401401
6. `dbsetup()`:
402402
- Runs `$migrate->latest()` to create all database tables
403403
- Calls `InstallService::createDefaultData()` to seed the database

modules/Auth/Database/Migrations/2026-02-25-062805_CreateUsersTable.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ public function up()
2020
'null' => false,
2121
],
2222
'profileIMG' => [
23-
'type' => 'TEXT',
24-
'null' => false,
23+
'type' => 'VARCHAR',
24+
'constraint' => '255',
25+
'null' => true,
2526
'default' => 'https://dummyimage.com/50x50/ced4da/6c757d.jpg',
2627
],
2728
'who_created' => [

modules/Backend/Commands/Ci4msSetup.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ public function run(array $params)
220220
'app.supportedLocales' => '["ar","de","en","es","fr","hi","ja","pt","ru","tr","zh"]',
221221
'app.negotiateLocale' => 'true',
222222
'app.appTimezone' => '\'Europe/Istanbul\'',
223-
'app.version' => '0.31.10.0',
223+
'app.version' => '0.31.11.0',
224224
];
225225

226226
if (!$this->updateEnvSettings($updates)) {

modules/Install/Config/Routes.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
<?php
22
$routes->group('install', ['namespace' => 'Modules\Install\Controllers'], function ($routes) {
33
$routes->match(['GET', 'POST'], '/', 'Install::index', ['as' => 'install','role'=>'create']);
4-
$routes->post('dbsetup', 'Install::dbSetup', ['as' => 'install_dbsetup','role'=>'create']);
54
});

modules/Install/Controllers/Install.php

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ public function index()
6767
'app.supportedLocales' => '["ar","de","en","es","fr","hi","ja","pt","ru","tr","zh"]',
6868
'app.negotiateLocale' => 'true',
6969
'app.appTimezone' => '\'Europe/Istanbul\'',
70-
'app.version' => '0.31.10.0'
70+
'app.version' => '0.31.11.0'
7171
];
7272
if ($this->copyEnvFile() && $this->updateEnvSettings($updates)) $this->generateEncryptionKey();
7373

7474

75-
$sessionData = [
75+
$installData = [
7676
'name' => $this->request->getPost('name'),
7777
'surname' => $this->request->getPost('surname'),
7878
'username' => $this->request->getPost('username'),
@@ -81,9 +81,9 @@ public function index()
8181
'siteName' => $this->request->getPost('siteName'),
8282
'baseUrl' => $this->request->getPost('baseUrl'),
8383
];
84-
if ($this->request->getPost('slogan')) $sessionData['slogan'] = $this->request->getPost('slogan') ?: null;
85-
session()->setFlashdata('install_data', $sessionData);
86-
return redirect()->to(site_url('install/dbsetup'));
84+
if ($this->request->getPost('slogan')) $installData['slogan'] = $this->request->getPost('slogan') ?: null;
85+
86+
return $this->dbsetup($installData);
8787
}
8888
return view('Modules\Install\Views\install');
8989
}
@@ -134,7 +134,7 @@ private function generateEncryptionKey()
134134
return true;
135135
}
136136

137-
public function dbsetup()
137+
private function dbsetup(array $installData)
138138
{
139139
$migrate = \Config\Services::migrations();
140140
$baseURL = rtrim(base_url(), '/');
@@ -145,8 +145,6 @@ public function dbsetup()
145145
return redirect()->route('install')->withInput()->with('errors', ['migration' => $e->getMessage()]);
146146
}
147147
$createDBs = new InstallService();
148-
$installData = session()->getFlashdata('install_data');
149-
if (empty($installData)) return redirect()->to($baseURL);
150148
$createDBs->createDefaultData([
151149
'fname' => trim(strip_tags($installData['name'])),
152150
'sname' => trim(strip_tags($installData['surname'])),

0 commit comments

Comments
 (0)