1.0.6 fix modifica install.php

This commit is contained in:
2026-06-03 13:32:04 +02:00
parent fcbb6fb061
commit f36a9906a2
13 changed files with 1323 additions and 238 deletions
+223 -75
View File
@@ -95,6 +95,55 @@ function runCapture(string $cmd): string {
return trim(shell_exec($cmd) ?: '');
}
/**
* Crea l'utente amministratore via PDO prepared statement.
* Nessun escaping PHP necessario (tutto via prepared statement).
*/
function createAdminUser(
string $dbHost, string $dbPort, string $dbName,
string $dbUser, string $dbPass,
string $adminName, string $adminEmail, string $adminPass
): bool {
try {
$pdo = new PDO(
"mysql:host={$dbHost};port={$dbPort};dbname={$dbName}",
$dbUser, $dbPass,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
$hash = password_hash($adminPass, PASSWORD_BCRYPT);
$permissions = json_encode([
'individui' => 2, 'gruppi' => 2, 'eventi' => 2,
'documenti' => 2, 'mailing' => 2, 'viste' => 2,
'report' => 2, 'settings' => 2,
]);
// Elimina eventuale utente con stessa email (seeder)
$stmt = $pdo->prepare('DELETE FROM users WHERE email = ?');
$stmt->execute([$adminEmail]);
// Inserisce admin con is_admin=1, status='active', permissions completi
$stmt = $pdo->prepare(
"INSERT INTO users (name, email, password, is_admin, status, permissions, role_preset_id, created_at, updated_at)
VALUES (?, ?, ?, 1, 'active', ?, 1, NOW(), NOW())"
);
$stmt->execute([$adminName, $adminEmail, $hash, $permissions]);
$userId = $pdo->lastInsertId();
// Assegna ruolo Spatie 'admin' (role_id = 1)
$stmt = $pdo->prepare(
"INSERT INTO model_has_roles (role_id, model_type, model_id) VALUES (1, ?, ?)"
);
$stmt->execute(['App\\Models\\User', $userId]);
return true;
} catch (\PDOException $e) {
error("Errore creazione admin: " . $e->getMessage());
return false;
}
}
// ── Banner ───────────────────────────────────────────
println(color(' ____ _ _ _', 'white'));
println(color(' / ___| | __ _ ___| |_ ___ _ __ ___ | |_ ___', 'white'));
@@ -292,46 +341,69 @@ if ($mode === 'Fresh Install su Apache (LAMP tradizionale)') {
println(color(' 4/7 — REGISTRAZIONE PACCHETTI', 'yellow'));
println(color('══════════════════════════════════════════', 'yellow'));
runCapture("php artisan package:discover --ansi");
runCapture("php artisan package:discover --ansi 2>/dev/null");
ok('Pacchetti registrati');
// ── Step 5: Migration + Seed ─────────────────────
// ── Step 5: Schema + Seed ────────────────────────
println();
println(color('══════════════════════════════════════════', 'yellow'));
println(color(' 5/7 — MIGRATION E SEED', 'yellow'));
println(color(' 5/7 — SCHEMA DATABASE E DATI BASE', 'yellow'));
println(color('══════════════════════════════════════════', 'yellow'));
if (!run('php artisan migrate --seed --force', 'Esecuzione migration e seed...')) {
fail('Migration fallita. Verifica le credenziali del database.');
$sqlFile = $scriptDir . '/database/install.sql';
if (!file_exists($sqlFile)) {
fail("File database/install.sql non trovato in {$scriptDir}");
}
ok('Struttura database creata e dati di base inseriti');
runCapture('php artisan storage:link --force');
if ($dbType === 'mysql') {
$importCmd = "mysql -h {$dbHost} -P {$dbPort} -u {$dbUser} -p{$dbPass} {$dbName} < {$sqlFile}";
if (!run($importCmd, 'Importazione struttura database e dati base...')) {
fail("Importazione SQL fallita. Verifica il file database/install.sql e le credenziali.");
}
} else {
// SQLite fallback: usa le migration (install.sql è solo per MySQL)
if (!run('php artisan migrate --seed --force', 'Esecuzione migration e seed...')) {
fail('Migration fallita. Verifica la configurazione SQLite.');
}
}
ok('Database popolato con struttura e dati base');
// ── Step 6: Admin user ───────────────────────────
runCapture('php artisan storage:link --force 2>/dev/null');
// ── Step 6: Admin user (via PDO — no tinker) ─────
println();
println(color('══════════════════════════════════════════', 'yellow'));
println(color(' 6/7 — CREAZIONE AMMINISTRATORE', 'yellow'));
println(color('══════════════════════════════════════════', 'yellow'));
$tinkerScript = <<<PHP
\App\Models\User::where('email', '{$adminEmail}')->delete();
\$u = new \App\Models\User;
\$u->name = '{$adminName}';
\$u->email = '{$adminEmail}';
\$u->password = bcrypt('{$adminPass}');
\$u->is_admin = true;
\$u->status = 'active';
\$u->permissions = ['individui' => 2, 'gruppi' => 2, 'eventi' => 2, 'documenti' => 2, 'mailing' => 2, 'viste' => 2, 'report' => 2, 'settings' => 2];
\$u->save();
echo "OK: " . \$u->id;
PHP;
$result = runCapture("php artisan tinker --execute=" . escapeshellarg($tinkerScript));
if (str_contains($result, 'OK:')) {
ok("Amministratore {$adminEmail} creato");
if ($dbType === 'mysql') {
if (createAdminUser($dbHost, $dbPort, $dbName, $dbUser, $dbPass, $adminName, $adminEmail, $adminPass)) {
ok("Amministratore {$adminEmail} creato con permessi completi");
} else {
fail("Creazione admin fallita. Verifica i dati inseriti.");
}
} else {
warn("Creazione admin fallita — crealo manualmente dopo l'installazione");
// SQLite: usa seeder (l'admin verrà creato da DatabaseSeeder)
// Poi aggiorna la password con quella scelta dall'utente
runCapture("php artisan tinker --execute=" . escapeshellarg(
"\$u = \App\Models\User::first(); " .
"if (\$u) { " .
"\$u->name = " . var_export($adminName, true) . "; " .
"\$u->email = " . var_export($adminEmail, true) . "; " .
"\$u->password = bcrypt(" . var_export($adminPass, true) . "); " .
"\$u->is_admin = true; " .
"\$u->status = 'active'; " .
"\$u->permissions = " . var_export([
'individui' => 2, 'gruppi' => 2, 'eventi' => 2,
'documenti' => 2, 'mailing' => 2, 'viste' => 2,
'report' => 2, 'settings' => 2,
], true) . "; " .
"\$u->role_preset_id = 1; " .
"\$u->save(); " .
"echo 'OK'; " .
"}"
) . " 2>/dev/null");
ok("Amministratore {$adminEmail} configurato");
}
// ── Step 7: Asset ────────────────────────────────
@@ -354,17 +426,9 @@ PHP;
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
info('Impostazione permessi...');
$wwwUser = trim(shell_exec('ps aux | grep -E "apache|httpd" | grep -v grep | head -1 | awk \'{print \$1}\'') ?: 'www-data');
run("chown -R {$wwwUser}:{$wwwUser} storage bootstrap/cache", 'Proprietà file (chown)');
runCapture("chown -R {$wwwUser}:{$wwwUser} storage bootstrap/cache 2>/dev/null");
chmod("{$scriptDir}/storage", 0775);
chmod("{$scriptDir}/bootstrap/cache", 0775);
// Verifica permessi sessione (causa comune di errori 419)
$sessionDir = "{$scriptDir}/storage/framework/sessions";
if (is_dir($sessionDir) && !is_writable($sessionDir)) {
warn("{$sessionDir} non è scrivibile — possibile errore 419 (CSRF) al login");
chmod($sessionDir, 0775);
}
ok("Permessi impostati (utente: {$wwwUser})");
}
@@ -452,26 +516,85 @@ if ($mode === 'Fresh Install via Docker') {
sleep(2);
}
$tinkerScript = <<<PHP
\App\Models\User::where('email', '{$adminEmail}')->delete();
\$u = new \App\Models\User;
\$u->name = '{$adminName}';
\$u->email = '{$adminEmail}';
\$u->password = bcrypt('{$adminPass}');
\$u->is_admin = true;
\$u->status = 'active';
\$u->permissions = ['individui' => 2, 'gruppi' => 2, 'eventi' => 2, 'documenti' => 2, 'mailing' => 2, 'viste' => 2, 'report' => 2, 'settings' => 2];
\$u->save();
echo "OK: " . \$u->id;
// Import schema SQL nel container
$sqlFile = $scriptDir . '/database/install.sql';
if (file_exists($sqlFile) && $dockerDb === 'mysql') {
info('Importazione schema nel container...');
runCapture("docker cp {$sqlFile} {$containerId}:/tmp/install.sql 2>/dev/null");
$mysqlHost = 'mysql';
$mysqlUser = 'glastree';
$mysqlPass = 'secret';
$mysqlDb = 'glastree';
$importResult = runCapture(
"docker exec {$containerId} sh -c 'mysql -h {$mysqlHost} -u {$mysqlUser} -p{$mysqlPass} {$mysqlDb} < /tmp/install.sql' 2>&1"
);
if ($importResult !== '') {
warn("Import SQL: {$importResult}");
} else {
ok('Schema database importato');
}
} elseif ($dockerDb === 'sqlite') {
run("docker exec {$containerId} php artisan migrate --seed --force", 'Migration e seed...');
}
// Crea admin
if ($dockerDb === 'mysql') {
// Script PHP temporaneo con var_export (safe)
$adminScriptPath = sys_get_temp_dir() . '/glastree-create-admin-' . uniqid() . '.php';
$hash = password_hash($adminPass, PASSWORD_BCRYPT);
$perm = json_encode([
'individui' => 2, 'gruppi' => 2, 'eventi' => 2,
'documenti' => 2, 'mailing' => 2, 'viste' => 2,
'report' => 2, 'settings' => 2,
]);
$nameExp = var_export($adminName, true);
$emailExp = var_export($adminEmail, true);
$hashExp = var_export($hash, true);
$userExp = var_export($mysqlUser, true);
$passExp = var_export($mysqlPass, true);
$dbExp = var_export($mysqlDb, true);
$hostExp = var_export($mysqlHost, true);
$adminPhp = <<<PHP
<?php
\$pdo = new PDO("mysql:host=" . {$hostExp} . ";dbname=" . {$dbExp}, {$userExp}, {$passExp}, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
\$pdo->prepare("DELETE FROM users WHERE email = ?")->execute([{$emailExp}]);
\$pdo->prepare("INSERT INTO users (name, email, password, is_admin, status, permissions, role_preset_id, created_at, updated_at) VALUES (?, ?, ?, 1, 'active', ?, 1, NOW(), NOW())")->execute([{$nameExp}, {$emailExp}, {$hashExp}, '{$perm}']);
\$uid = \$pdo->lastInsertId();
\$pdo->prepare("INSERT INTO model_has_roles (role_id, model_type, model_id) VALUES (1, ?, ?)")->execute(['App\\\\Models\\\\User', \$uid]);
echo "OK:" . \$uid;
PHP;
$result = runCapture(
"docker exec -i {$containerId} php artisan tinker --execute=" . escapeshellarg($tinkerScript)
);
if (str_contains($result, 'OK:')) {
file_put_contents($adminScriptPath, $adminPhp);
runCapture("docker cp {$adminScriptPath} {$containerId}:/tmp/create_admin.php 2>/dev/null");
$adminResult = runCapture("docker exec {$containerId} php /tmp/create_admin.php 2>/dev/null");
@unlink($adminScriptPath);
} else {
// SQLite: usa tinker via docker exec
$adminResult = runCapture("docker exec {$containerId} php artisan tinker --execute=" . escapeshellarg(
"\$u = \App\Models\User::first(); " .
"if (\$u) { " .
"\$u->name = " . var_export($adminName, true) . "; " .
"\$u->email = " . var_export($adminEmail, true) . "; " .
"\$u->password = bcrypt(" . var_export($adminPass, true) . "); " .
"\$u->is_admin = true; " .
"\$u->status = 'active'; " .
"\$u->permissions = " . var_export([
'individui' => 2, 'gruppi' => 2, 'eventi' => 2,
'documenti' => 2, 'mailing' => 2, 'viste' => 2,
'report' => 2, 'settings' => 2,
], true) . "; " .
"\$u->role_preset_id = 1; " .
"\$u->save(); " .
"echo 'OK'; " .
"}"
) . " 2>/dev/null");
}
if (str_contains($adminResult ?? '', 'OK')) {
ok("Amministratore {$adminEmail} creato nel container");
$adminCreated = true;
} else {
warn("Creazione admin fallita — crealo manualmente dopo l'installazione");
warn("Creazione admin fallita — output: " . (($adminResult ?? '') ?: 'nessun output'));
}
}
@@ -593,49 +716,74 @@ if ($mode === 'Restore da Backup (Apache)') {
$storageBackup = "{$tmpDir}/storage";
if (is_dir($storageBackup)) {
info('Ripristino file storage...');
run("cp -r {$storageBackup}/* {$scriptDir}/storage/", null);
runCapture("cp -r {$storageBackup}/* {$scriptDir}/storage/ 2>/dev/null");
ok('Storage ripristinato');
}
// Composer
run('composer install --no-dev --optimize-autoloader', 'Installazione dipendenze Composer...');
runCapture('php artisan package:discover --ansi');
runCapture('php artisan package:discover --ansi 2>/dev/null');
// Storage link + cache
runCapture('php artisan storage:link --force');
runCapture('php artisan storage:link --force 2>/dev/null');
runCapture('php artisan optimize:clear');
// Permissions
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
$wwwUser = trim(shell_exec('ps aux | grep -E "apache|httpd" | grep -v grep | head -1 | awk \'{print \$1}\'') ?: 'www-data');
run("chown -R {$wwwUser}:{$wwwUser} storage bootstrap/cache", 'Proprietà file (chown)');
runCapture("chown -R {$wwwUser}:{$wwwUser} storage bootstrap/cache 2>/dev/null");
chmod("{$scriptDir}/storage", 0775);
chmod("{$scriptDir}/bootstrap/cache", 0775);
ok("Permessi impostati (utente: {$wwwUser})");
}
// Create admin if not exists
$tinkerScript = <<<PHP
\$exists = \App\Models\User::where('email', '{$adminEmail}')->exists();
if (!\$exists) {
\$u = new \App\Models\User;
\$u->name = '{$adminName}';
\$u->email = '{$adminEmail}';
\$u->password = bcrypt('{$adminPass}');
\$u->is_admin = true;
\$u->status = 'active';
\$u->permissions = ['individui' => 2, 'gruppi' => 2, 'eventi' => 2, 'documenti' => 2, 'mailing' => 2, 'viste' => 2, 'report' => 2, 'settings' => 2];
\$u->save();
echo 'OK';
} else {
echo 'EXISTS';
// Create admin if not exists (via PDO)
if ($dbType === 'mysql') {
$exists = false;
try {
$pdo = new PDO("mysql:host={$dbHost};port={$dbPort};dbname={$dbName}", $dbUser, $dbPass);
$stmt = $pdo->prepare('SELECT COUNT(*) FROM users WHERE email = ?');
$stmt->execute([$adminEmail]);
$exists = (int) $stmt->fetchColumn() > 0;
} catch (\PDOException) {
// Ignora — tenteremo la creazione
}
if ($exists) {
ok("Amministratore {$adminEmail} già esistente");
} elseif (createAdminUser($dbHost, $dbPort, $dbName, $dbUser, $dbPass, $adminName, $adminEmail, $adminPass)) {
ok("Amministratore {$adminEmail} creato");
} else {
warn("Creazione admin fallita — crealo manualmente dal pannello admin");
}
} else {
// SQLite fallback: usa tinker
$result = runCapture("php artisan tinker --execute=" . escapeshellarg(
"\$e = \App\Models\User::where('email', " . var_export($adminEmail, true) . ")->exists(); " .
"if (!\$e) { " .
"\$u = new \App\Models\User; " .
"\$u->name = " . var_export($adminName, true) . "; " .
"\$u->email = " . var_export($adminEmail, true) . "; " .
"\$u->password = bcrypt(" . var_export($adminPass, true) . "); " .
"\$u->is_admin = true; " .
"\$u->status = 'active'; " .
"\$u->permissions = " . var_export([
'individui' => 2, 'gruppi' => 2, 'eventi' => 2,
'documenti' => 2, 'mailing' => 2, 'viste' => 2,
'report' => 2, 'settings' => 2,
], true) . "; " .
"\$u->role_preset_id = 1; " .
"\$u->save(); " .
"echo 'OK'; " .
"} else { echo 'EXISTS'; }"
) . " 2>/dev/null");
if (str_contains($result, 'OK')) {
ok("Amministratore {$adminEmail} creato");
} elseif (str_contains($result, 'EXISTS')) {
ok("Amministratore {$adminEmail} già esistente");
} else {
warn("Creazione admin fallita (output: " . ($result ?: 'vuoto') . ")");
}
PHP;
$result = runCapture("php artisan tinker --execute=" . escapeshellarg($tinkerScript));
if (str_contains($result, 'OK')) {
ok("Amministratore {$adminEmail} creato");
} elseif (str_contains($result, 'EXISTS')) {
ok("Amministratore {$adminEmail} già esistente");
}
// Cleanup