[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |