FinancePlanner/auth.php
2026-05-29 12:00:49 +01:00

113 lines
4 KiB
PHP

<?php
// ─────────────────────────────────────────────
// auth.php · Session-based authentication
// ─────────────────────────────────────────────
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
function currentUserId(): ?int {
return isset($_SESSION['user']['id']) ? (int)$_SESSION['user']['id'] : null;
}
function currentUser(): ?array {
return $_SESSION['user'] ?? null;
}
function isAdmin(): bool {
return (int)($_SESSION['user']['is_admin'] ?? 0) === 1;
}
function requireLogin(): void {
if (!currentUserId()) {
header('Location: login.php');
exit;
}
}
function requireAdmin(): void {
requireLogin();
if (!isAdmin()) {
http_response_code(403);
echo '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8">'
. '<title>Access Denied · Finance Planner</title>'
. '<link rel="stylesheet" href="style.css"></head>'
. '<body style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:24px">'
. '<div style="text-align:center">'
. '<div style="font-size:3rem;margin-bottom:12px">🚫</div>'
. '<h2 style="margin-bottom:8px">Access Denied</h2>'
. '<p style="color:var(--text-dim);margin-bottom:20px">Admin privileges required.</p>'
. '<a href="index.php" style="color:var(--accent)">← Back to Dashboard</a>'
. '</div></body></html>';
exit;
}
}
/**
* Returns true on success, 'suspended' if account suspended, false on bad credentials.
*/
function attemptLogin(string $username, string $password): bool|string {
require_once __DIR__ . '/db.php';
$db = getDB();
$st = $db->prepare("SELECT * FROM users WHERE username = ? LIMIT 1");
$st->execute([trim($username)]);
$user = $st->fetch();
if (!$user) return false;
if ((int)($user['is_suspended'] ?? 0) === 1) return 'suspended';
if (!password_verify($password, $user['password_hash'])) return false;
$_SESSION['user'] = [
'id' => (int)$user['id'],
'username' => $user['username'],
'display_name' => $user['display_name'] ?? $user['username'],
'is_admin' => (int)($user['is_admin'] ?? 0),
];
return true;
}
function logout(): void {
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$p = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$p['path'], $p['domain'], $p['secure'], $p['httponly']);
}
session_destroy();
}
function changePassword(int $userId, string $currentPassword, string $newPassword): bool {
require_once __DIR__ . '/db.php';
$db = getDB();
$st = $db->prepare("SELECT password_hash FROM users WHERE id = ?");
$st->execute([$userId]);
$row = $st->fetch();
if (!$row || !password_verify($currentPassword, $row['password_hash'])) return false;
$db->prepare("UPDATE users SET password_hash = ? WHERE id = ?")
->execute([password_hash($newPassword, PASSWORD_DEFAULT), $userId]);
return true;
}
// ── App settings (stored in `settings` table) ─────────────────────────────
function getSetting(string $key, string $default = ''): string {
try {
require_once __DIR__ . '/db.php';
$db = getDB();
$st = $db->prepare("SELECT setting_value FROM settings WHERE setting_key = ?");
$st->execute([$key]);
$row = $st->fetch();
return $row ? $row['setting_value'] : $default;
} catch (Exception $e) {
return $default;
}
}
function setSetting(string $key, string $value): void {
require_once __DIR__ . '/db.php';
$db = getDB();
$db->prepare("INSERT INTO settings (setting_key, setting_value) VALUES (?,?)
ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)")
->execute([$key, $value]);
}