[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/joomla/session/src/ -> Session.php (source)

   1  <?php
   2  /**
   3   * Part of the Joomla Framework Session Package
   4   *
   5   * @copyright  Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved.
   6   * @license    GNU General Public License version 2 or later; see LICENSE
   7   */
   8  
   9  namespace Joomla\Session;
  10  
  11  use Joomla\Event\DispatcherAwareInterface;
  12  use Joomla\Event\DispatcherAwareTrait;
  13  use Joomla\Event\DispatcherInterface;
  14  
  15  /**
  16   * Class for managing HTTP sessions
  17   *
  18   * Provides access to session-state values as well as session-level settings and lifetime management methods.
  19   * Based on the standard PHP session handling mechanism it provides more advanced features such as expire timeouts.
  20   *
  21   * @since  1.0
  22   */
  23  class Session implements SessionInterface, DispatcherAwareInterface
  24  {
  25      use DispatcherAwareTrait;
  26  
  27      /**
  28       * Internal session state.
  29       *
  30       * @var    string
  31       * @since  1.0
  32       */
  33      protected $state = SessionState::INACTIVE;
  34  
  35      /**
  36       * Maximum age of unused session in seconds.
  37       *
  38       * @var    integer
  39       * @since  1.0
  40       */
  41      protected $expire = 900;
  42  
  43      /**
  44       * The session store object.
  45       *
  46       * @var    StorageInterface
  47       * @since  1.0
  48       */
  49      protected $store;
  50  
  51      /**
  52       * Container holding session validators.
  53       *
  54       * @var    ValidatorInterface[]
  55       * @since  2.0.0
  56       */
  57      protected $sessionValidators = [];
  58  
  59      /**
  60       * Constructor
  61       *
  62       * @param   StorageInterface     $store       A StorageInterface implementation.
  63       * @param   DispatcherInterface  $dispatcher  DispatcherInterface for the session to use.
  64       * @param   array                $options     Optional parameters. Supported keys include:
  65       *                                            - name: The session name
  66       *                                            - id: The session ID
  67       *                                            - expire: The session lifetime in seconds
  68       *
  69       * @since   1.0
  70       */
  71  	public function __construct(StorageInterface $store = null, DispatcherInterface $dispatcher = null, array $options = [])
  72      {
  73          $this->store = $store ?: new Storage\NativeStorage(new Handler\FilesystemHandler);
  74  
  75          if ($dispatcher)
  76          {
  77              $this->setDispatcher($dispatcher);
  78          }
  79  
  80          $this->setOptions($options);
  81  
  82          $this->setState(SessionState::INACTIVE);
  83      }
  84  
  85      /**
  86       * Adds a validator to the session
  87       *
  88       * @param   ValidatorInterface  $validator  The session validator
  89       *
  90       * @return  void
  91       *
  92       * @since   2.0.0
  93       */
  94  	public function addValidator(ValidatorInterface $validator): void
  95      {
  96          $this->sessionValidators[] = $validator;
  97      }
  98  
  99      /**
 100       * Get expiration time in seconds
 101       *
 102       * @return  integer  The session expiration time in seconds
 103       *
 104       * @since   1.0
 105       */
 106  	public function getExpire()
 107      {
 108          return $this->expire;
 109      }
 110  
 111      /**
 112       * Get current state of session
 113       *
 114       * @return  string  The session state
 115       *
 116       * @since   1.0
 117       */
 118  	public function getState()
 119      {
 120          return $this->state;
 121      }
 122  
 123      /**
 124       * Get a session token.
 125       *
 126       * Tokens are used to secure forms from spamming attacks. Once a token has been generated the system will check the request to see if
 127       * it is present, if not it will invalidate the session.
 128       *
 129       * @param   boolean  $forceNew  If true, forces a new token to be created
 130       *
 131       * @return  string
 132       *
 133       * @since   1.0
 134       */
 135  	public function getToken($forceNew = false)
 136      {
 137          // Ensure the session token exists and create it if necessary
 138          if (!$this->has('session.token') || $forceNew)
 139          {
 140              $this->set('session.token', $this->createToken());
 141          }
 142  
 143          return $this->get('session.token');
 144      }
 145  
 146      /**
 147       * Check if the session has the given token.
 148       *
 149       * @param   string   $token        Hashed token to be verified
 150       * @param   boolean  $forceExpire  If true, expires the session
 151       *
 152       * @return  boolean
 153       *
 154       * @since   1.0
 155       */
 156  	public function hasToken($token, $forceExpire = true)
 157      {
 158          $result = $this->get('session.token') === $token;
 159  
 160          if (!$result && $forceExpire)
 161          {
 162              $this->setState(SessionState::EXPIRED);
 163          }
 164  
 165          return $result;
 166      }
 167  
 168      /**
 169       * Retrieve an external iterator.
 170       *
 171       * @return  \ArrayIterator  Return an ArrayIterator of $_SESSION.
 172       *
 173       * @since   1.0
 174       */
 175      #[\ReturnTypeWillChange]
 176  	public function getIterator()
 177      {
 178          return new \ArrayIterator($this->all());
 179      }
 180  
 181      /**
 182       * Get session name
 183       *
 184       * @return  string  The session name
 185       *
 186       * @since   1.0
 187       */
 188  	public function getName()
 189      {
 190          return $this->store->getName();
 191      }
 192  
 193      /**
 194       * Set the session name
 195       *
 196       * @param   string  $name  The session name
 197       *
 198       * @return  $this
 199       *
 200       * @since   2.0.0
 201       */
 202  	public function setName(string $name)
 203      {
 204          $this->store->setName($name);
 205  
 206          return $this;
 207      }
 208  
 209      /**
 210       * Get session id
 211       *
 212       * @return  string  The session id
 213       *
 214       * @since   1.0
 215       */
 216  	public function getId()
 217      {
 218          return $this->store->getId();
 219      }
 220  
 221      /**
 222       * Set the session ID
 223       *
 224       * @param   string  $id  The session ID
 225       *
 226       * @return  $this
 227       *
 228       * @since   2.0.0
 229       */
 230  	public function setId(string $id)
 231      {
 232          $this->store->setId($id);
 233  
 234          return $this;
 235      }
 236  
 237      /**
 238       * Check if the session is active
 239       *
 240       * @return  boolean
 241       *
 242       * @since   1.0
 243       */
 244  	public function isActive()
 245      {
 246          if ($this->getState() === SessionState::ACTIVE)
 247          {
 248              return $this->store->isActive();
 249          }
 250  
 251          return false;
 252      }
 253  
 254      /**
 255       * Check whether this session is currently created
 256       *
 257       * @return  boolean
 258       *
 259       * @since   1.0
 260       */
 261  	public function isNew()
 262      {
 263          $counter = $this->get('session.counter');
 264  
 265          return $counter === 1;
 266      }
 267  
 268      /**
 269       * Check if the session is started
 270       *
 271       * @return  boolean
 272       *
 273       * @since   2.0.0
 274       */
 275  	public function isStarted(): bool
 276      {
 277          return $this->store->isStarted();
 278      }
 279  
 280      /**
 281       * Get data from the session store
 282       *
 283       * @param   string  $name     Name of a variable
 284       * @param   mixed   $default  Default value of a variable if not set
 285       *
 286       * @return  mixed  Value of a variable
 287       *
 288       * @since   1.0
 289       */
 290  	public function get($name, $default = null)
 291      {
 292          if (!$this->isActive())
 293          {
 294              $this->start();
 295          }
 296  
 297          return $this->store->get($name, $default);
 298      }
 299  
 300      /**
 301       * Set data into the session store.
 302       *
 303       * @param   string  $name   Name of a variable.
 304       * @param   mixed   $value  Value of a variable.
 305       *
 306       * @return  mixed  Old value of a variable.
 307       *
 308       * @since   1.0
 309       */
 310  	public function set($name, $value = null)
 311      {
 312          if (!$this->isActive())
 313          {
 314              $this->start();
 315          }
 316  
 317          return $this->store->set($name, $value);
 318      }
 319  
 320      /**
 321       * Check whether data exists in the session store
 322       *
 323       * @param   string  $name  Name of variable
 324       *
 325       * @return  boolean  True if the variable exists
 326       *
 327       * @since   1.0
 328       */
 329  	public function has($name)
 330      {
 331          if (!$this->isActive())
 332          {
 333              $this->start();
 334          }
 335  
 336          return $this->store->has($name);
 337      }
 338  
 339      /**
 340       * Unset a variable from the session store
 341       *
 342       * @param   string  $name  Name of variable
 343       *
 344       * @return  mixed   The value from session or NULL if not set
 345       *
 346       * @since   2.0.0
 347       */
 348  	public function remove(string $name)
 349      {
 350          if (!$this->isActive())
 351          {
 352              $this->start();
 353          }
 354  
 355          return $this->store->remove($name);
 356      }
 357  
 358      /**
 359       * Clears all variables from the session store
 360       *
 361       * @return  void
 362       *
 363       * @since   1.0
 364       */
 365  	public function clear()
 366      {
 367          if (!$this->isActive())
 368          {
 369              $this->start();
 370          }
 371  
 372          $this->store->clear();
 373      }
 374  
 375      /**
 376       * Retrieves all variables from the session store
 377       *
 378       * @return  array
 379       *
 380       * @since   2.0.0
 381       */
 382  	public function all(): array
 383      {
 384          if (!$this->isActive())
 385          {
 386              $this->start();
 387          }
 388  
 389          return $this->store->all();
 390      }
 391  
 392      /**
 393       * Start a session.
 394       *
 395       * @return  void
 396       *
 397       * @since   1.0
 398       */
 399  	public function start()
 400      {
 401          if ($this->isStarted())
 402          {
 403              return;
 404          }
 405  
 406          $this->store->start();
 407  
 408          $this->setState(SessionState::ACTIVE);
 409  
 410          // Initialise the session
 411          $this->setCounter();
 412          $this->setTimers();
 413  
 414          // Perform security checks
 415          if (!$this->validate())
 416          {
 417              // If the session isn't valid because it expired try to restart it or destroy it.
 418              if ($this->getState() === SessionState::EXPIRED)
 419              {
 420                  $this->restart();
 421              }
 422              else
 423              {
 424                  $this->destroy();
 425              }
 426          }
 427  
 428          if ($this->dispatcher)
 429          {
 430              if (!empty($this->dispatcher->getListeners('onAfterSessionStart')))
 431              {
 432                  trigger_deprecation(
 433                      'joomla/session',
 434                      '2.0.0',
 435                      'The `onAfterSessionStart` event is deprecated and will be removed in 3.0, use the %s::START event instead.',
 436                      SessionEvents::class
 437                  );
 438  
 439                  // Dispatch deprecated event
 440                  $this->dispatcher->dispatch('onAfterSessionStart', new SessionEvent('onAfterSessionStart', $this));
 441              }
 442  
 443              // Dispatch new event
 444              $this->dispatcher->dispatch(SessionEvents::START, new SessionEvent(SessionEvents::START, $this));
 445          }
 446      }
 447  
 448      /**
 449       * Frees all session variables and destroys all data registered to a session
 450       *
 451       * This method resets the $_SESSION variable and destroys all of the data associated
 452       * with the current session in its storage (file or DB). It forces new session to be
 453       * started after this method is called.
 454       *
 455       * @return  boolean
 456       *
 457       * @see     session_destroy()
 458       * @see     session_unset()
 459       * @since   1.0
 460       */
 461  	public function destroy()
 462      {
 463          // Session was already destroyed
 464          if ($this->getState() === SessionState::DESTROYED)
 465          {
 466              return true;
 467          }
 468  
 469          $this->clear();
 470          $this->fork(true);
 471  
 472          $this->setState(SessionState::DESTROYED);
 473  
 474          return true;
 475      }
 476  
 477      /**
 478       * Restart an expired or locked session.
 479       *
 480       * @return  boolean  True on success
 481       *
 482       * @see     destroy
 483       * @since   1.0
 484       */
 485  	public function restart()
 486      {
 487          // Backup existing session data
 488          $data = $this->all();
 489  
 490          $this->destroy();
 491  
 492          if ($this->getState() !== SessionState::DESTROYED)
 493          {
 494              // @TODO :: generated error here
 495              return false;
 496          }
 497  
 498          // Restart the session
 499          $this->store->start();
 500  
 501          $this->setState(SessionState::ACTIVE);
 502  
 503          // Initialise the session
 504          $this->setCounter();
 505          $this->setTimers();
 506  
 507          // Restore the data
 508          foreach ($data as $key => $value)
 509          {
 510              $this->set($key, $value);
 511          }
 512  
 513          // If the restarted session cannot be validated then it will be destroyed
 514          if (!$this->validate(true))
 515          {
 516              $this->destroy();
 517          }
 518  
 519          if ($this->dispatcher)
 520          {
 521              if (!empty($this->dispatcher->getListeners('onAfterSessionRestart')))
 522              {
 523                  trigger_deprecation(
 524                      'joomla/session',
 525                      '2.0.0',
 526                      'The `onAfterSessionRestart` event is deprecated and will be removed in 3.0, use the %s::RESTART event instead.',
 527                      SessionEvents::class
 528                  );
 529  
 530                  // Dispatch deprecated event
 531                  $this->dispatcher->dispatch('onAfterSessionRestart', new SessionEvent('onAfterSessionRestart', $this));
 532              }
 533  
 534              // Dispatch new event
 535              $this->dispatcher->dispatch(SessionEvents::RESTART, new SessionEvent(SessionEvents::RESTART, $this));
 536          }
 537  
 538          return true;
 539      }
 540  
 541      /**
 542       * Create a new session and copy variables from the old one
 543       *
 544       * @param   boolean  $destroy  Whether to delete the old session or leave it to garbage collection.
 545       *
 546       * @return  boolean  True on success
 547       *
 548       * @since   1.0
 549       */
 550  	public function fork($destroy = false)
 551      {
 552          $result = $this->store->regenerate($destroy);
 553  
 554          if ($result)
 555          {
 556              $this->setTimers();
 557          }
 558  
 559          return $result;
 560      }
 561  
 562      /**
 563       * Writes session data and ends session
 564       *
 565       * Session data is usually stored after your script terminated without the need
 566       * to call {@link Session::close()}, but as session data is locked to prevent concurrent
 567       * writes only one script may operate on a session at any time. When using
 568       * framesets together with sessions you will experience the frames loading one
 569       * by one due to this locking. You can reduce the time needed to load all the
 570       * frames by ending the session as soon as all changes to session variables are
 571       * done.
 572       *
 573       * @return  void
 574       *
 575       * @see     session_write_close()
 576       * @since   1.0
 577       */
 578  	public function close()
 579      {
 580          $this->store->close();
 581          $this->setState(SessionState::CLOSED);
 582      }
 583  
 584      /**
 585       * Perform session data garbage collection
 586       *
 587       * @return  integer|boolean  Number of deleted sessions on success or boolean false on failure or if the function is unsupported
 588       *
 589       * @see     session_gc()
 590       * @since   2.0.0
 591       */
 592      public function gc()
 593      {
 594          if (!$this->isActive())
 595          {
 596              $this->start();
 597          }
 598  
 599          return $this->store->gc();
 600      }
 601  
 602      /**
 603       * Aborts the current session
 604       *
 605       * @return  boolean
 606       *
 607       * @see     session_abort()
 608       * @since   2.0.0
 609       */
 610  	public function abort(): bool
 611      {
 612          if (!$this->isActive())
 613          {
 614              return true;
 615          }
 616  
 617          return $this->store->abort();
 618      }
 619  
 620      /**
 621       * Create a token string
 622       *
 623       * @return  string
 624       *
 625       * @since   1.3.1
 626       */
 627  	protected function createToken(): string
 628      {
 629          /*
 630           * We are returning a 32 character string.
 631           * The bin2hex() function will double the length of the hexadecimal value returned by random_bytes(),
 632           * so generate the token from a 16 byte random value
 633           */
 634          return bin2hex(random_bytes(16));
 635      }
 636  
 637      /**
 638       * Set counter of session usage
 639       *
 640       * @return  boolean  True on success
 641       *
 642       * @since   1.0
 643       */
 644  	protected function setCounter()
 645      {
 646          $counter = $this->get('session.counter', 0);
 647          $counter++;
 648  
 649          $this->set('session.counter', $counter);
 650  
 651          return true;
 652      }
 653  
 654      /**
 655       * Set the session expiration
 656       *
 657       * @param   integer  $expire  Maximum age of unused session in seconds
 658       *
 659       * @return  $this
 660       *
 661       * @since   1.3.0
 662       */
 663  	protected function setExpire($expire)
 664      {
 665          $this->expire = $expire;
 666  
 667          return $this;
 668      }
 669  
 670      /**
 671       * Set the session state
 672       *
 673       * @param   string  $state  Internal state
 674       *
 675       * @return  $this
 676       *
 677       * @since   1.3.0
 678       */
 679  	protected function setState($state)
 680      {
 681          $this->state = $state;
 682  
 683          return $this;
 684      }
 685  
 686      /**
 687       * Set the session timers
 688       *
 689       * @return  boolean  True on success
 690       *
 691       * @since   1.0
 692       */
 693  	protected function setTimers()
 694      {
 695          if (!$this->has('session.timer.start'))
 696          {
 697              $start = time();
 698  
 699              $this->set('session.timer.start', $start);
 700              $this->set('session.timer.last', $start);
 701              $this->set('session.timer.now', $start);
 702          }
 703  
 704          $this->set('session.timer.last', $this->get('session.timer.now'));
 705          $this->set('session.timer.now', time());
 706  
 707          return true;
 708      }
 709  
 710      /**
 711       * Set additional session options
 712       *
 713       * @param   array  $options  List of parameter
 714       *
 715       * @return  boolean  True on success
 716       *
 717       * @since   1.0
 718       */
 719  	protected function setOptions(array $options)
 720      {
 721          // Set name
 722          if (isset($options['name']))
 723          {
 724              $this->setName($options['name']);
 725          }
 726  
 727          // Set id
 728          if (isset($options['id']))
 729          {
 730              $this->setId($options['id']);
 731          }
 732  
 733          // Set expire time
 734          if (isset($options['expire']))
 735          {
 736              $this->setExpire($options['expire']);
 737          }
 738  
 739          // Sync the session maxlifetime
 740          if (!headers_sent())
 741          {
 742              ini_set('session.gc_maxlifetime', $this->getExpire());
 743          }
 744  
 745          return true;
 746      }
 747  
 748      /**
 749       * Do some checks for security reasons
 750       *
 751       * If one check fails, session data has to be cleaned.
 752       *
 753       * @param   boolean  $restart  Reactivate session
 754       *
 755       * @return  boolean  True on success
 756       *
 757       * @see     http://shiflett.org/articles/the-truth-about-sessions
 758       * @since   1.0
 759       */
 760  	protected function validate($restart = false)
 761      {
 762          // Allow to restart a session
 763          if ($restart)
 764          {
 765              $this->setState(SessionState::ACTIVE);
 766          }
 767  
 768          // Check if session has expired
 769          if ($this->expire)
 770          {
 771              $curTime = $this->get('session.timer.now', 0);
 772              $maxTime = $this->get('session.timer.last', 0) + $this->expire;
 773  
 774              // Empty session variables
 775              if ($maxTime < $curTime)
 776              {
 777                  $this->setState(SessionState::EXPIRED);
 778  
 779                  return false;
 780              }
 781          }
 782  
 783          try
 784          {
 785              foreach ($this->sessionValidators as $validator)
 786              {
 787                  $validator->validate($restart);
 788              }
 789          }
 790          catch (Exception\InvalidSessionException $e)
 791          {
 792              $this->setState(SessionState::ERROR);
 793  
 794              return false;
 795          }
 796  
 797          return true;
 798      }
 799  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer