Add SQLite-backed announcement system and admin portal
- Add SQLite database initialization and management in inc/db.php - Implement session authentication and CSRF security helpers in inc/auth.php - Implement announcement querying and saving in inc/announcements.php - Add management dashboard, login, and logout in admin/ - Protect db/ directory with Apache access controls
This commit is contained in:
1 parent
b9d3262233
commit
9b7d9ceccb
7 files changed
+761
No files matched your search
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* Announcements helper functions
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/db.php';
|
||||
|
||||
function get_active_announcement(): ?array {
|
||||
$pdo = get_db();
|
||||
$today = date('Y-m-d');
|
||||
|
||||
$sql = "
|
||||
SELECT * FROM announcements
|
||||
WHERE is_active = 1
|
||||
AND (start_date IS NULL OR start_date = '' OR start_date <= :today1)
|
||||
AND (end_date IS NULL OR end_date = '' OR end_date >= :today2)
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
':today1' => $today,
|
||||
':today2' => $today
|
||||
]);
|
||||
$result = $stmt->fetch();
|
||||
|
||||
return $result ?: null;
|
||||
}
|
||||
|
||||
function get_all_announcements(): array {
|
||||
$pdo = get_db();
|
||||
$stmt = $pdo->query("SELECT * FROM announcements ORDER BY id DESC");
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
|
||||
function save_announcement(array $data, ?int $id = null): int {
|
||||
$pdo = get_db();
|
||||
|
||||
$isActive = !empty($data['is_active']) ? 1 : 0;
|
||||
$type = in_array($data['type'] ?? '', ['holiday', 'special', 'closure']) ? $data['type'] : 'holiday';
|
||||
$headline = trim($data['headline'] ?? '');
|
||||
$message = trim($data['message'] ?? '');
|
||||
$startDate = !empty($data['start_date']) ? trim($data['start_date']) : null;
|
||||
$endDate = !empty($data['end_date']) ? trim($data['end_date']) : null;
|
||||
$showBanner = !empty($data['show_banner']) ? 1 : 0;
|
||||
$showInHours = !empty($data['show_in_hours']) ? 1 : 0;
|
||||
|
||||
if ($id) {
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE announcements SET
|
||||
is_active = ?,
|
||||
type = ?,
|
||||
headline = ?,
|
||||
message = ?,
|
||||
start_date = ?,
|
||||
end_date = ?,
|
||||
show_banner = ?,
|
||||
show_in_hours = ?,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?
|
||||
");
|
||||
$stmt->execute([
|
||||
$isActive, $type, $headline, $message, $startDate, $endDate,
|
||||
$showBanner, $showInHours, $id
|
||||
]);
|
||||
return $id;
|
||||
} else {
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO announcements (
|
||||
is_active, type, headline, message, start_date, end_date, show_banner, show_in_hours
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
$stmt->execute([
|
||||
$isActive, $type, $headline, $message, $startDate, $endDate,
|
||||
$showBanner, $showInHours
|
||||
]);
|
||||
return (int)$pdo->lastInsertId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Auth & session helper
|
||||
*/
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
// Configure secure session cookie defaults
|
||||
session_set_cookie_params([
|
||||
'lifetime' => 86400 * 7, // 7 days
|
||||
'path' => '/',
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax'
|
||||
]);
|
||||
session_start();
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/db.php';
|
||||
|
||||
function is_authenticated(): bool {
|
||||
return !empty($_SESSION['admin_user_id']);
|
||||
}
|
||||
|
||||
function require_auth(): void {
|
||||
if (!is_authenticated()) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
function get_logged_in_user(): ?array {
|
||||
if (!is_authenticated()) {
|
||||
return null;
|
||||
}
|
||||
return [
|
||||
'id' => $_SESSION['admin_user_id'],
|
||||
'username' => $_SESSION['admin_username'] ?? 'admin',
|
||||
'role' => $_SESSION['admin_role'] ?? 'admin'
|
||||
];
|
||||
}
|
||||
|
||||
function authenticate_user(string $username, string $password): bool {
|
||||
$pdo = get_db();
|
||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
|
||||
$stmt->execute([trim($username)]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user && password_verify($password, $user['password_hash'])) {
|
||||
session_regenerate_id(true);
|
||||
$_SESSION['admin_user_id'] = $user['id'];
|
||||
$_SESSION['admin_username'] = $user['username'];
|
||||
$_SESSION['admin_role'] = $user['role'];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function logout_user(): void {
|
||||
$_SESSION = [];
|
||||
if (ini_get("session.use_cookies")) {
|
||||
$params = session_get_cookie_params();
|
||||
setcookie(session_name(), '', time() - 42000,
|
||||
$params["path"], $params["domain"],
|
||||
$params["secure"], $params["httponly"]
|
||||
);
|
||||
}
|
||||
session_destroy();
|
||||
}
|
||||
|
||||
function get_csrf_token(): string {
|
||||
if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
return $_SESSION['csrf_token'];
|
||||
}
|
||||
|
||||
function verify_csrf_token(?string $token): bool {
|
||||
if (empty($_SESSION['csrf_token']) || empty($token)) {
|
||||
return false;
|
||||
}
|
||||
return hash_equals($_SESSION['csrf_token'], $token);
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Database connection & schema management for SQLite
|
||||
*/
|
||||
|
||||
function get_db(): PDO {
|
||||
static $pdo = null;
|
||||
if ($pdo !== null) {
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
$dbDir = __DIR__ . '/../db';
|
||||
if (!is_dir($dbDir)) {
|
||||
mkdir($dbDir, 0755, true);
|
||||
}
|
||||
|
||||
$dbPath = $dbDir . '/fitz.sqlite';
|
||||
$isNew = !file_exists($dbPath);
|
||||
|
||||
$pdo = new PDO('sqlite:' . $dbPath, null, null, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_TIMEOUT => 5
|
||||
]);
|
||||
|
||||
// Enable WAL mode for concurrency and performance
|
||||
$pdo->exec('PRAGMA journal_mode = WAL;');
|
||||
$pdo->exec('PRAGMA foreign_keys = ON;');
|
||||
|
||||
// Initialize tables if needed
|
||||
init_db_schema($pdo);
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
function init_db_schema(PDO $pdo): void {
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'admin',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS announcements (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
type TEXT NOT NULL DEFAULT 'holiday',
|
||||
headline TEXT NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
start_date TEXT NULL,
|
||||
end_date TEXT NULL,
|
||||
show_banner INTEGER NOT NULL DEFAULT 1,
|
||||
show_in_hours INTEGER NOT NULL DEFAULT 1,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
");
|
||||
|
||||
// Seed default admin user if table is empty (username: admin / password: password)
|
||||
$stmt = $pdo->query("SELECT COUNT(*) as count FROM users");
|
||||
$userCount = $stmt->fetchColumn();
|
||||
if ($userCount == 0) {
|
||||
$defaultPassHash = password_hash('password', PASSWORD_DEFAULT);
|
||||
$insert = $pdo->prepare("INSERT INTO users (username, password_hash, role) VALUES (?, ?, 'admin')");
|
||||
$insert->execute(['admin', $defaultPassHash]);
|
||||
}
|
||||
|
||||
// Seed default Labor Day announcement row if table is empty
|
||||
$stmtAnn = $pdo->query("SELECT COUNT(*) as count FROM announcements");
|
||||
$annCount = $stmtAnn->fetchColumn();
|
||||
if ($annCount == 0) {
|
||||
$insertAnn = $pdo->prepare("
|
||||
INSERT INTO announcements (
|
||||
is_active, type, headline, message, start_date, end_date, show_banner, show_in_hours
|
||||
) VALUES (
|
||||
1, 'holiday', 'Labor Day Closure', 'The Old Fitz will be closed Thursday, Sept 3 through Saturday, Sept 5 for the holiday weekend. Doors reopen Thursday, Sept 10 at 4:00 PM!', NULL, NULL, 1, 1
|
||||
)
|
||||
");
|
||||
$insertAnn->execute();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user