<?php
// Basic configuration and bootstrap
declare(strict_types=1);
session_start();
/**
* Very small .env loader.
*
* Loads key=value pairs from a .env file in the project root
* into getenv()/$_ENV (lines starting with # are comments).
*/
function load_env(string $path): void
{
if (!is_readable($path)) {
return;
}
$lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if ($lines === false) {
return;
}
foreach ($lines as $line) {
$line = trim($line);
if ($line === '' || str_starts_with($line, '#')) {
continue;
}
$pos = strpos($line, '=');
if ($pos === false) {
continue;
}
$name = trim(substr($line, 0, $pos));
$value = trim(substr($line, $pos + 1));
// Strip optional surrounding quotes
if ((str_starts_with($value, '"') && str_ends_with($value, '"')) ||
(str_starts_with($value, "'") && str_ends_with($value, "'"))) {
$value = substr($value, 1, -1);
}
if ($name !== '') {
putenv($name . '=' . $value);
$_ENV[$name] = $value;
}
}
}
// Load .env from the project root (same dir as this file)
load_env(__DIR__ . '/.env');
// Application timezone: default to US Eastern if not explicitly set.
// This ensures all "today"/"now" calculations and formatted dates
// are anchored to East Coast time across the entire site.
$appTimezone = getenv('APP_TIMEZONE') ?: 'America/New_York';
date_default_timezone_set($appTimezone);
// Database configuration from environment, with sensible defaults.
$dbHost = getenv('DB_HOST');
$dbName = getenv('DB_NAME');
$dbUser = getenv('DB_USER');
$dbPass = getenv('DB_PASS');
// Optional app-level config from env
$appEnv = getenv('APP_ENV') ?: 'production';
$debug = filter_var(getenv('APP_DEBUG') ?: '0', FILTER_VALIDATE_BOOL);
// In debug mode, show mysqli warnings as exceptions
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
$db = new mysqli($dbHost, $dbUser, $dbPass, $dbName);
$db->set_charset('utf8mb4');
} catch (mysqli_sql_exception $e) {
http_response_code(500);
if ($debug) {
echo 'Database connection error: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
} else {
echo 'Database connection error.';
}
exit;
}
// Base path helper (for running under a subdirectory such as /7oclockdinner)
// APP_BASE_PATH can be set in .env, otherwise it falls back to the directory name.
$envBase = getenv('APP_BASE_PATH') ?: '/7oclockdinner';
define('APP_BASE_PATH', rtrim($envBase, '/'));
function url(string $path = ''): string
{
$base = APP_BASE_PATH === '' ? '' : APP_BASE_PATH;
$path = '/' . ltrim($path, '/');
return $base . $path;
}
// Simple helper to get the current path (without query string),
// normalised and with the APP_BASE_PATH prefix stripped.
function current_path(): string
{
$uri = $_SERVER['REQUEST_URI'] ?? '/';
$uri = strtok($uri, '?') ?: '/';
// Normalise multiple slashes
$uri = '/' . trim(preg_replace('#/+#', '/', $uri), '/');
if ($uri === '//') {
$uri = '/';
}
// Strip base path prefix if present (e.g. /7oclockdinner)
if (APP_BASE_PATH !== '' && APP_BASE_PATH !== '/') {
$base = APP_BASE_PATH;
// Ensure base starts with a single leading slash
if ($base[0] !== '/') {
$base = '/' . $base;
}
$base = rtrim($base, '/');
if ($uri === $base || str_starts_with($uri, $base . '/')) {
$uri = substr($uri, strlen($base));
if ($uri === '' || $uri === false) {
$uri = '/';
}
}
}
return $uri === '' ? '/' : $uri;
}
// Simple view renderer
function render_view(string $view, array $data = []): void
{
// Expose the database connection to views
global $db;
extract($data, EXTR_SKIP);
$viewFile = __DIR__ . '/views/' . $view . '.php';
if (!is_file($viewFile)) {
http_response_code(500);
echo 'View not found.';
return;
}
include __DIR__ . '/views/layout/header.php';
include $viewFile;
include __DIR__ . '/views/layout/footer.php';
}
// Simple visit logger
function log_visit(mysqli $db, string $path): void
{
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$ua = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 255);
$userId = $_SESSION['user_id'] ?? null;
$now = (new DateTimeImmutable('now'))->format('Y-m-d H:i:s');
$stmt = $db->prepare('INSERT INTO visits (path, user_id, ip_address, user_agent, created_at) VALUES (?, ?, ?, ?, ?)');
$stmt->bind_param('sisss', $path, $userId, $ip, $ua, $now);
$stmt->execute();
}