MOON
Server: Apache
System: Linux server1.studioinfinity.com.br 2.6.32-954.3.5.lve1.4.90.el6.x86_64 #1 SMP Tue Feb 21 12:26:30 UTC 2023 x86_64
User: artinside (517)
PHP: 7.4.33
Disabled: exec,passthru,shell_exec,system
Upload Files
File: /home/artinside/sites.artinside.com.br/mainpro/vendor/aplus/session/src/Session.php
<?php declare(strict_types=1);
/*
 * This file is part of Aplus Framework Session Library.
 *
 * (c) Natan Felles <natanfelles@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Framework\Session;

use Framework\Session\Debug\SessionCollector;
use JetBrains\PhpStorm\Pure;
use LogicException;
use RuntimeException;

/**
 * Class Session.
 *
 * @package session
 */
class Session
{
    /**
     * @var array<string,mixed>
     */
    protected array $options = [];
    protected SaveHandler $saveHandler;
    protected SessionCollector $debugCollector;

    /**
     * Session constructor.
     *
     * @param array<string,int|string> $options
     * @param SaveHandler|null $handler
     */
    public function __construct(array $options = [], ?SaveHandler $handler = null)
    {
        $this->setOptions($options);
        if ($handler) {
            $this->saveHandler = $handler;
            \session_set_save_handler($handler);
        }
    }

    public function __destruct()
    {
        $this->stop();
    }

    public function __get(string $key) : mixed
    {
        return $this->get($key);
    }

    public function __set(string $key, mixed $value) : void
    {
        $this->set($key, $value);
    }

    public function __isset(string $key) : bool
    {
        return $this->has($key);
    }

    public function __unset(string $key) : void
    {
        $this->remove($key);
    }

    /**
     * @see http://php.net/manual/en/session.security.ini.php
     *
     * @param array<string,int|string> $custom
     */
    protected function setOptions(array $custom) : void
    {
        $serializer = \ini_get('session.serialize_handler');
        $serializer = $serializer === 'php' ? 'php_serialize' : $serializer;
        $secure = (isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] === 'https')
            || (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on');
        $default = [
            'name' => 'session_id',
            'serialize_handler' => $serializer,
            'cookie_domain' => '',
            'cookie_httponly' => 1,
            'cookie_lifetime' => 7200,
            'cookie_path' => '/',
            'cookie_samesite' => 'Strict',
            'cookie_secure' => $secure,
            'referer_check' => '',
            'use_cookies' => 1,
            'use_only_cookies' => 1,
            'use_strict_mode' => 1,
            'use_trans_sid' => 0,
            // used to auto-regenerate the session id:
            'auto_regenerate_maxlifetime' => 0,
            'auto_regenerate_destroy' => true,
        ];
        if (\PHP_VERSION_ID < 80400) {
            $default['sid_bits_per_character'] = 6;
            $default['sid_length'] = 48;
        }
        $this->options = $custom
            ? \array_replace($default, $custom)
            : $default;
    }

    /**
     * @param array<string,mixed> $custom
     *
     * @return array<string,mixed>
     */
    protected function getOptions(array $custom = []) : array
    {
        $options = $custom
            ? \array_replace($this->options, $custom)
            : $this->options;
        unset(
            $options['auto_regenerate_maxlifetime'],
            $options['auto_regenerate_destroy']
        );
        return $options;
    }

    /**
     * @param array<string,int|string> $customOptions
     *
     * @throws LogicException if session was already active
     * @throws RuntimeException if session could not be started
     *
     * @return bool
     */
    public function start(array $customOptions = []) : bool
    {
        if ($this->isActive()) {
            throw new LogicException('Session was already active');
        }
        if (!@\session_start($this->getOptions($customOptions))) {
            $message = '';
            if (\error_get_last()) {
                $message = ': ' . \error_get_last()['message'];
            }
            throw new RuntimeException(
                'Session could not be started' . $message
            );
        }
        $time = \time();
        $this->autoRegenerate($time);
        $this->clearTemp($time);
        $this->clearFlash();
        return true;
    }

    /**
     * Make sure the session is active.
     *
     * If it is not active, it will start it.
     *
     * @throws RuntimeException if session could not be started
     *
     * @return bool
     */
    public function activate() : bool
    {
        if ($this->isActive()) {
            return true;
        }
        return $this->start();
    }

    /**
     * Auto regenerate the session id.
     *
     * @param int $time
     *
     * @see https://owasp.org/www-community/attacks/Session_fixation
     */
    protected function autoRegenerate(int $time) : void
    {
        $maxlifetime = (int) $this->options['auto_regenerate_maxlifetime'];
        $isActive = $maxlifetime > 0;
        if (($isActive && empty($_SESSION['$']['regenerated_at']))
            || ($isActive && $_SESSION['$']['regenerated_at'] < ($time - $maxlifetime))
        ) {
            $this->regenerateId((bool) $this->options['auto_regenerate_destroy']);
        }
    }

    /**
     * Clears the Flash Data.
     */
    protected function clearFlash() : void
    {
        unset($_SESSION['$']['flash']['old']);
        if (isset($_SESSION['$']['flash']['new'])) {
            foreach ($_SESSION['$']['flash']['new'] as $key => $value) {
                $_SESSION['$']['flash']['old'][$key] = $value;
            }
        }
        unset($_SESSION['$']['flash']['new']);
        if (empty($_SESSION['$']['flash'])) {
            unset($_SESSION['$']['flash']);
        }
    }

    /**
     * Clears the Temp Data.
     *
     * @param int $time The max time to temp data survive
     */
    protected function clearTemp(int $time) : void
    {
        if (isset($_SESSION['$']['temp'])) {
            foreach ($_SESSION['$']['temp'] as $key => $value) {
                if ($value['ttl'] < $time) {
                    unset($_SESSION['$']['temp'][$key]);
                }
            }
        }
        if (empty($_SESSION['$']['temp'])) {
            unset($_SESSION['$']['temp']);
        }
    }

    /**
     * Tells if sessions are enabled, and one exists.
     *
     * @return bool
     */
    public function isActive() : bool
    {
        return \session_status() === \PHP_SESSION_ACTIVE;
    }

    /**
     * Destroys all data registered to a session.
     *
     * @return bool true on success or false on failure
     */
    public function destroy() : bool
    {
        if ($this->isActive()) {
            $destroyed = \session_destroy();
        }
        unset($_SESSION);
        return $destroyed ?? true;
    }

    /**
     * Sets a Cookie with the session name to be destroyed in the user-agent.
     *
     * @throws RuntimeException If it could not get the session name
     *
     * @return bool True if the Set-Cookie header was set to invalidate the
     * session cookie, false if output exists
     */
    public function destroyCookie() : bool
    {
        $name = \session_name();
        if ($name === false) {
            throw new RuntimeException('Could not get the session name');
        }
        $params = \session_get_cookie_params();
        // @phpstan-ignore-next-line
        return \setcookie($name, '', [
            'expires' => 0,
            'path' => $params['path'],
            'domain' => $params['domain'],
            'secure' => $params['secure'],
            'httponly' => $params['httponly'],
            'samesite' => $params['samesite'],
        ]);
    }

    /**
     * Write session data and end session.
     *
     * @return bool returns true on success or false on failure
     */
    public function stop() : bool
    {
        if ($this->isActive()) {
            $closed = \session_write_close();
        }
        return $closed ?? true;
    }

    /**
     * Discard session data changes and end session.
     *
     * @return bool returns true on success or false on failure
     */
    public function abort() : bool
    {
        if ($this->isActive()) {
            $aborted = \session_abort();
        }
        return $aborted ?? true;
    }

    /**
     * Tells if the session has an item.
     *
     * @param string $key The item key name
     *
     * @return bool True if it has, otherwise false
     */
    #[Pure]
    public function has(string $key) : bool
    {
        return isset($_SESSION[$key]);
    }

    /**
     * Gets one session item.
     *
     * @param string $key The item key name
     *
     * @return mixed The item value or null if no set
     */
    #[Pure]
    public function get(string $key) : mixed
    {
        return $_SESSION[$key] ?? null;
    }

    /**
     * Get all session items.
     *
     * @return array<mixed> The value of the $_SESSION global
     */
    #[Pure]
    public function getAll() : array
    {
        return $_SESSION;
    }

    /**
     * Get multiple session items.
     *
     * @param array<string> $keys An array of key item names
     *
     * @return array<string,mixed> An associative array with items keys and
     * values. Item not set will return as null.
     */
    #[Pure]
    public function getMulti(array $keys) : array
    {
        $items = [];
        foreach ($keys as $key) {
            $items[$key] = $this->get($key);
        }
        return $items;
    }

    /**
     * Set a session item.
     *
     * @param string $key The item key name
     * @param mixed $value The item value
     *
     * @rerun static
     */
    public function set(string $key, mixed $value) : static
    {
        $_SESSION[$key] = $value;
        return $this;
    }

    /**
     * Set multiple session items.
     *
     * @param array<string,mixed> $items An associative array of items keys and
     * values
     *
     * @rerun static
     */
    public function setMulti(array $items) : static
    {
        foreach ($items as $key => $value) {
            $this->set($key, $value);
        }
        return $this;
    }

    /**
     * Remove (unset) a session item.
     *
     * @param string $key The item key name
     *
     * @rerun static
     */
    public function remove(string $key) : static
    {
        unset($_SESSION[$key]);
        return $this;
    }

    /**
     * Remove (unset) multiple session items.
     *
     * @param array<string> $keys A list of items keys names
     *
     * @rerun static
     */
    public function removeMulti(array $keys) : static
    {
        foreach ($keys as $key) {
            $this->remove($key);
        }
        return $this;
    }

    /**
     * Remove (unset) all session items.
     *
     * @rerun static
     */
    public function removeAll() : static
    {
        @\session_unset();
        $_SESSION = [];
        return $this;
    }

    /**
     * Update the current session id with a newly generated one.
     *
     * @param bool $deleteOldSession Whether to delete the old associated session item or not
     *
     * @return bool
     */
    public function regenerateId(bool $deleteOldSession = false) : bool
    {
        $regenerated = \session_regenerate_id($deleteOldSession);
        if ($regenerated) {
            $_SESSION['$']['regenerated_at'] = \time();
        }
        return $regenerated;
    }

    /**
     * Re-initialize session array with original values.
     *
     * @return bool true if the session was successfully reinitialized or false on failure
     */
    public function reset() : bool
    {
        return \session_reset();
    }

    /**
     * Get a Flash Data item.
     *
     * @param string $key The Flash item key name
     *
     * @return mixed The item value or null if not exists
     */
    #[Pure]
    public function getFlash(string $key) : mixed
    {
        return $_SESSION['$']['flash']['new'][$key]
            ?? $_SESSION['$']['flash']['old'][$key]
            ?? null;
    }

    /**
     * Set a Flash Data item, available only in the next time the session is started.
     *
     * @param string $key The Flash Data item key name
     * @param mixed $value The item value
     *
     * @rerun static
     */
    public function setFlash(string $key, mixed $value) : static
    {
        $_SESSION['$']['flash']['new'][$key] = $value;
        return $this;
    }

    /**
     * Remove a Flash Data item.
     *
     * @param string $key The item key name
     *
     * @rerun static
     */
    public function removeFlash(string $key) : static
    {
        unset(
            $_SESSION['$']['flash']['old'][$key],
            $_SESSION['$']['flash']['new'][$key]
        );
        return $this;
    }

    /**
     * Get a Temp Data item.
     *
     * @param string $key The item key name
     *
     * @return mixed The item value or null if it is expired or not set
     */
    public function getTemp(string $key) : mixed
    {
        if (isset($_SESSION['$']['temp'][$key])) {
            if ($_SESSION['$']['temp'][$key]['ttl'] > \time()) {
                return $_SESSION['$']['temp'][$key]['data'];
            }
            unset($_SESSION['$']['temp'][$key]);
        }
        return null;
    }

    /**
     * Set a Temp Data item.
     *
     * @param string $key The item key name
     * @param mixed $value The item value
     * @param int $ttl The Time-To-Live of the item, in seconds
     *
     * @rerun static
     */
    public function setTemp(string $key, mixed $value, int $ttl = 60) : static
    {
        $_SESSION['$']['temp'][$key] = [
            'ttl' => \time() + $ttl,
            'data' => $value,
        ];
        return $this;
    }

    /**
     * Remove (unset) a Temp Data item.
     *
     * @param string $key The item key name
     *
     * @rerun static
     */
    public function removeTemp(string $key) : static
    {
        unset($_SESSION['$']['temp'][$key]);
        return $this;
    }

    /**
     * Get/Set the session id.
     *
     * @param string|null $newId [optional] The new session id
     *
     * @throws LogicException when trying to set a new id and the session is active
     *
     * @return false|string The old session id or false on failure. Note: If a
     * $newId is set, it is accepted but not validated. When session_start is
     * called, the id is only used if it is valid
     */
    public function id(?string $newId = null) : false | string
    {
        if ($newId !== null && $this->isActive()) {
            throw new LogicException(
                'Session ID cannot be changed when a session is active'
            );
        }
        return \session_id($newId);
    }

    /**
     * Perform session data garbage collection.
     *
     * If return false, use {@see error_get_last()} to get error details.
     *
     * @return false|int Returns the number of deleted session data for success,
     * false for failure
     */
    public function gc() : false | int
    {
        return @\session_gc();
    }

    public function setDebugCollector(SessionCollector $collector) : static
    {
        $this->debugCollector = $collector;
        $this->debugCollector->setSession($this)->setOptions($this->options);
        if (isset($this->saveHandler)) {
            $this->debugCollector->setSaveHandler($this->saveHandler);
        }
        return $this;
    }
}