Files
mivo/app/Core/Console.php

241 lines
9.7 KiB
PHP

<?php
namespace App\Core;
class Console {
// ANSI Color Codes
const COLOR_RESET = "\033[0m";
const COLOR_GREEN = "\033[32m";
const COLOR_YELLOW = "\033[33m";
const COLOR_BLUE = "\033[34m";
const COLOR_GRAY = "\033[90m";
const COLOR_RED = "\033[31m";
const COLOR_BOLD = "\033[1m";
public function run($argv) {
$command = $argv[1] ?? 'help';
$args = array_slice($argv, 2);
$this->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.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";
}
}