Verzeichnisstruktur phpBB-3.3.16


Veröffentlicht
27.04.2026

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

NativeSessionStorage.php

Zuletzt modifiziert: 01.05.2026, 11:28 - Dateigröße: 13.73 KiB


 001  <?php
 002   
 003  /*
 004   * This file is part of the Symfony package.
 005   *
 006   * (c) Fabien Potencier <fabien@symfony.com>
 007   *
 008   * For the full copyright and license information, please view the LICENSE
 009   * file that was distributed with this source code.
 010   */
 011   
 012  namespace Symfony\Component\HttpFoundation\Session\Storage;
 013   
 014  use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
 015  use Symfony\Component\HttpFoundation\Session\SessionUtils;
 016  use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler;
 017  use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
 018  use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
 019   
 020  /**
 021   * This provides a base class for session attribute storage.
 022   *
 023   * @author Drak <drak@zikula.org>
 024   */
 025  class NativeSessionStorage implements SessionStorageInterface
 026  {
 027      /**
 028       * @var SessionBagInterface[]
 029       */
 030      protected $bags = [];
 031   
 032      /**
 033       * @var bool
 034       */
 035      protected $started = false;
 036   
 037      /**
 038       * @var bool
 039       */
 040      protected $closed = false;
 041   
 042      /**
 043       * @var AbstractProxy|\SessionHandlerInterface
 044       */
 045      protected $saveHandler;
 046   
 047      /**
 048       * @var MetadataBag
 049       */
 050      protected $metadataBag;
 051   
 052      /**
 053       * @var string|null
 054       */
 055      private $emulateSameSite;
 056   
 057      /**
 058       * Depending on how you want the storage driver to behave you probably
 059       * want to override this constructor entirely.
 060       *
 061       * List of options for $options array with their defaults.
 062       *
 063       * @see https://php.net/session.configuration for options
 064       * but we omit 'session.' from the beginning of the keys for convenience.
 065       *
 066       * ("auto_start", is not supported as it tells PHP to start a session before
 067       * PHP starts to execute user-land code. Setting during runtime has no effect).
 068       *
 069       * cache_limiter, "" (use "0" to prevent headers from being sent entirely).
 070       * cache_expire, "0"
 071       * cookie_domain, ""
 072       * cookie_httponly, ""
 073       * cookie_lifetime, "0"
 074       * cookie_path, "/"
 075       * cookie_secure, ""
 076       * cookie_samesite, null
 077       * entropy_file, ""
 078       * entropy_length, "0"
 079       * gc_divisor, "100"
 080       * gc_maxlifetime, "1440"
 081       * gc_probability, "1"
 082       * hash_bits_per_character, "4"
 083       * hash_function, "0"
 084       * lazy_write, "1"
 085       * name, "PHPSESSID"
 086       * referer_check, ""
 087       * serialize_handler, "php"
 088       * use_strict_mode, "0"
 089       * use_cookies, "1"
 090       * use_only_cookies, "1"
 091       * use_trans_sid, "0"
 092       * upload_progress.enabled, "1"
 093       * upload_progress.cleanup, "1"
 094       * upload_progress.prefix, "upload_progress_"
 095       * upload_progress.name, "PHP_SESSION_UPLOAD_PROGRESS"
 096       * upload_progress.freq, "1%"
 097       * upload_progress.min-freq, "1"
 098       * url_rewriter.tags, "a=href,area=href,frame=src,form=,fieldset="
 099       * sid_length, "32"
 100       * sid_bits_per_character, "5"
 101       * trans_sid_hosts, $_SERVER['HTTP_HOST']
 102       * trans_sid_tags, "a=href,area=href,frame=src,form="
 103       *
 104       * @param AbstractProxy|\SessionHandlerInterface|null $handler
 105       */
 106      public function __construct(array $options = [], $handler = null, MetadataBag $metaBag = null)
 107      {
 108          if (!\extension_loaded('session')) {
 109              throw new \LogicException('PHP extension "session" is required.');
 110          }
 111   
 112          $options += [
 113              'cache_limiter' => '',
 114              'cache_expire' => 0,
 115              'use_cookies' => 1,
 116              'lazy_write' => 1,
 117          ];
 118   
 119          session_register_shutdown();
 120   
 121          $this->setMetadataBag($metaBag);
 122          $this->setOptions($options);
 123          $this->setSaveHandler($handler);
 124      }
 125   
 126      /**
 127       * Gets the save handler instance.
 128       *
 129       * @return AbstractProxy|\SessionHandlerInterface
 130       */
 131      public function getSaveHandler()
 132      {
 133          return $this->saveHandler;
 134      }
 135   
 136      /**
 137       * {@inheritdoc}
 138       */
 139      public function start()
 140      {
 141          if ($this->started) {
 142              return true;
 143          }
 144   
 145          if (\PHP_SESSION_ACTIVE === session_status()) {
 146              throw new \RuntimeException('Failed to start the session: already started by PHP.');
 147          }
 148   
 149          if (filter_var(ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line)) {
 150              throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line));
 151          }
 152   
 153          // ok to try and start the session
 154          if (!session_start()) {
 155              throw new \RuntimeException('Failed to start the session.');
 156          }
 157   
 158          if (null !== $this->emulateSameSite) {
 159              $originalCookie = SessionUtils::popSessionCookie(session_name(), session_id());
 160              if (null !== $originalCookie) {
 161                  header(sprintf('%s; SameSite=%s', $originalCookie, $this->emulateSameSite), false);
 162              }
 163          }
 164   
 165          $this->loadSession();
 166   
 167          return true;
 168      }
 169   
 170      /**
 171       * {@inheritdoc}
 172       */
 173      public function getId()
 174      {
 175          return $this->saveHandler->getId();
 176      }
 177   
 178      /**
 179       * {@inheritdoc}
 180       */
 181      public function setId($id)
 182      {
 183          $this->saveHandler->setId($id);
 184      }
 185   
 186      /**
 187       * {@inheritdoc}
 188       */
 189      public function getName()
 190      {
 191          return $this->saveHandler->getName();
 192      }
 193   
 194      /**
 195       * {@inheritdoc}
 196       */
 197      public function setName($name)
 198      {
 199          $this->saveHandler->setName($name);
 200      }
 201   
 202      /**
 203       * {@inheritdoc}
 204       */
 205      public function regenerate($destroy = false, $lifetime = null)
 206      {
 207          // Cannot regenerate the session ID for non-active sessions.
 208          if (\PHP_SESSION_ACTIVE !== session_status()) {
 209              return false;
 210          }
 211   
 212          if (headers_sent()) {
 213              return false;
 214          }
 215   
 216          if (null !== $lifetime && $lifetime != ini_get('session.cookie_lifetime')) {
 217              $this->save();
 218              ini_set('session.cookie_lifetime', $lifetime);
 219              $this->start();
 220          }
 221   
 222          if ($destroy) {
 223              $this->metadataBag->stampNew();
 224          }
 225   
 226          $isRegenerated = session_regenerate_id($destroy);
 227   
 228          if (null !== $this->emulateSameSite) {
 229              $originalCookie = SessionUtils::popSessionCookie(session_name(), session_id());
 230              if (null !== $originalCookie) {
 231                  header(sprintf('%s; SameSite=%s', $originalCookie, $this->emulateSameSite), false);
 232              }
 233          }
 234   
 235          return $isRegenerated;
 236      }
 237   
 238      /**
 239       * {@inheritdoc}
 240       */
 241      public function save()
 242      {
 243          // Store a copy so we can restore the bags in case the session was not left empty
 244          $session = $_SESSION;
 245   
 246          foreach ($this->bags as $bag) {
 247              if (empty($_SESSION[$key = $bag->getStorageKey()])) {
 248                  unset($_SESSION[$key]);
 249              }
 250          }
 251          if ([$key = $this->metadataBag->getStorageKey()] === array_keys($_SESSION)) {
 252              unset($_SESSION[$key]);
 253          }
 254   
 255          // Register error handler to add information about the current save handler
 256          $previousHandler = set_error_handler(function ($type, $msg, $file, $line) use (&$previousHandler) {
 257              if (\E_WARNING === $type && 0 === strpos($msg, 'session_write_close():')) {
 258                  $handler = $this->saveHandler instanceof SessionHandlerProxy ? $this->saveHandler->getHandler() : $this->saveHandler;
 259                  $msg = sprintf('session_write_close(): Failed to write session data with "%s" handler', \get_class($handler));
 260              }
 261   
 262              return $previousHandler ? $previousHandler($type, $msg, $file, $line) : false;
 263          });
 264   
 265          try {
 266              session_write_close();
 267          } finally {
 268              restore_error_handler();
 269   
 270              // Restore only if not empty
 271              if ($_SESSION) {
 272                  $_SESSION = $session;
 273              }
 274          }
 275   
 276          $this->closed = true;
 277          $this->started = false;
 278      }
 279   
 280      /**
 281       * {@inheritdoc}
 282       */
 283      public function clear()
 284      {
 285          // clear out the bags
 286          foreach ($this->bags as $bag) {
 287              $bag->clear();
 288          }
 289   
 290          // clear out the session
 291          $_SESSION = [];
 292   
 293          // reconnect the bags to the session
 294          $this->loadSession();
 295      }
 296   
 297      /**
 298       * {@inheritdoc}
 299       */
 300      public function registerBag(SessionBagInterface $bag)
 301      {
 302          if ($this->started) {
 303              throw new \LogicException('Cannot register a bag when the session is already started.');
 304          }
 305   
 306          $this->bags[$bag->getName()] = $bag;
 307      }
 308   
 309      /**
 310       * {@inheritdoc}
 311       */
 312      public function getBag($name)
 313      {
 314          if (!isset($this->bags[$name])) {
 315              throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name));
 316          }
 317   
 318          if (!$this->started && $this->saveHandler->isActive()) {
 319              $this->loadSession();
 320          } elseif (!$this->started) {
 321              $this->start();
 322          }
 323   
 324          return $this->bags[$name];
 325      }
 326   
 327      public function setMetadataBag(MetadataBag $metaBag = null)
 328      {
 329          if (null === $metaBag) {
 330              $metaBag = new MetadataBag();
 331          }
 332   
 333          $this->metadataBag = $metaBag;
 334      }
 335   
 336      /**
 337       * Gets the MetadataBag.
 338       *
 339       * @return MetadataBag
 340       */
 341      public function getMetadataBag()
 342      {
 343          return $this->metadataBag;
 344      }
 345   
 346      /**
 347       * {@inheritdoc}
 348       */
 349      public function isStarted()
 350      {
 351          return $this->started;
 352      }
 353   
 354      /**
 355       * Sets session.* ini variables.
 356       *
 357       * For convenience we omit 'session.' from the beginning of the keys.
 358       * Explicitly ignores other ini keys.
 359       *
 360       * @param array $options Session ini directives [key => value]
 361       *
 362       * @see https://php.net/session.configuration
 363       */
 364      public function setOptions(array $options)
 365      {
 366          if (headers_sent() || \PHP_SESSION_ACTIVE === session_status()) {
 367              return;
 368          }
 369   
 370          $validOptions = array_flip([
 371              'cache_expire', 'cache_limiter', 'cookie_domain', 'cookie_httponly',
 372              'cookie_lifetime', 'cookie_path', 'cookie_secure', 'cookie_samesite',
 373              'entropy_file', 'entropy_length', 'gc_divisor',
 374              'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character',
 375              'hash_function', 'lazy_write', 'name', 'referer_check',
 376              'serialize_handler', 'use_strict_mode', 'use_cookies',
 377              'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled',
 378              'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name',
 379              'upload_progress.freq', 'upload_progress.min_freq', 'url_rewriter.tags',
 380              'sid_length', 'sid_bits_per_character', 'trans_sid_hosts', 'trans_sid_tags',
 381          ]);
 382   
 383          foreach ($options as $key => $value) {
 384              if (isset($validOptions[$key])) {
 385                  if ('cookie_samesite' === $key && \PHP_VERSION_ID < 70300) {
 386                      // PHP < 7.3 does not support same_site cookies. We will emulate it in
 387                      // the start() method instead.
 388                      $this->emulateSameSite = $value;
 389                      continue;
 390                  }
 391                  ini_set('url_rewriter.tags' !== $key ? 'session.'.$key : $key, $value);
 392              }
 393          }
 394      }
 395   
 396      /**
 397       * Registers session save handler as a PHP session handler.
 398       *
 399       * To use internal PHP session save handlers, override this method using ini_set with
 400       * session.save_handler and session.save_path e.g.
 401       *
 402       *     ini_set('session.save_handler', 'files');
 403       *     ini_set('session.save_path', '/tmp');
 404       *
 405       * or pass in a \SessionHandler instance which configures session.save_handler in the
 406       * constructor, for a template see NativeFileSessionHandler.
 407       *
 408       * @see https://php.net/session-set-save-handler
 409       * @see https://php.net/sessionhandlerinterface
 410       * @see https://php.net/sessionhandler
 411       *
 412       * @param AbstractProxy|\SessionHandlerInterface|null $saveHandler
 413       *
 414       * @throws \InvalidArgumentException
 415       */
 416      public function setSaveHandler($saveHandler = null)
 417      {
 418          if (!$saveHandler instanceof AbstractProxy &&
 419              !$saveHandler instanceof \SessionHandlerInterface &&
 420              null !== $saveHandler) {
 421              throw new \InvalidArgumentException('Must be instance of AbstractProxy; implement \SessionHandlerInterface; or be null.');
 422          }
 423   
 424          // Wrap $saveHandler in proxy and prevent double wrapping of proxy
 425          if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) {
 426              $saveHandler = new SessionHandlerProxy($saveHandler);
 427          } elseif (!$saveHandler instanceof AbstractProxy) {
 428              $saveHandler = new SessionHandlerProxy(new StrictSessionHandler(new \SessionHandler()));
 429          }
 430          $this->saveHandler = $saveHandler;
 431   
 432          if (headers_sent() || \PHP_SESSION_ACTIVE === session_status()) {
 433              return;
 434          }
 435   
 436          if ($this->saveHandler instanceof SessionHandlerProxy) {
 437              session_set_save_handler($this->saveHandler, false);
 438          }
 439      }
 440   
 441      /**
 442       * Load the session with attributes.
 443       *
 444       * After starting the session, PHP retrieves the session from whatever handlers
 445       * are set to (either PHP's internal, or a custom save handler set with session_set_save_handler()).
 446       * PHP takes the return value from the read() handler, unserializes it
 447       * and populates $_SESSION with the result automatically.
 448       */
 449      protected function loadSession(array &$session = null)
 450      {
 451          if (null === $session) {
 452              $session = &$_SESSION;
 453          }
 454   
 455          $bags = array_merge($this->bags, [$this->metadataBag]);
 456   
 457          foreach ($bags as $bag) {
 458              $key = $bag->getStorageKey();
 459              $session[$key] = isset($session[$key]) && \is_array($session[$key]) ? $session[$key] : [];
 460              $bag->initialize($session[$key]);
 461          }
 462   
 463          $this->started = true;
 464          $this->closed = false;
 465      }
 466  }
 467