Webbserver - Love Blomberg

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)
<?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($valueENT_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($targetJSON_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($amount2','' ') . ' 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 $typestring $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 $startDateDateTimeImmutable $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;
}