= 7.4' => version_compare(PHP_VERSION, '7.4.0', '>='),
'PDO Extension' => extension_loaded('pdo'),
'PDO MySQL Extension' => extension_loaded('pdo_mysql'),
'Config Directory Writable' => is_writable(__DIR__ . '/db/'),
'Uploads Directory Writable' => is_writable(__DIR__ . '/uploads/') || (mkdir(__DIR__ . '/uploads/', 0777, true) && is_writable(__DIR__ . '/uploads/')),
];
$all_requirements_met = !in_array(false, $requirements, true);
// Current step
$step = isset($_GET['step']) ? (int)$_GET['step'] : 1;
// Handle form submissions
$error = '';
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($step === 2) {
// Save database configuration
$host = $_POST['db_host'] ?? '127.0.0.1';
$name = $_POST['db_name'] ?? 'app_database';
$user = $_POST['db_user'] ?? 'root';
$password = $_POST['db_pass'] ?? '';
// Test connection
try {
$test_pdo = new PDO("mysql:host=$host;dbname=$name;charset=utf8mb4", $user, $password);
$test_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Generate config file content
$content = "setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
";
$content .= " \$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
";
$content .= " \$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
";
$content .= " } catch (PDOException \$e) {\n";
$content .= " die('Connection failed: ' . \$e->getMessage());\n";
$content .= " }\n";
$content .= " }\n";
$content .= " return \$pdo;\n";
$content .= " }\n";
$content .= "}\n";
if (file_put_contents($config_file, $content)) {
header('Location: ' . htmlspecialchars($_SERVER['SCRIPT_NAME']) . '?step=3');
exit;
} else {
$error = "Failed to write configuration file to $config_file. Please check permissions.";
}
} catch (PDOException $e) {
$error = "Connection failed: " . $e->getMessage();
}
} elseif ($step === 3) {
// Run migrations
if (!file_exists($config_file)) {
$error = "Configuration file not found. Please go back to Step 2.";
} else {
try {
require_once $config_file;
if (!function_exists('db')) {
throw new Exception("The 'db()' function is not defined in your config file.");
}
$pdo = db();
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
// Create migration table if not exists
$pdo->exec("CREATE TABLE IF NOT EXISTS migrations (
id INT AUTO_INCREMENT PRIMARY KEY,
migration_name VARCHAR(255) NOT NULL UNIQUE,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
$migrations_dir = __DIR__ . '/db/migrations/';
$files = glob($migrations_dir . '*.sql');
if ($files === false) $files = [];
sort($files);
$applied = 0;
$errors = [];
foreach ($files as $file) {
$migration_name = basename($file);
// Check if already applied
$stmt = $pdo->prepare("SELECT id FROM migrations WHERE migration_name = ?");
$stmt->execute([$migration_name]);
if ($stmt->fetch()) {
continue;
}
$sql = file_get_contents($file);
if (empty($sql)) continue;
// Split SQL into individual statements by ; followed by newline
$statements = preg_split('/;(?:\\s*[
]+)/', $sql);
$file_success = true;
foreach ($statements as $stmt_sql) {
$stmt_sql = trim($stmt_sql);
if (empty($stmt_sql)) continue;
// Basic comment removal
$stmt_lines = explode("\n", $stmt_sql);
$clean_stmt = "";
foreach ($stmt_lines as $line) {
if (trim(substr(trim($line), 0, 2)) === '--') continue;
$clean_stmt .= $line . "\n";
}
$clean_stmt = trim($clean_stmt);
if (empty($clean_stmt)) continue;
try {
$res = $pdo->query($clean_stmt);
if ($res) {
$res->closeCursor();
}
} catch (Throwable $e) {
$msg = $e->getMessage();
// If the error is about a table already existing, it's fine
if (strpos($msg, "already exists") !== false ||
strpos($msg, "Duplicate column") !== false ||
strpos($msg, "Duplicate entry") !== false ||
strpos($msg, "already a column") !== false ||
strpos($msg, "Duplicate key") !== false ||
strpos($msg, "errno: 121") !== false) {
continue;
} else {
$errors[] = $migration_name . " at statement: " . substr($clean_stmt, 0, 50) . "... Error: " . $msg;
$file_success = false;
break;
}
}
}
if ($file_success) {
$ins = $pdo->prepare("INSERT INTO migrations (migration_name) VALUES (?)");
$ins->execute([$migration_name]);
$applied++;
}
}
if (empty($errors)) {
$success = "Successfully applied migrations.";
header('Location: ' . htmlspecialchars($_SERVER['SCRIPT_NAME']) . '?step=4');
exit;
} else {
$error = "Applied migrations, but some errors occurred:
We will now run the SQL scripts to set up your database tables.
The system is ready to use. For security, please delete install.php or rename it.