<?php
/**
* Shared helper functions used across public pages and the admin panel.
*/
require_once __DIR__ . '/../config/database.php';
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
/** Escape a string for safe HTML output. */
function e(?string $value): string
{
return htmlspecialchars($value ?? '', ENT_QUOTES, 'UTF-8');
}
/** Fetch the singleton site settings row (cached per request). */
function getSettings(): array
{
static $settings = null;
if ($settings === null) {
$stmt = db()->query('SELECT * FROM settings WHERE id = 1');
$settings = $stmt->fetch() ?: [];
}
return $settings;
}
/** Fetch SEO metadata for a given page key (home, about, services, downloads, contact). */
function getSeo(string $pageKey): array
{
$stmt = db()->prepare('SELECT * FROM seo_pages WHERE page_key = ? LIMIT 1');
$stmt->execute([$pageKey]);
return $stmt->fetch() ?: [
'title' => 'PIMS Nepal',
'meta_description' => '',
'meta_keywords' => '',
'og_image_path' => '',
'canonical_url' => '',
];
}
/** Fetch active navigation links, ordered. */
function getNavLinks(): array
{
return db()->query('SELECT * FROM nav_links WHERE is_active = 1 ORDER BY sort_order ASC, id ASC')->fetchAll();
}
/** Build a public URL for an uploaded/asset file path stored in the DB. */
function assetUrl(?string $path): string
{
if (!$path) {
return '';
}
if (str_starts_with($path, 'http://') || str_starts_with($path, 'https://')) {
return $path;
}
return rtrim(basePath(), '/') . '/' . ltrim($path, '/');
}
/** Base path of the site relative to the domain root (auto-detected). */
function basePath(): string
{
if (defined('SITE_URL') && SITE_URL !== '') {
return SITE_URL;
}
return '';
}
/** Render a set of <meta> tags + <title> for the current page's SEO row. */
function renderSeoTags(array $seo): void
{
echo '<title>' . e($seo['title'] ?? 'PIMS Nepal') . "</title>\n";
if (!empty($seo['meta_description'])) {
echo '<meta name="description" content="' . e($seo['meta_description']) . "\">\n";
}
if (!empty($seo['meta_keywords'])) {
echo '<meta name="keywords" content="' . e($seo['meta_keywords']) . "\">\n";
}
if (!empty($seo['canonical_url'])) {
echo '<link rel="canonical" href="' . e($seo['canonical_url']) . "\">\n";
}
if (!empty($seo['og_image_path'])) {
echo '<meta property="og:image" content="' . e(assetUrl($seo['og_image_path'])) . "\">\n";
}
}
/** Generate (and stash in session) a CSRF token, or return the existing one. */
function csrfToken(): string
{
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
/** Verify a submitted CSRF token against the session's token. */
function csrfVerify(?string $token): bool
{
return !empty($token) && !empty($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
/**
* Very simple per-session rate limiter (e.g. for the contact form) —
* allows up to $max submissions per $windowSeconds.
*/
function rateLimitCheck(string $key, int $max = 5, int $windowSeconds = 60): bool
{
$now = time();
$bucket = $_SESSION['rate_' . $key] ?? ['count' => 0, 'start' => $now];
if ($now - $bucket['start'] > $windowSeconds) {
$bucket = ['count' => 0, 'start' => $now];
}
$bucket['count']++;
$_SESSION['rate_' . $key] = $bucket;
return $bucket['count'] <= $max;
}
/** Decode a JSON TEXT column safely into an array. */
function jdecode(?string $json): array
{
if (!$json) {
return [];
}
$decoded = json_decode($json, true);
return is_array($decoded) ? $decoded : [];
}
/** Redirect helper. */
function redirect(string $url): never
{
header('Location: ' . $url);
exit;
}
/** Is an admin currently logged in? */
function isAdminLoggedIn(): bool
{
return !empty($_SESSION['admin_id']);
}
/** Require admin login or redirect to the admin login page. */
function requireAdmin(): void
{
if (!isAdminLoggedIn()) {
redirect('login.php');
}
}
/** Flash a one-time message to session, read/cleared on next request. */
function flash(string $key, ?string $message = null): ?string
{
if ($message !== null) {
$_SESSION['flash_' . $key] = $message;
return null;
}
$value = $_SESSION['flash_' . $key] ?? null;
unset($_SESSION['flash_' . $key]);
return $value;
}