From 6b637fc12bdd2d9dea1fa216f9e59e626c806c78 Mon Sep 17 00:00:00 2001 From: Inext68 Date: Wed, 3 Jun 2026 16:23:27 +0200 Subject: [PATCH] fix - install 1.0.9 --- MEMORY.md | 11 +++++- install.php | 97 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 91 insertions(+), 17 deletions(-) diff --git a/MEMORY.md b/MEMORY.md index a4372577..f31c4443 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -24,6 +24,10 @@ - Fallback SQLite: mantiene `php artisan migrate --seed` + tinker ma con `var_export()` per escaping - Step 5 rinominato da "MIGRATION E SEED" a "SCHEMA DATABASE E DATI BASE" - Step 6 usa PDO invece di tinker (MySQL) +- **Auto-creazione utente MySQL**: aggiunta funzione `ensureMysqlUserAndDb()` che chiede password root, crea utente + database + GRANT ALL PRIVILEGES su `localhost` e `%` +- **Sostituito loop 30-retry** con connessione singola PDO (timeout 5s): se credenziali errate, chiede se creare utente automaticamente +- **Fix parse error**: `\$adminName` → `$adminName` in `var_export()` nel ramo SQLite +- **Fix composer**: rimosso `sudo -u www-data` da composer (causa git dubious ownership + permission denied), aggiunto `COMPOSER_ROOT_VERSION=dev-main`; `vendor` aggiunto al chown finale ### In Progress - *(nessuno)* @@ -37,6 +41,8 @@ - **`var_export()` per tinker fallback**: nei rari casi SQLite, si usa `var_export()` che produce stringhe PHP valide con escaping automatico - **`2>/dev/null` rimosso** dal MySQL main path (non serve più, non c'è tinker) - **Docker MySQL credenziali**: hardcoded `mysql:glastree:secret:glastree` (dal docker-compose.mysql.yml) +- **Composer senza sudo**: `COMPOSER_ROOT_VERSION=dev-main` per evitare git dubious ownership; composer eseguito come utente corrente (root), non più come www-data — dopo, `chown -R www-data vendor` per permessi lettura webserver +- **Auto-create MySQL user**: `ensureMysqlUserAndDb()` prova prima root senza password (auth_socket), poi chiede password; crea utente su `localhost` e `%`, GRANT ALL sul database, CREATE DATABASE IF NOT EXISTS ## Next Steps - *(nessuno)* @@ -46,7 +52,10 @@ - `DatabaseSeeder` crea ancora admin `admin@glastree.local / password` ma per MySQL viene cancellato dal PDO script - `createAdminUser()` setta `is_admin=1`, `status='active'`, `permissions` completo, `role_preset_id=1`, e Spatie `model_has_roles` con role_id=1 - `password_hash($pass, PASSWORD_BCRYPT)` produce hash `$2y$...` compatibile con `Hash::check()` di Laravel +- Composer ora eseguito come utente corrente (root) con `COMPOSER_ROOT_VERSION=dev-main` per evitare git dubious ownership e permission denied su `vendor/` +- `vendor/` aggiunto al `chown` finale in entrambi i modi (Apache e Restore) per garantire leggibilità da www-data +- `ensureMysqlUserAndDb()` sanitizza input (rimuove `' " \0 \`) prima di passarli a SQL exec ## Relevant Files - `database/install.sql`: NEW — schema MySQL completo + seed data (1059 righe) -- `install.php`: MODIFIED — `createAdminUser()` function + SQL import + PDO admin + Docker/restore adattati +- `install.php`: MODIFIED — `createAdminUser()` + `ensureMysqlUserAndDb()` + composer fix + auto-create MySQL user diff --git a/install.php b/install.php index 26d46b8d..beda2bad 100644 --- a/install.php +++ b/install.php @@ -95,6 +95,56 @@ function runCapture(string $cmd): string { return trim(shell_exec($cmd) ?: ''); } +/** + * Crea un utente MySQL con permessi completi sul database e lo schema. + * Chiede la password root se la connessione senza password fallisce. + */ +function ensureMysqlUserAndDb( + string $dbHost, string $dbPort, string $dbName, + string $dbUser, string $dbPass +): bool { + // Prova senza password (auth_socket / Unix socket) + $rootPdo = null; + try { + $rootPdo = new PDO( + "mysql:host={$dbHost};port={$dbPort}", + 'root', '', + [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 5] + ); + } catch (\PDOException) { + $rootPass = askRequired('Password utente root MySQL (lascia vuoto se senza password)'); + try { + $rootPdo = new PDO( + "mysql:host={$dbHost};port={$dbPort}", + 'root', $rootPass, + [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 5] + ); + } catch (\PDOException $e) { + error('Connessione come root fallita: ' . $e->getMessage()); + return false; + } + } + + $safeUser = str_replace(["'", '"', '`', "\0", '\\'], '', $dbUser); + $safePass = str_replace(["'", '"', '`', "\0", '\\'], '', $dbPass); + $safeName = str_replace(["'", '"', '`', "\0", '\\'], '', $dbName); + + try { + $rootPdo->exec("CREATE DATABASE IF NOT EXISTS `{$safeName}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); + + foreach (['localhost', '%'] as $host) { + $rootPdo->exec("CREATE USER IF NOT EXISTS '{$safeUser}'@'{$host}' IDENTIFIED BY '{$safePass}'"); + $rootPdo->exec("GRANT ALL PRIVILEGES ON `{$safeName}`.* TO '{$safeUser}'@'{$host}'"); + } + $rootPdo->exec("FLUSH PRIVILEGES"); + + return true; + } catch (\PDOException $e) { + error("Errore creazione utente MySQL: " . $e->getMessage()); + return false; + } +} + /** * Crea l'utente amministratore via PDO prepared statement. * Nessun escaping PHP necessario (tutto via prepared statement). @@ -306,29 +356,44 @@ if ($mode === 'Fresh Install su Apache (LAMP tradizionale)') { if ($dbType === 'mysql') { info("Connessione a MySQL {$dbHost}:{$dbPort}..."); + $connected = false; - for ($i = 0; $i < 30; $i++) { - try { - new PDO("mysql:host={$dbHost};port={$dbPort}", $dbUser, $dbPass); - $connected = true; - break; - } catch (\PDOException) { - sleep(2); - } + try { + new PDO( + "mysql:host={$dbHost};port={$dbPort}", + $dbUser, $dbPass, + [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 5] + ); + $connected = true; + } catch (\PDOException) { + // Credenziali non valide o utente inesistente } + if ($connected) { ok('MySQL raggiungibile'); } else { - warn('Timeout MySQL — verificare che il servizio sia attivo'); + warn("Accesso negato per '{$dbUser}' — utente inesistente o password errata"); + if (confirm("Creare l'utente MySQL '{$dbUser}' con permessi completi su '{$dbName}'?")) { + if (!ensureMysqlUserAndDb($dbHost, $dbPort, $dbName, $dbUser, $dbPass)) { + fail("Impossibile creare l'utente MySQL. Verifica la password root."); + } + ok("Utente '{$dbUser}' creato con permessi completi su '{$dbName}'"); + } else { + fail("Riavvia lo script con credenziali valide."); + } } - info("Creazione database '{$dbName}'..."); + info("Verifica database '{$dbName}'..."); try { - $pdo = new PDO("mysql:host={$dbHost};port={$dbPort}", $dbUser, $dbPass); + $pdo = new PDO( + "mysql:host={$dbHost};port={$dbPort}", + $dbUser, $dbPass, + [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] + ); $pdo->exec("CREATE DATABASE IF NOT EXISTS `{$dbName}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); ok("Database '{$dbName}' pronto"); } catch (\PDOException $e) { - warn("Crea manualmente: mysql -u root -p -e \"CREATE DATABASE `{$dbName}` CHARACTER SET utf8mb4;\""); + warn("Crea manualmente: mysql -u root -p -e \"CREATE DATABASE `{$dbName}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\""); } } else { $sqlitePath = $scriptDir . '/database/database.sqlite'; @@ -345,7 +410,7 @@ if ($mode === 'Fresh Install su Apache (LAMP tradizionale)') { println(color(' 3/7 — INSTALLAZIONE DIPENDENZE', 'yellow')); println(color('══════════════════════════════════════════', 'yellow')); - run("{$sudo}composer install --no-dev --optimize-autoloader", 'Installazione dipendenze Composer...'); + run("COMPOSER_ROOT_VERSION=dev-main composer install --no-dev --optimize-autoloader", 'Installazione dipendenze Composer...'); ok('Dipendenze PHP installate'); // ── Step 4: Package discovery ──────────────────── @@ -442,7 +507,7 @@ if ($mode === 'Fresh Install su Apache (LAMP tradizionale)') { // ── Permissions ────────────────────────────────── if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') { info('Impostazione permessi...'); - runCapture("chown -R {$wwwUser}:{$wwwUser} storage bootstrap/cache 2>/dev/null"); + runCapture("chown -R {$wwwUser}:{$wwwUser} vendor storage bootstrap/cache 2>/dev/null"); chmod("{$scriptDir}/storage", 0775); chmod("{$scriptDir}/bootstrap/cache", 0775); ok("Permessi impostati (utente: {$wwwUser})"); @@ -737,7 +802,7 @@ if ($mode === 'Restore da Backup (Apache)') { } // Composer - run("{$sudo}composer install --no-dev --optimize-autoloader", 'Installazione dipendenze Composer...'); + run("COMPOSER_ROOT_VERSION=dev-main composer install --no-dev --optimize-autoloader", 'Installazione dipendenze Composer...'); runCapture("{$sudo}php artisan package:discover --ansi 2>/dev/null"); // Storage link + cache @@ -746,7 +811,7 @@ if ($mode === 'Restore da Backup (Apache)') { // Permissions if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') { - runCapture("chown -R {$wwwUser}:{$wwwUser} storage bootstrap/cache 2>/dev/null"); + runCapture("chown -R {$wwwUser}:{$wwwUser} vendor storage bootstrap/cache 2>/dev/null"); chmod("{$scriptDir}/storage", 0775); chmod("{$scriptDir}/bootstrap/cache", 0775); ok("Permessi impostati (utente: {$wwwUser})");