113 lines
4 KiB
PHP
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]);
|
|
}
|