Show sourcecode
The following files exists in this folder. Click to view.
public_html/smartkortet/includes/
auth.php
data.php
functions.php
layout.php
functions.php
251 lines UTF-8 Windows (CRLF)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
<?php
declare(strict_types=1);
function config(?string $key = null)
{
static $config = null;
if ($config === null) {
$config = require __DIR__ . '/../config/app.php';
date_default_timezone_set($config['timezone']);
}
if ($key === null) {
return $config;
}
return $config[$key] ?? null;
}
function e(string $value): string
{
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
function url(string $path = ''): string
{
$base = rtrim((string) config('base_url'), '/');
$path = ltrim($path, '/');
if ($path === '') {
return $base !== '' ? $base : '/';
}
if ($base === '') {
return '/' . $path;
}
return $base . '/' . $path;
}
function redirect(string $path): void
{
$target = url($path);
if (!headers_sent()) {
header('Location: ' . $target);
exit;
}
// Fallback when output has already started and HTTP headers can no longer be changed.
echo '<script>window.location.replace(' . json_encode($target, JSON_UNESCAPED_UNICODE) . ');</script>';
echo '<noscript><meta http-equiv="refresh" content="0;url=' . e($target) . '"></noscript>';
exit;
}
function startAppSession(): void
{
if (session_status() === PHP_SESSION_ACTIVE) {
return;
}
$lifetime = 60 * 60 * 24 * 180; // 180 days
$secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| (isset($_SERVER['SERVER_PORT']) && (int) $_SERVER['SERVER_PORT'] === 443);
ini_set('session.gc_maxlifetime', (string) $lifetime);
ini_set('session.cookie_lifetime', (string) $lifetime);
ini_set('session.use_strict_mode', '1');
session_set_cookie_params([
'lifetime' => $lifetime,
'path' => '/',
'domain' => '',
'secure' => $secure,
'httponly' => true,
'samesite' => 'Lax',
]);
session_start();
// Sliding expiration: renew cookie on each request.
if (!headers_sent()) {
setcookie(session_name(), session_id(), [
'expires' => time() + $lifetime,
'path' => '/',
'domain' => '',
'secure' => $secure,
'httponly' => true,
'samesite' => 'Lax',
]);
}
}
function csrfToken(): string
{
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
function verifyCsrf(): void
{
$token = $_POST['csrf_token'] ?? '';
if (!hash_equals($_SESSION['csrf_token'] ?? '', $token)) {
setFlash('error', 'Sessionen har uppdaterats. Försök igen.');
$backPath = $_SERVER['REQUEST_URI'] ?? '/index.php';
redirect($backPath);
}
}
function formatCurrency(float $amount): string
{
return number_format($amount, 2, ',', ' ') . ' kr';
}
function parseAmount(string $value): float
{
$normalized = str_replace(',', '.', trim($value));
return (float) $normalized;
}
function normalizeNullableString(?string $value): ?string
{
$trimmed = trim((string) $value);
return $trimmed === '' ? null : $trimmed;
}
function normalizeIsoDate(?string $value, ?string $fallback = null): string
{
$candidate = trim((string) $value);
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $candidate) === 1) {
return $candidate;
}
return $fallback ?? date('Y-m-d');
}
function normalizeYearMonth(?string $value, ?string $fallback = null): string
{
$candidate = trim((string) $value);
if (preg_match('/^\d{4}-\d{2}$/', $candidate) === 1) {
return $candidate;
}
return $fallback ?? date('Y-m');
}
function setFlash(string $type, string $message): void
{
$_SESSION['flash'] = [
'type' => $type,
'message' => $message,
];
}
function getFlash(): ?array
{
if (empty($_SESSION['flash'])) {
return null;
}
$flash = $_SESSION['flash'];
unset($_SESSION['flash']);
return $flash;
}
function getSwedishPublicHolidayDates(int $year): array
{
static $cache = [];
if (isset($cache[$year])) {
return $cache[$year];
}
$easterSunday = new DateTimeImmutable(date('Y-m-d', easter_date($year)));
$midsummerDay = null;
for ($day = 20; $day <= 26; $day++) {
$candidate = new DateTimeImmutable(sprintf('%04d-06-%02d', $year, $day));
if ((int) $candidate->format('N') === 6) {
$midsummerDay = $candidate;
break;
}
}
$allSaintsDay = null;
for ($offset = 0; $offset <= 6; $offset++) {
$candidate = new DateTimeImmutable(sprintf('%04d-10-31', $year));
$candidate = $candidate->modify('+' . $offset . ' days');
if ((int) $candidate->format('N') === 6) {
$allSaintsDay = $candidate;
break;
}
}
$holidays = [
sprintf('%04d-01-01', $year), // Nyarsdagen
sprintf('%04d-01-06', $year), // Trettondedag jul
$easterSunday->modify('-2 days')->format('Y-m-d'), // Langfredagen
$easterSunday->format('Y-m-d'), // Paskdagen
$easterSunday->modify('+1 day')->format('Y-m-d'), // Annandag pask
sprintf('%04d-05-01', $year), // Forsta maj
$easterSunday->modify('+39 days')->format('Y-m-d'), // Kristi himmelsfardsdag
$easterSunday->modify('+49 days')->format('Y-m-d'), // Pingstdagen
sprintf('%04d-06-06', $year), // Nationaldagen
$midsummerDay !== null ? $midsummerDay->format('Y-m-d') : null, // Midsommardagen
$allSaintsDay !== null ? $allSaintsDay->format('Y-m-d') : null, // Alla helgons dag
sprintf('%04d-12-25', $year), // Juldagen
sprintf('%04d-12-26', $year), // Annandag jul
];
$cache[$year] = array_values(array_filter($holidays));
return $cache[$year];
}
function isSwedishPublicHoliday(DateTimeImmutable $date): bool
{
$year = (int) $date->format('Y');
return in_array($date->format('Y-m-d'), getSwedishPublicHolidayDates($year), true);
}
function countSwedishBusinessDays(DateTimeImmutable $startDate, DateTimeImmutable $endDate): int
{
if ($startDate > $endDate) {
return 0;
}
$count = 0;
$current = $startDate;
while ($current <= $endDate) {
$weekday = (int) $current->format('N');
$isWeekend = $weekday >= 6;
if (!$isWeekend && !isSwedishPublicHoliday($current)) {
$count++;
}
$current = $current->modify('+1 day');
}
return $count;
}