2026-02-18 10:32:06 +00:00

259 lines
13 KiB
PHP

<?php
session_start();
$lockFile = __DIR__ . '/../installed.lock';
if (file_exists($lockFile)) {
die("Installation already completed. Please remove 'installed.lock' if you want to re-install.");
}
$step = isset($_GET['step']) ? (int)$_GET['step'] : 1;
$error = '';
$success = '';
// Step 1: Requirements
if ($step === 1) {
$requirements = [
'php_version' => [
'name' => 'PHP Version (>= 8.0)',
'status' => version_compare(PHP_VERSION, '8.0.0', '>='),
'current' => PHP_VERSION
],
'pdo_mysql' => [
'name' => 'PDO MySQL Extension',
'status' => extension_loaded('pdo_mysql'),
'current' => extension_loaded('pdo_mysql') ? 'Loaded' : 'Missing'
],
'config_writable' => [
'name' => 'db/config.php Writable',
'status' => is_writable(__DIR__ . '/../db/config.php'),
'current' => is_writable(__DIR__ . '/../db/config.php') ? 'Yes' : 'No'
],
'root_writable' => [
'name' => 'Root Directory Writable',
'status' => is_writable(__DIR__ . '/..'),
'current' => is_writable(__DIR__ . '/..') ? 'Yes' : 'No'
]
];
$allOk = true;
foreach ($requirements as $req) {
if (!$req['status']) $allOk = false;
}
}
// Step 2: Database
if ($step === 2 && $_SERVER['REQUEST_METHOD'] === 'POST') {
$host = $_POST['db_host'] ?? '';
$name = $_POST['db_name'] ?? '';
$user = $_POST['db_user'] ?? '';
$pass = $_POST['db_pass'] ?? '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$name", $user, $pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
// Save to config.php
$configContent = "<?php\ndefine('DB_HOST', '$host');\ndefine('DB_NAME', '$name');\ndefine('DB_USER', '$user');\ndefine('DB_PASS', '$pass');\n\nfunction db() {\n static \$pdo;\n if (!\$pdo) {\n \$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASS, [\n PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,\n PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,\n ]);\n }\n return \$pdo;\n}\n";
file_put_contents(__DIR__ . '/../db/config.php', $configContent);
header("Location: index.php?step=3");
exit;
} catch (PDOException $e) {
$error = "Database Connection Failed: " . $e->getMessage();
}
}
// Step 3: Super Admin
if ($step === 3 && $_SERVER['REQUEST_METHOD'] === 'POST') {
require_once __DIR__ . '/../db/config.php';
$adminUser = $_POST['admin_user'] ?? '';
$adminPass = $_POST['admin_pass'] ?? '';
$adminEmail = $_POST['admin_email'] ?? '';
try {
$pdo = db();
// Create tables if they don't exist
$pdo->exec("CREATE TABLE IF NOT EXISTS role_groups (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
permissions TEXT
)");
$pdo->exec("CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
phone VARCHAR(20),
group_id INT,
status ENUM('active', 'inactive') DEFAULT 'active',
profile_pic VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
// Insert Default Admin Role if missing
$stmt = $pdo->prepare("SELECT id FROM role_groups WHERE name = 'Administrator'");
$stmt->execute();
$role = $stmt->fetch();
if (!$role) {
$pdo->exec("INSERT INTO role_groups (name, permissions) VALUES ('Administrator', 'all')");
$roleId = $pdo->lastInsertId();
} else {
$roleId = $role['id'];
}
// Insert Admin User
$hashedPass = password_hash($adminPass, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (username, password, email, group_id, status) VALUES (?, ?, ?, ?, 'active')");
$stmt->execute([$adminUser, $hashedPass, $adminEmail, $roleId]);
header("Location: index.php?step=4");
exit;
} catch (Exception $e) {
$error = "Setup Failed: " . $e->getMessage();
}
}
// Step 4: Finish
if ($step === 4) {
file_put_contents($lockFile, date('Y-m-d H:i:s'));
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Installation - Step <?= $step ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
<style>
body { background: #f0f2f5; font-family: 'Inter', sans-serif; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; }
.install-container { width: 100%; max-width: 600px; padding: 20px; }
.card { border: none; border-radius: 20px; box-shadow: 0 10px 40px rgba(0,0,0,0.08); overflow: hidden; }
.card-header { background: linear-gradient(135deg, #6e8efb, #a777e3); color: white; border: none; padding: 30px; text-align: center; }
.step-indicator { display: flex; justify-content: space-between; margin-bottom: 30px; position: relative; }
.step-indicator::before { content: ''; position: absolute; top: 15px; left: 0; right: 0; height: 2px; background: #e0e0e0; z-index: 1; }
.step-dot { width: 32px; height: 32px; background: #fff; border: 2px solid #e0e0e0; border-radius: 50%; display: flex; align-items: center; justify-content: center; z-index: 2; font-weight: bold; font-size: 14px; color: #999; }
.step-dot.active { border-color: #6e8efb; color: #6e8efb; background: #fff; box-shadow: 0 0 10px rgba(110, 142, 251, 0.3); }
.step-dot.completed { background: #6e8efb; border-color: #6e8efb; color: #fff; }
.btn-primary { background: linear-gradient(135deg, #6e8efb, #a777e3); border: none; border-radius: 12px; padding: 12px 24px; font-weight: 600; }
.form-control { border-radius: 12px; padding: 12px; border: 1px solid #dee2e6; }
</style>
</head>
<body>
<div class="install-container">
<div class="card">
<div class="card-header">
<h3 class="fw-bold mb-0">System Installation</h3>
<p class="mb-0 opacity-75">Configure your application in minutes</p>
</div>
<div class="card-body p-4 p-md-5">
<div class="step-indicator">
<div class="step-dot <?= $step >= 1 ? ($step > 1 ? 'completed' : 'active') : '' ?>"><?= $step > 1 ? '<i class="bi bi-check"></i>' : '1' ?></div>
<div class="step-dot <?= $step >= 2 ? ($step > 2 ? 'completed' : 'active') : '' ?>"><?= $step > 2 ? '<i class="bi bi-check"></i>' : '2' ?></div>
<div class="step-dot <?= $step >= 3 ? ($step > 3 ? 'completed' : 'active') : '' ?>"><?= $step > 3 ? '<i class="bi bi-check"></i>' : '3' ?></div>
<div class="step-dot <?= $step >= 4 ? 'completed' : '' ?>">4</div>
</div>
<?php if ($error): ?>
<div class="alert alert-danger d-flex align-items-center mb-4">
<i class="bi bi-exclamation-triangle-fill me-2"></i>
<div><?= $error ?></div>
</div>
<?php endif; ?>
<?php if ($step === 1): ?>
<h5 class="fw-bold mb-4">Step 1: Check Requirements</h5>
<div class="list-group list-group-flush mb-4">
<?php foreach ($requirements as $req): ?>
<div class="list-group-item d-flex justify-content-between align-items-center py-3">
<div>
<h6 class="mb-0 fw-semibold"><?= $req['name'] ?></h6>
<small class="text-muted">Current: <?= $req['current'] ?></small>
</div>
<?php if ($req['status']): ?>
<span class="badge bg-success-subtle text-success rounded-pill px-3">Passed</span>
<?php else: ?>
<span class="badge bg-danger-subtle text-danger rounded-pill px-3">Failed</span>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php if ($allOk): ?>
<div class="d-grid">
<a href="index.php?step=2" class="btn btn-primary">Next: Database Setup</a>
</div>
<?php else: ?>
<div class="alert alert-warning small">Please fix the issues above to continue.</div>
<div class="d-grid">
<button onclick="window.location.reload()" class="btn btn-secondary">Retry Check</button>
</div>
<?php endif; ?>
<?php elseif ($step === 2): ?>
<h5 class="fw-bold mb-4">Step 2: Database Configuration</h5>
<form method="POST">
<div class="mb-3">
<label class="form-label small fw-bold">Database Host</label>
<input type="text" name="db_host" class="form-control" value="127.0.0.1" required>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Database Name</label>
<input type="text" name="db_name" class="form-control" placeholder="e.g. admin_db" required>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Database User</label>
<input type="text" name="db_user" class="form-control" placeholder="e.g. root" required>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Database Password</label>
<input type="password" name="db_pass" class="form-control" placeholder="Enter password">
</div>
<div class="d-grid mt-4">
<button type="submit" class="btn btn-primary">Verify & Save Config</button>
</div>
</form>
<?php elseif ($step === 3): ?>
<h5 class="fw-bold mb-4">Step 3: Super Admin Setup</h5>
<form method="POST">
<div class="mb-3">
<label class="form-label small fw-bold">Admin Username</label>
<input type="text" name="admin_user" class="form-control" placeholder="e.g. admin" required>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Admin Email</label>
<input type="email" name="admin_email" class="form-control" placeholder="admin@example.com" required>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Admin Password</label>
<input type="password" name="admin_pass" class="form-control" placeholder="Minimum 6 characters" required minlength="6">
</div>
<div class="d-grid mt-4">
<button type="submit" class="btn btn-primary">Finish Installation</button>
</div>
</form>
<?php elseif ($step === 4): ?>
<div class="text-center py-4">
<div class="display-1 text-success mb-4">
<i class="bi bi-check-circle-fill"></i>
</div>
<h4 class="fw-bold">Ready to Launch!</h4>
<p class="text-muted">Installation completed successfully. Your system is now secure and ready to use.</p>
<div class="alert alert-info small mt-4">
<i class="bi bi-info-circle me-2"></i>
For security, the <code>installed.lock</code> file has been created.
</div>
<div class="d-grid mt-5">
<a href="../index.php" class="btn btn-primary">Go to Dashboard</a>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
</body>
</html>