Skip to content

Session Management

Systém pro správu PHP sessions s vlastní konfigurací, bezpečností a logika pro expiraci.

Přehled

Petrovo CMS používá vlastní Session wrapper kolem PHP sessions. Poskytuje:

  • Jednoduchou APISession::get(), Session::set(), Session::delete()
  • Automatický start – Session se spouští on-demand
  • Custom session ID – Bezpečnější ID generování
  • Periodic cleanup – Automatické čištění zastaralých session souborů
  • Vnořené hodnoty – Přístup k nested hodnotám přes dvoutečku user:name

Konfigurace – session.yaml

Konfigurační soubor /config/session.yaml definuje chování PHP sessions:

# Backend pro uložení sessions
save_handler: 'files'
save_path: '/var/sessions'

# Garbage collection – jak často se spustí čištění
gc_probability: 1
gc_maxlifetime: 1800      # 30 minut – maximální lifetime session

# Cookie nastavení
name: 'PHPSESSID'
cookie_httponly: true     # Zákaz přístupu z JavaScript (XSS ochrana)
use_only_cookies: true    # Session ID jen v cookies, ne v URL
use_strict_mode: true     # Validace Session ID
use_trans_sid: false      # Žádné transparent SID
cookie_secure: true       # Jen HTTPS cookies
cookie_samesite: 'Strict' # CSRF ochrana (problém s card payment přesměrováním)

Bezpečnostní nastavení:

  • cookie_httponly: true – JavaScript nemůže číst session cookie (XSS ochrana)
  • use_only_cookies: true – Session ID jen v cookies, ne v URL
  • use_strict_mode: true – Nové SID, když se přijme neznámé ID
  • cookie_secure: true – Jen HTTPS (v produkci)
  • cookie_samesite: 'Strict' – CSRF ochrana, ale problém s card payment přesměrováním (Proto disabled!)

Session Třída

Inicializace

use Petrovo\Session\Session;

// Session se automaticky spouští on-demand
// Nebo explicitně:
Session::start();

Co start() dělá:

  1. Kontroluje, zda session již běží
  2. Načte konfiguraci z session.yaml
  3. Validuje cestu pro uložení session souborů
  4. Generuje custom Session ID, pokud neexistuje
  5. Spouští session
  6. Provede periodic cleanup zastaralých session souborů

Metody

Session::get(string $key): mixed

Získá hodnotu z session.

use Petrovo\Session\Session;

// Jednoduché hodnoty
$userId = Session::get('user_id');

// Dot-notation pro nested values
$userName = Session::get('user:name');
$email = Session::get('user:profile:email');

// Vrátí null, pokud klíč neexistuje
$value = Session::get('non_existent');  // null

Session::set(mixed $key, mixed $value): mixed

Nastaví hodnotu v session.

// Jednoduché hodnoty
Session::set('user_id', 123);
Session::set('cart_items', 5);

// Nested hodnoty (vytvoří strukturu)
Session::set('user:name', 'John');
Session::set('user:profile:email', 'john@example.com');

// Vrátí nastavenou hodnotu
$result = Session::set('key', 'value');  // 'value'

Session::delete(mixed $key): void

Smaže hodnotu z session.

// Smazat jednoduchou hodnotu
Session::delete('user_id');

// Smazat nested hodnotu
Session::delete('user:profile');  // Smaže celý profil

Session::getAll(): array

Vrátí všechny session hodnoty.

$allData = Session::getAll();
// Vrátí: $_SESSION

var_dump($allData);
// Array (
//   [user_id] => 123,
//   [user] => Array([name] => 'John', ...),
//   ...
// )

Příklady

Login workflow:

// Login
Session::set('user_id', $user['id']);
Session::set('user:name', $user['name']);
Session::set('user:email', $user['email']);
Session::set('admin', true);

// Použití v šablonách
$userId = Session::get('user_id');
if (Session::get('admin')) {
    echo 'Přihlášený admin';
}

// Logout
Session::delete('user_id');
Session::delete('user');
Session::delete('admin');

Nákupní košík:

// Přidání do košíku
$cart = Session::get('cart') ?? [];
$cart[] = ['product_id' => 42, 'qty' => 1];
Session::set('cart', $cart);

// Počet položek v košíku
$itemCount = count(Session::get('cart') ?? []);

// Vyprázdnění košíku
Session::delete('cart');

Flash data (jednorazové zprávy):

// Nastavit flash zprávu
Session::set('flash:message', 'Změny byly uloženy!');
Session::set('flash:type', 'success');

// V šablonách
if ($message = Session::get('flash:message')) {
    echo $message;
    Session::delete('flash:message');
}

Middleware – Admin Session Expiration

Middleware sessionExpirationAdminMiddleware kontroluje expiraci admin session.

Umístění: /app/Middlewares/Session/sessionExpirationAdminMiddleware.php

Jak funguje

  1. Čte timeout z config/session.yaml (gc_maxlifetime)
  2. Kontroluje last activity – čas poslední aktivity v session
  3. Pokud vypršel timeout → vyprázdní session a přesměruje na login
  4. Aktualizuje last_activity – zaznamenání nové aktivity
$options = Cache::file(DIR . '/config/session.yaml');
$lifeTime = $options['gc_maxlifetime'];  // 1800 sekund = 30 minut

// Kontrola expiraci
$lastActivity = Session::get('last_activity');
if (isset($lastActivity) && (time() - $lastActivity) > $lifeTime) {
    // Session vypršela – logout
    session_unset();
    session_destroy();
    redirect(loginUrl);
}

// Aktualizace aktivity
Session::set('last_activity', time());

Praktické scénáře

Scénář 1: Admin pracuje aktivně

10:00 - Admin se přihlásí
        last_activity = 10:00

10:15 - Admin kliká na stránky
        Middleware kontroluje: 10:15 - 10:00 = 15 minut < 30 minut (OK)
        last_activity = 10:15

10:30 - Admin kliká
        Middleware kontroluje: 10:30 - 10:15 = 15 minut < 30 minut (OK)
        last_activity = 10:30

10:45 - Admin se neaktivní
        (žádné klikání)

Scénář 2: Admin se nechal sedět

10:00 - Admin se přihlásí
        last_activity = 10:00

10:40 - Admin se vrátí a kliká
        Middleware kontroluje: 10:40 - 10:00 = 40 minut > 30 minut (VYPRŠELO)
        Session VYPRŠELA → session_unset() → session_destroy()
        Přesměrování na login

Integraci do middleware pipeline

Middleware se načítá v /app/bootstrap.php pro admin pipeline:

// app/bootstrap.php

$app->pipe('/ADMIN', sessionExpirationAdminMiddleware);
// Ostatní admin middleware...

Spouští se na každý admin request PŘED kontrolerům.

Cleanup Logika

Session soubory se akumulují na disku. Session::start() provádí periodic cleanup:

private static function cleanup(string $path, int $lifetime): void
{
    $lifetime += 120;  // +2 minuty buffer
    $lastCleanFile = $path . '/last_clean';

    if (!file_exists($lastCleanFile)) {
        touch($lastCleanFile);
    }

    $lastCleanTimestamp = filemtime($lastCleanFile);
    if (time() - $lastCleanTimestamp > $lifetime) {
        touch($lastCleanFile);  // Aktualizace timesteampu
    }
}

Jak to funguje:

  • Sleduje soubor /var/sessions/last_clean
  • Pokud od poslední kontroly uplynulo víc než gc_maxlifetime, dotkneme se souboru
  • PHP pak provede garbage collection (smaže staré session soubory)

Proč to takhle? – Aby se neprovádělo cleanup na každém request (drahé), ale jen periodicky.

Bezpečnostní Best Practices

Správně

// Bezpečné – session je vždy HTTP-only, HTTPS-only
Session::set('user_id', $userId);
Session::set('token', hash('sha256', $secret));

// Bezpečné – logout smaže všechna data
Session::delete('user_id');
session_destroy();

// Bezpečné – regenerace Session ID po loginu
session_regenerate_id(true);
Session::set('user_id', $userId);

Nebezpečně

// Neukládat hesla v session
Session::set('password', $plainPassword);

// Neukládat citlivé tokeny bez hashu
Session::set('api_key', $rawApiKey);

// Neměnit session ID po loginu – Session fixation útok!

Časté Problémy

Session data zmizejí

Příčina: Session timeout v gc_maxlifetime

// Kontrola v middleware
$lifeTime = 1800;  // 30 minut
if (time() - $lastActivity > $lifeTime) {
    // Data byla smazána!
}

Řešení: Zvýšit timeout nebo refresh stránky

Není možné zapisovat session soubory

Příčina: /var/sessions není writable

# Kontrola
ls -la var/sessions

# Oprava
chmod 755 var/sessions

Příčina: cookie_secure: true vyžaduje HTTPS

// V .env dev prostředí
APP_ENV=dev

// A nebo vypnout cookie_secure pro dev
# config/session.yaml
cookie_secure: false  # Dev only!

Konfigurace pro vývoj vs produkci

Development (.env dev)

# config/session.yaml (dev)
gc_maxlifetime: 7200      # 2 hodiny
cookie_secure: false      # Bez HTTPS
cookie_samesite: 'Lax'    # Tolerantní

Production (.env prod)

# config/session.yaml (prod)
gc_maxlifetime: 1800      # 30 minut (krátko!)
cookie_secure: true       # Jen HTTPS
cookie_samesite: 'Strict' # Striktní

API Reference

Metoda Parametry Vrací Popis
start() - bool Spustí session, vrátí true pokud nová
get(key) string mixed Získá hodnotu (dot-notation)
getAll() - array Vrátí všechny session hodnoty
set(key, value) mixed, mixed mixed Nastaví hodnotu, vrátí ji
delete(key) mixed void Smaže hodnotu

Reference