results = []; // 1. Check PHP extensions $this->checkAndFixPhpExtensions(); // 2. Check Git $this->checkAndFixGit(); // 3. Check Maven $this->checkAndFixMaven(); // 4. Check Node.js $this->checkAndFixNode(); // 5. Check MySQL connection $this->checkDatabase(); // 6. Fix permissions $this->fixPermissions(); // 7. Fix open_basedir $this->fixOpenBaseDir(); // 8. Configure emulator database from .env $this->configureEmulatorDatabase(); // 9. Create missing directories $this->createMissingDirectories(); // 10. Fix storage permissions $this->fixStoragePermissions(); // 11. Check disk space $this->checkDiskSpace(); // 12. Clear old caches $this->clearOldCaches(); // 13. Fix git safe directories $this->fixGitSafeDirectories(); // 14. Create .m2 directory for Maven $this->fixMavenDirectory(); // 15. Check and install Java (needed for Maven) $this->checkAndFixJava(); return $this->results; } private function checkAndFixPhpExtensions(): void { $requiredExtensions = ['pdo_mysql', 'curl', 'json', 'mbstring', 'xml', 'zip', 'bcmath']; $missing = []; foreach ($requiredExtensions as $ext) { if (! extension_loaded($ext)) { $missing[] = $ext; } } if ($missing === []) { $this->results[] = ['item' => 'PHP Extensions', 'status' => 'ok', 'message' => 'Alle vereiste extensies geïnstalleerd']; } else { $this->results[] = ['item' => 'PHP Extensions', 'status' => 'warning', 'message' => 'Ontbrekend: ' . implode(', ', $missing)]; } } private function checkAndFixGit(): void { $result = shell_exec('which git 2>/dev/null || echo ""'); if (! in_array(trim($result ?? ''), ['', '0'], true)) { $this->results[] = ['item' => 'Git', 'status' => 'ok', 'message' => trim($result)]; } else { // Install Git shell_exec('sudo apt-get update && sudo apt-get install -y git 2>&1'); $result = shell_exec('which git 2>/dev/null || echo ""'); if (! in_array(trim($result ?? ''), ['', '0'], true)) { $this->results[] = ['item' => 'Git', 'status' => 'fixed', 'message' => 'Automatisch geïnstalleerd']; } else { $this->results[] = ['item' => 'Git', 'status' => 'error', 'message' => 'Installatie mislukt']; } } } private function checkAndFixMaven(): void { $result = shell_exec('which mvn 2>/dev/null || echo ""'); if (! in_array(trim($result ?? ''), ['', '0'], true)) { $this->results[] = ['item' => 'Maven', 'status' => 'ok', 'message' => trim($result)]; } else { // Install Maven shell_exec('sudo apt-get update && sudo apt-get install -y maven 2>&1'); // Fix Maven repository permissions shell_exec('sudo mkdir -p /var/www/.m2/repository && sudo chown -R www-data:www-data /var/www/.m2'); $result = shell_exec('which mvn 2>/dev/null || echo ""'); if (! in_array(trim($result ?? ''), ['', '0'], true)) { $this->results[] = ['item' => 'Maven', 'status' => 'fixed', 'message' => 'Automatisch geïnstalleerd']; } else { $this->results[] = ['item' => 'Maven', 'status' => 'error', 'message' => 'Installatie mislukt']; } } } private function checkAndFixNode(): void { // Use shell command to check for node (bypasses open_basedir) $nodeResult = shell_exec('which node 2>/dev/null || echo ""'); $nodePath = trim($nodeResult ?? ''); if ($nodePath !== '' && $nodePath !== '0') { $version = shell_exec("{$nodePath} --version 2>/dev/null || echo ''"); $versionNum = trim($version ?? ''); // Check if version is 24.x if (str_starts_with($versionNum, 'v24')) { $this->results[] = ['item' => 'Node.js', 'status' => 'ok', 'message' => $versionNum]; } else { // Upgrade to Node.js 24 $this->installNode24(); } } else { // Install Node.js 24 $this->installNode24(); } } private function installNode24(): void { // Install Node.js 24 via NodeSource $commands = [ 'curl -fsSL https://deb.nodesource.com/setup_24.x | sudo bash - 2>&1', 'sudo apt-get install -y nodejs 2>&1', ]; $success = true; foreach ($commands as $cmd) { $result = shell_exec($cmd); if (str_contains($result ?? '', 'E:')) { $success = false; break; } } // Verify installation $version = shell_exec('node --version 2>/dev/null || echo ""'); $versionNum = trim($version ?? ''); if ($versionNum !== '' && $versionNum !== '0' && str_starts_with($versionNum, 'v24')) { $this->results[] = ['item' => 'Node.js', 'status' => 'fixed', 'message' => "Geïnstalleerd: {$versionNum}"]; } else { $this->results[] = ['item' => 'Node.js', 'status' => 'error', 'message' => 'Installatie mislukt']; } } private function checkDatabase(): void { try { $host = setting('emulator_database_host', '127.0.0.1'); $port = setting('emulator_database_port', '3306'); $name = setting('emulator_database_name', config('database.connections.mysql.database', '')); $username = setting('emulator_database_username', config('database.connections.mysql.username', '')); $password = setting('emulator_database_password', config('database.connections.mysql.password', '')); if (empty($name) || empty($username)) { $this->results[] = ['item' => 'Emulator Database', 'status' => 'warning', 'message' => 'Niet geconfigureerd']; $this->autoFixEmulatorDatabase(); return; } // Validate inputs $validationErrors = $this->validateDatabaseInputs($host, $port, $name, $username); if ($validationErrors !== []) { $this->results[] = ['item' => 'Emulator Database', 'status' => 'error', 'message' => implode(', ', $validationErrors)]; $this->autoFixEmulatorDatabase(); return; } // Try connection try { $pdo = new \PDO( "mysql:host={$host};port={$port};charset=utf8mb4", $username, $password, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_TIMEOUT => 5], ); // Test with database $pdo->exec("USE `{$name}`"); $pdo->query('SELECT 1'); $this->results[] = ['item' => 'Emulator Database', 'status' => 'ok', 'message' => "Verbonden met {$name}"]; } catch (\PDOException $e) { $errorMsg = $e->getMessage(); if (str_contains($errorMsg, 'Unknown database')) { $this->results[] = ['item' => 'Emulator Database', 'status' => 'error', 'message' => "Database '{$name}' bestaat niet"]; $this->autoFixEmulatorDatabase(); } elseif (str_contains($errorMsg, 'Access denied')) { $this->results[] = ['item' => 'Emulator Database', 'status' => 'error', 'message' => 'Verkeerde gebruikersnaam/wachtwoord']; $this->autoFixEmulatorDatabase(); } elseif (str_contains($errorMsg, 'Connection refused')) { $this->results[] = ['item' => 'Emulator Database', 'status' => 'error', 'message' => "Kan niet verbinden met {$host}:{$port}"]; } else { $this->results[] = ['item' => 'Emulator Database', 'status' => 'error', 'message' => $errorMsg]; } } } catch (\Exception $e) { $this->results[] = ['item' => 'Emulator Database', 'status' => 'error', 'message' => $e->getMessage()]; $this->autoFixEmulatorDatabase(); } } private function validateDatabaseInputs(string $host, string $port, string $name, string $username): array { $errors = []; // Validate host if ($host === '' || $host === '0') { $errors[] = 'Host is leeg'; } elseif (! filter_var($host, FILTER_VALIDATE_IP) && ! preg_match('/^[a-zA-Z0-9.-]+$/', $host)) { $errors[] = 'Ongeldige host: ' . $host; } // Validate port if ($port === '' || $port === '0') { $errors[] = 'Port is leeg'; } elseif (! is_numeric($port) || $port < 1 || $port > 65535) { $errors[] = 'Ongeldige port: ' . $port; } // Validate database name if ($name === '' || $name === '0') { $errors[] = 'Database naam is leeg'; } elseif (! preg_match('/^\w+$/', $name)) { $errors[] = 'Ongeldige database naam: ' . $name; } // Validate username if ($username === '' || $username === '0') { $errors[] = 'Gebruikersnaam is leeg'; } elseif (! preg_match('/^\w+$/', $username)) { $errors[] = 'Ongeldige gebruikersnaam: ' . $username; } return $errors; } private function autoFixEmulatorDatabase(): void { // Try to get correct values from .env / config $host = config('database.connections.mysql.host', '127.0.0.1'); $port = config('database.connections.mysql.port', '3306'); $name = config('database.connections.mysql.database', ''); $username = config('database.connections.mysql.username', ''); $password = config('database.connections.mysql.password', ''); if (empty($name) || empty($username)) { // Try to detect from MySQL process list or common names $detected = $this->detectDatabaseFromMysql(); if ($detected) { $name = $detected['name']; $host = $detected['host'] ?? $host; $username = $detected['username'] ?? $username; $password = $detected['password'] ?? $password; } else { $this->results[] = ['item' => 'Emulator Database Fix', 'status' => 'warning', 'message' => 'Kon geen geldige database vinden']; return; } } $settings = app(SettingsService::class); $settings->set('emulator_database_host', $host); $settings->set('emulator_database_port', (string) $port); $settings->set('emulator_database_name', $name); $settings->set('emulator_database_username', $username); $settings->set('emulator_database_password', $password); $this->results[] = ['item' => 'Emulator Database Fix', 'status' => 'fixed', 'message' => "Automatisch gefixt: {$name}@{$host}"]; } private function detectDatabaseFromMysql(): ?array { // Common database names for hotel emulators $commonNames = ['habbo', 'hotel', 'retro', 'emulator', 'game', 'server', 'arcturus', 'fusion']; // Get CMS database credentials that work $cmsHost = config('database.connections.mysql.host', '127.0.0.1'); $cmsPort = config('database.connections.mysql.port', '3306'); $cmsUser = config('database.connections.mysql.username', ''); $cmsPass = config('database.connections.mysql.password', ''); $cmsDb = config('database.connections.mysql.database', ''); if (empty($cmsUser)) { return null; } try { $pdo = new \PDO( "mysql:host={$cmsHost};port={$cmsPort};charset=utf8mb4", $cmsUser, $cmsPass, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_TIMEOUT => 5], ); // Get all databases the user can access $stmt = $pdo->query('SHOW DATABASES'); $databases = $stmt->fetchAll(\PDO::FETCH_COLUMN); // Check for common names foreach ($commonNames as $name) { if (in_array($name, $databases)) { return [ 'name' => $name, 'host' => $cmsHost, 'username' => $cmsUser, 'password' => $cmsPass, ]; } } // If CMS database exists and works, use that if (! empty($cmsDb) && in_array($cmsDb, $databases)) { return [ 'name' => $cmsDb, 'host' => $cmsHost, 'username' => $cmsUser, 'password' => $cmsPass, ]; } // Return first database that's not system db foreach ($databases as $db) { if (! in_array($db, ['information_schema', 'performance_schema', 'mysql', 'sys'])) { return [ 'name' => $db, 'host' => $cmsHost, 'username' => $cmsUser, 'password' => $cmsPass, ]; } } } catch (\Exception) { // Could not detect } return null; } private function fixPermissions(): void { $directories = [ '/var/www/emulator-source', '/var/www/nitro-client', '/var/www/nitro-renderer', '/var/www/Client', '/var/www/atomcms/storage', '/var/www/atomcms/bootstrap/cache', '/var/www/atomcms/app', ]; $fixed = false; foreach ($directories as $dir) { if (is_dir($dir)) { // Check if already owned by www-data $owner = shell_exec("stat -c '%U' {$dir} 2>/dev/null || echo ''"); if (trim($owner ?? '') !== 'www-data') { shell_exec("sudo chown -R www-data:www-data {$dir} 2>/dev/null || true"); $fixed = true; } } } // Always fix app directory permissions (new files might have wrong owner) shell_exec("sudo find /var/www/atomcms/app -type f -name '*.php' ! -user www-data -exec chown www-data:www-data {} \\; 2>/dev/null || true"); $this->results[] = ['item' => 'Permissions', 'status' => $fixed ? 'fixed' : 'ok', 'message' => $fixed ? 'Directories eigendom gefixt' : 'Al correct geconfigureerd']; } private function fixOpenBaseDir(): void { $openBaseDir = ini_get('open_basedir'); if (in_array($openBaseDir, ['', '0', false], true)) { $this->results[] = ['item' => 'open_basedir', 'status' => 'ok', 'message' => 'Geen restrictie']; return; } // Check if all required paths are in open_basedir $requiredPaths = ['/var/www', '/tmp', '/root']; $missing = []; foreach ($requiredPaths as $path) { if (! str_contains($openBaseDir, $path)) { $missing[] = $path; } } if ($missing === []) { $this->results[] = ['item' => 'open_basedir', 'status' => 'ok', 'message' => 'Alle paden toegestaan']; } else { $this->results[] = ['item' => 'open_basedir', 'status' => 'warning', 'message' => 'Ontbrekende paden: ' . implode(', ', $missing)]; } } private function configureEmulatorDatabase(): void { // Only configure if not already set $currentHost = setting('emulator_database_host', ''); if (! empty($currentHost)) { $this->results[] = ['item' => 'Emulator Database Config', 'status' => 'ok', 'message' => 'Al geconfigureerd']; return; } // Get from .env $host = config('database.connections.mysql.host', '127.0.0.1'); $port = config('database.connections.mysql.port', '3306'); $name = config('database.connections.mysql.database', ''); $username = config('database.connections.mysql.username', ''); $password = config('database.connections.mysql.password', ''); if (empty($name) || empty($username)) { $this->results[] = ['item' => 'Emulator Database Config', 'status' => 'warning', 'message' => 'Geen database gevonden in .env']; return; } $settings = app(SettingsService::class); $settings->set('emulator_database_host', $host); $settings->set('emulator_database_port', $port); $settings->set('emulator_database_name', $name); $settings->set('emulator_database_username', $username); $settings->set('emulator_database_password', $password); $this->results[] = ['item' => 'Emulator Database Config', 'status' => 'fixed', 'message' => "Automatisch geconfigureerd: {$name}@{$host}"]; } private function createMissingDirectories(): void { $directories = [ '/var/www/emulator-source', '/var/www/nitro-client', '/var/www/nitro-client/dist', '/var/www/nitro-renderer', '/var/www/Client', '/var/www/Client/gamedata', '/var/www/Gamedata', '/root/emulator', ]; $created = []; foreach ($directories as $dir) { if (! is_dir($dir)) { shell_exec("sudo mkdir -p {$dir} 2>/dev/null && sudo chown www-data:www-data {$dir} 2>/dev/null"); $created[] = basename($dir); } } if ($created !== []) { $this->results[] = ['item' => 'Directories', 'status' => 'fixed', 'message' => 'Aangemaakt: ' . implode(', ', $created)]; } else { $this->results[] = ['item' => 'Directories', 'status' => 'ok', 'message' => 'Alle directories bestaan']; } } private function fixStoragePermissions(): void { $storageDirs = [ '/var/www/atomcms/storage', '/var/www/atomcms/storage/logs', '/var/www/atomcms/storage/framework', '/var/www/atomcms/storage/framework/cache', '/var/www/atomcms/storage/framework/sessions', '/var/www/atomcms/storage/framework/views', '/var/www/atomcms/bootstrap/cache', ]; $fixed = false; foreach ($storageDirs as $dir) { if (is_dir($dir)) { $owner = shell_exec("stat -c '%U' {$dir} 2>/dev/null || echo ''"); if (trim($owner ?? '') !== 'www-data') { shell_exec("sudo chown -R www-data:www-data {$dir} 2>/dev/null"); $fixed = true; } } else { shell_exec("sudo mkdir -p {$dir} && sudo chown www-data:www-data {$dir} 2>/dev/null"); $fixed = true; } } // Make storage writable shell_exec('sudo chmod -R 775 /var/www/atomcms/storage 2>/dev/null'); shell_exec('sudo chmod -R 775 /var/www/atomcms/bootstrap/cache 2>/dev/null'); $this->results[] = ['item' => 'Storage Permissions', 'status' => $fixed ? 'fixed' : 'ok', 'message' => $fixed ? 'Gefixt' : 'Al correct']; } private function checkDiskSpace(): void { $result = shell_exec("df -h /var/www 2>/dev/null | tail -1 | awk '{print $5}'"); $usage = trim($result ?? '0%'); $usageNum = (int) str_replace('%', '', $usage); if ($usageNum >= 90) { $this->results[] = ['item' => 'Disk Space', 'status' => 'error', 'message' => "Disk {$usage} vol!"]; } elseif ($usageNum >= 75) { $this->results[] = ['item' => 'Disk Space', 'status' => 'warning', 'message' => "Disk {$usage} gebruikt"]; } else { $this->results[] = ['item' => 'Disk Space', 'status' => 'ok', 'message' => "Disk {$usage} gebruikt"]; } } private function clearOldCaches(): void { // Clear old temp files shell_exec("find /tmp -name 'emulator-update-*' -mtime +1 -exec rm -rf {} \\; 2>/dev/null"); shell_exec("find /tmp -name 'nitro_*' -mtime +1 -exec rm -rf {} \\; 2>/dev/null"); shell_exec("find /tmp -name '*.lock' -mtime +1 -delete 2>/dev/null"); // Clear Laravel caches shell_exec('cd /var/www/atomcms && php artisan cache:clear 2>/dev/null'); shell_exec('cd /var/www/atomcms && php artisan view:clear 2>/dev/null'); $this->results[] = ['item' => 'Cache Cleanup', 'status' => 'fixed', 'message' => 'Oude caches opgeruimd']; } private function fixGitSafeDirectories(): void { $directories = [ '/var/www/atomcms', '/var/www/emulator-source', '/var/www/emulator-source/Emulator', '/var/www/nitro-client', '/var/www/nitro-renderer', '/var/www/Client', '/root', '/root/emulator', '/var/www', ]; foreach ($directories as $dir) { shell_exec("git config --global --add safe.directory {$dir} 2>/dev/null || true"); } $this->results[] = ['item' => 'Git Safe Directories', 'status' => 'fixed', 'message' => 'Alle directories toegevoegd']; } private function fixMavenDirectory(): void { $mavenDir = '/var/www/.m2'; if (! is_dir($mavenDir)) { shell_exec("sudo mkdir -p {$mavenDir}/repository && sudo chown -R www-data:www-data {$mavenDir}"); $this->results[] = ['item' => 'Maven Directory', 'status' => 'fixed', 'message' => 'Aangemaakt']; } else { $owner = shell_exec("stat -c '%U' {$mavenDir} 2>/dev/null || echo ''"); if (trim($owner ?? '') !== 'www-data') { shell_exec("sudo chown -R www-data:www-data {$mavenDir}"); $this->results[] = ['item' => 'Maven Directory', 'status' => 'fixed', 'message' => 'Permissions gefixt']; } else { $this->results[] = ['item' => 'Maven Directory', 'status' => 'ok', 'message' => 'Al correct']; } } } private function checkAndFixJava(): void { $result = shell_exec('which java 2>/dev/null || echo ""'); if (! in_array(trim($result ?? ''), ['', '0'], true)) { $version = shell_exec('java -version 2>&1 | head -1'); $this->results[] = ['item' => 'Java', 'status' => 'ok', 'message' => trim($version ?? '')]; } else { // Install Java shell_exec('sudo apt-get update && sudo apt-get install -y default-jdk 2>&1'); $result = shell_exec('which java 2>/dev/null || echo ""'); if (! in_array(trim($result ?? ''), ['', '0'], true)) { $this->results[] = ['item' => 'Java', 'status' => 'fixed', 'message' => 'Automatisch geïnstalleerd']; } else { $this->results[] = ['item' => 'Java', 'status' => 'error', 'message' => 'Installatie mislukt']; } } } }