fix - install 1.0.9

This commit is contained in:
2026-06-03 16:23:27 +02:00
parent 72c48d301d
commit 6b637fc12b
2 changed files with 91 additions and 17 deletions
+10 -1
View File
@@ -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
+78 -13
View File
@@ -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);
new PDO(
"mysql:host={$dbHost};port={$dbPort}",
$dbUser, $dbPass,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 5]
);
$connected = true;
break;
} catch (\PDOException) {
sleep(2);
}
// 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})");