Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

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: 02.04.2025, 15:03 - 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