HEX
Server: LiteSpeed
System: Linux d8 4.18.0-553.121.1.lve.el8.x86_64 #1 SMP Thu Apr 30 16:40:41 UTC 2026 x86_64
User: wbwebdes (3015)
PHP: 8.1.31
Disabled: exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Upload Files
File: /home/wbwebdes/domains/uren-registratie.blankevoort.net/public_html/src/Security/SessionHandler.php
<?php

/*
 * This file is part of the Kimai time-tracking app.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace App\Security;

use Doctrine\DBAL\Connection;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\RateLimiter\RateLimiterFactory;

final class SessionHandler extends PdoSessionHandler
{
    public function __construct(
        Connection $connection,
        private readonly RateLimiterFactory $sessionPredictionLimiter,
        private readonly RequestStack $requestStack
    )
    {
        parent::__construct($connection->getNativeConnection(), [
            'db_table' => 'kimai2_sessions',
            'db_id_col' => 'id',
            'db_data_col' => 'data',
            'db_lifetime_col' => 'lifetime',
            'db_time_col' => 'time',
            'lock_mode' => PdoSessionHandler::LOCK_ADVISORY,
        ]);
    }

    public function garbageCollection(): void
    {
        $connection = $this->getConnection();
        $sql = 'DELETE FROM kimai2_sessions WHERE lifetime < :time';
        $stmt = $connection->prepare($sql);
        $stmt->bindValue(':time', time(), \PDO::PARAM_INT);
        $stmt->execute();
    }

    public function validateId(#[\SensitiveParameter] string $sessionId): bool
    {
        $result = parent::validateId($sessionId);

        if ($result === false) {
            $limiter = $this->sessionPredictionLimiter->create($this->requestStack->getMainRequest()?->getClientIp());
            $limit = $limiter->consume();

            if (false === $limit->isAccepted()) {
                throw new BadRequestHttpException('Too many requests with invalid Session ID. Prediction attack?');
            }

            usleep(250000); // slow down potential attacks
        }

        return $result;
    }
}