printBanner(); switch ($command) { case 'serve': $this->commandServe($args); break; case 'key:generate': $this->commandKeyGenerate(); break; case 'admin:reset': $this->commandAdminReset($args); break; case 'install': $this->commandInstall($args); break; case 'help': default: $this->commandHelp(); break; } } private function printBanner() { echo "\n"; echo self::COLOR_BOLD . " MIVO Helper " . self::COLOR_RESET . self::COLOR_GRAY . "v1.1.0" . self::COLOR_RESET . "\n\n"; } private function commandServe($args) { $host = '0.0.0.0'; $port = 8000; foreach ($args as $arg) { if (strpos($arg, '--port=') === 0) { $port = (int) substr($arg, 7); } if (strpos($arg, '--host=') === 0) { $host = substr($arg, 7); } } echo " " . self::COLOR_GREEN . "Server running on:" . self::COLOR_RESET . "\n"; echo " - Local: " . self::COLOR_BLUE . "http://localhost:$port" . self::COLOR_RESET . "\n"; $hostname = gethostname(); $ip = gethostbyname($hostname); if ($ip !== '127.0.0.1' && $ip !== 'localhost') { echo " - Network: " . self::COLOR_BLUE . "http://$ip:$port" . self::COLOR_RESET . "\n"; } echo "\n " . self::COLOR_GRAY . "Press Ctrl+C to stop" . self::COLOR_RESET . "\n\n"; $cmd = sprintf("php -S %s:%d -t public public/index.php", $host, $port); passthru($cmd); } private function commandKeyGenerate() { echo self::COLOR_YELLOW . "Generating new application key..." . self::COLOR_RESET . "\n"; // Generate 32 bytes of random data for AES-256 $key = bin2hex(random_bytes(16)); // 32 chars hex $envPath = ROOT . '/.env'; $examplePath = ROOT . '/.env.example'; // Copy example if .env doesn't exist if (!file_exists($envPath)) { echo self::COLOR_BLUE . "Copying .env.example to .env..." . self::COLOR_RESET . "\n"; if (file_exists($examplePath)) { copy($examplePath, $envPath); } else { echo self::COLOR_RED . "Error: .env.example not found." . self::COLOR_RESET . "\n"; return; } } // Read .env $content = file_get_contents($envPath); // Replace or Append APP_KEY if (strpos($content, 'APP_KEY=') !== false) { $newContent = preg_replace( "/APP_KEY=.*/", "APP_KEY=$key", $content ); } else { $newContent = $content . "\nAPP_KEY=$key"; } file_put_contents($envPath, $newContent); echo self::COLOR_GREEN . "Application key set successfully in .env." . self::COLOR_RESET . "\n"; echo self::COLOR_GRAY . "Key: " . $key . self::COLOR_RESET . "\n"; echo self::COLOR_YELLOW . "Please ensure .env is not committed to version control." . self::COLOR_RESET . "\n"; } private function commandAdminReset($args) { $username = 'admin'; $password = $args[0] ?? 'admin'; echo self::COLOR_YELLOW . "Resetting password for user '$username'..." . self::COLOR_RESET . "\n"; try { $db = \App\Core\Database::getInstance(); $hash = password_hash($password, PASSWORD_DEFAULT); // Check if user exists first $check = $db->query("SELECT id FROM users WHERE username = ?", [$username])->fetch(); if ($check) { $db->query("UPDATE users SET password = ? WHERE username = ?", [$hash, $username]); echo self::COLOR_GREEN . "Password updated successfully." . self::COLOR_RESET . "\n"; } else { // Determine if we should create it echo self::COLOR_YELLOW . "User '$username' not found. Creating..." . self::COLOR_RESET . "\n"; $db->query("INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)", [ $username, $hash, date('Y-m-d H:i:s') ]); echo self::COLOR_GREEN . "User created successfully." . self::COLOR_RESET . "\n"; } echo "New Password: " . self::COLOR_BOLD . $password . self::COLOR_RESET . "\n"; } catch (\Exception $e) { echo self::COLOR_RED . "Error: " . $e->getMessage() . self::COLOR_RESET . "\n"; } } private function commandInstall($args) { echo self::COLOR_BLUE . "=== MIVO Installer ===" . self::COLOR_RESET . "\n"; // 1. Database Migration echo "Setting up database...\n"; try { if (\App\Core\Migrations::up()) { echo self::COLOR_GREEN . "Database schema created successfully." . self::COLOR_RESET . "\n"; } } catch (\Exception $e) { echo self::COLOR_RED . "Migration Error: " . $e->getMessage() . self::COLOR_RESET . "\n"; return; } // 2. Encryption Key echo "Generating encryption key...\n"; $envPath = ROOT . '/.env'; $keyExists = false; if (file_exists($envPath)) { $envIds = parse_ini_file($envPath); if (!empty($envIds['APP_KEY']) && $envIds['APP_KEY'] !== 'mikhmonv3remake_secret_key_32bytes') { $keyExists = true; } } if (!$keyExists) { $this->commandKeyGenerate(); } else { echo self::COLOR_YELLOW . "Secret key already set in .env. Skipping." . self::COLOR_RESET . "\n"; } // 3. Admin Account echo "Create Admin Account? [Y/n] "; $handle = fopen("php://stdin", "r"); $line = trim(fgets($handle)); if (strtolower($line) != 'n') { echo "Username [admin]: "; $user = trim(fgets($handle)); if (empty($user)) $user = 'admin'; echo "Password [admin]: "; $pass = trim(fgets($handle)); if (empty($pass)) $pass = 'admin'; // Re-use admin reset logic slightly modified or called directly $this->commandAdminReset([$pass]); // Simplification: admin:reset implementation uses hardcoded user='admin' currently, need to update it to support custom username if we want full flexibility. // Wait, my commandAdminReset implementation uses hardcoded 'admin'. // I should update commandAdminReset to accept username as argument or just replicate logic here. // Replicating logic for clarity here. /* Actually, commandAdminReset as currently implemented takes password as arg[0] and uses 'admin' as username. User requested robust install. I will just run the logic manually here to respect the inputted username. */ try { $db = \App\Core\Database::getInstance(); $hash = password_hash($pass, PASSWORD_DEFAULT); $check = $db->query("SELECT id FROM users WHERE username = ?", [$user])->fetch(); if ($check) { $db->query("UPDATE users SET password = ? WHERE username = ?", [$hash, $user]); echo self::COLOR_GREEN . "User '$user' updated." . self::COLOR_RESET . "\n"; } else { $db->query("INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)", [$user, $hash, date('Y-m-d H:i:s')]); echo self::COLOR_GREEN . "User '$user' created." . self::COLOR_RESET . "\n"; } } catch (\Exception $e) { echo self::COLOR_RED . "Error creating user: " . $e->getMessage() . self::COLOR_RESET . "\n"; } } echo "\n" . self::COLOR_GREEN . "Installation Completed Successfully!" . self::COLOR_RESET . "\n"; echo "You can now run: " . self::COLOR_YELLOW . "php mivo serve" . self::COLOR_RESET . "\n"; } private function commandHelp() { echo self::COLOR_YELLOW . "Usage:" . self::COLOR_RESET . "\n"; echo " php mivo [command] [options]\n\n"; echo self::COLOR_YELLOW . "Available commands:" . self::COLOR_RESET . "\n"; echo " " . self::COLOR_GREEN . "install " . self::COLOR_RESET . " Install MIVO (Setup DB & Admin)\n"; echo " " . self::COLOR_GREEN . "serve " . self::COLOR_RESET . " Start the development server\n"; echo " " . self::COLOR_GREEN . "key:generate " . self::COLOR_RESET . " Set the application key\n"; echo " " . self::COLOR_GREEN . "admin:reset " . self::COLOR_RESET . " Reset admin password (default: admin)\n"; echo " " . self::COLOR_GREEN . "help " . self::COLOR_RESET . " Show this help message\n"; echo "\n"; } }