biurad/php-http-galaxy

View on GitHub
src/Sessions/CacheSessionHandler.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

declare(strict_types=1);

/*
 * This file is part of Biurad opensource projects.
 *
 * PHP version 7.2 and above required
 *
 * @author    Divine Niiquaye Ibok <divineibok@gmail.com>
 * @copyright 2019 Biurad Group (https://biurad.com/)
 * @license   https://opensource.org/licenses/BSD-3-Clause License
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Biurad\Http\Sessions;

use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler;

class CacheSessionHandler extends AbstractSessionHandler
{
    /** @var CacheItemPoolInterface */
    private $cache;

    /** @var int|float */
    private $sessionOpen;

    /** @var string */
    private $sessionId;

    /** @var int */
    private $minutes;

    /** @var bool */
    private $gcCalled = false;

    /**
     * Create a new cache driven handler instance.
     *
     * @param int|string|null $minutes
     */
    public function __construct(CacheItemPoolInterface $cache, $minutes = null)
    {
        $this->cache = $cache;

        if (null === $minutes) {
            $minutes = (int) \ini_get('session.gc_maxlifetime');
        } elseif (!\is_numeric($minutes)) {
            $minutes = \time() - \strtotime($minutes);
        }

        $this->minutes = $minutes;
    }

    /**
     * Returns true when the current session exists but expired according to session.gc_maxlifetime.
     *
     * Can be used to distinguish between a new session and one that expired due to inactivity.
     *
     * @return bool Whether current session expired
     */
    public function isSessionExpired(): bool
    {
        if (@$this->sessionOpen < \time() - $this->minutes) {
            //Session flash expired
            return true;
        }

        return false;
    }

    public function open($savePath, $sessionName): bool
    {
        $this->sessionOpen = \time();

        return parent::open($savePath, $sessionName);
    }

    public function updateTimestamp($sessionId, $sessionData): bool
    {
        return $this->write($sessionId, $sessionData);
    }

    /**
     * {@inheritdoc}
     */
    public function doDestroy($sessionId): bool
    {
        $exists = $this->cache->hasItem($sessionId);

        if (!(bool) $exists) {
            return true;
        }

        return (bool) $this->cache->deleteItem($sessionId);
    }

    /**
     * {@inheritdoc}
     *
     * @return int|false
     */
    public function gc(int $maxlifetime): int
    {
        // We delay gc() to close() so that it is executed outside the transactional and blocking read-write process.
        // This way, pruning expired sessions does not block them from being started while the current session is used.
        $this->gcCalled = true;

        return 0;
    }

    /**
     * {@inheritdoc}
     */
    public function close(): bool
    {
        if ($this->gcCalled && null !== $this->sessionId) {
            $this->gcCalled = false;

            $this->cache->deleteItem($this->sessionId);
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    protected function doRead($sessionId): string
    {
        $this->sessionId = $sessionId;

        return (string) $this->cache->getItem($sessionId)->get();
    }

    /**
     * {@inheritdoc}
     */
    protected function doWrite($sessionId, $data): bool
    {
        $item = $this->cache->getItem($sessionId)
            ->expiresAfter($this->minutes);

        return $this->cache->save($item->set($data));
    }
}