PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]; $pdo = new PDO($dsn, DB_USER, DB_PASS, $options); } return $pdo; } /** * Read a value from site_settings table. */ function get_setting(string $key, string $default = ''): string { static $cache = []; if (isset($cache[$key])) return $cache[$key]; try { $st = get_pdo()->prepare('SELECT val FROM site_settings WHERE key_name = ?'); $st->execute([$key]); $row = $st->fetch(); $cache[$key] = $row ? (string)$row['val'] : $default; } catch (PDOException $e) { $cache[$key] = $default; } return $cache[$key]; } /** * Save a value to site_settings table. */ function set_setting(string $key, string $value): void { get_pdo()->prepare('INSERT INTO site_settings (key_name, val) VALUES (?,?) ON DUPLICATE KEY UPDATE val=?') ->execute([$key, $value, $value]); } /** * Slugify a string for use in URLs. */ function slugify(string $text): string { $text = mb_strtolower(trim($text)); $text = preg_replace('/[^a-z0-9\s-]/', '', $text); $text = preg_replace('/[\s-]+/', '-', $text); return trim($text, '-') ?: 'session'; } /** * Generate a slug unique for a given user_id in sessions/novena_groups. * $table: 'sessions' or 'novena_groups', $exclude_id: ID to exclude (for edits) */ function unique_slug(string $base, int $user_id, string $table = 'sessions', ?int $exclude_id = null): string { $slug = slugify($base); $pdo = get_pdo(); $candidate = $slug; $n = 2; while (true) { $sql = "SELECT COUNT(*) FROM {$table} WHERE slug = ? AND user_id = ?"; $params = [$candidate, $user_id]; if ($exclude_id !== null) { $sql .= ' AND id != ?'; $params[] = $exclude_id; } $st = $pdo->prepare($sql); $st->execute($params); if ((int)$st->fetchColumn() === 0) break; $candidate = $slug . '-' . ($n++); if ($n > 999) { $candidate = $slug . '-' . uniqid(); break; } } return $candidate; }