PageRenderTime 79ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/session/session.php

https://bitbucket.org/eternaware/joomus
PHP | 1012 lines | 448 code | 125 blank | 439 comment | 59 complexity | 1efc68f36b327f8463dea5a7f6eab174 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Session
  5. *
  6. * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. /**
  11. * Class for managing HTTP sessions
  12. *
  13. * Provides access to session-state values as well as session-level
  14. * settings and lifetime management methods.
  15. * Based on the standard PHP session handling mechanism it provides
  16. * more advanced features such as expire timeouts.
  17. *
  18. * @package Joomla.Platform
  19. * @subpackage Session
  20. * @since 11.1
  21. */
  22. class JSession implements IteratorAggregate
  23. {
  24. /**
  25. * Internal state.
  26. * One of 'inactive'|'active'|'expired'|'destroyed'|'error'
  27. *
  28. * @var string
  29. * @see getState()
  30. * @since 11.1
  31. */
  32. protected $_state = 'inactive';
  33. /**
  34. * Maximum age of unused session in minutes
  35. *
  36. * @var string
  37. * @since 11.1
  38. */
  39. protected $_expire = 15;
  40. /**
  41. * The session store object.
  42. *
  43. * @var JSessionStorage
  44. * @since 11.1
  45. */
  46. protected $_store = null;
  47. /**
  48. * Security policy.
  49. * List of checks that will be done.
  50. *
  51. * Default values:
  52. * - fix_browser
  53. * - fix_adress
  54. *
  55. * @var array
  56. * @since 11.1
  57. */
  58. protected $_security = array('fix_browser');
  59. /**
  60. * Force cookies to be SSL only
  61. * Default false
  62. *
  63. * @var boolean
  64. * @since 11.1
  65. */
  66. protected $_force_ssl = false;
  67. /**
  68. * @var JSession JSession instances container.
  69. * @since 11.3
  70. */
  71. protected static $instance;
  72. /**
  73. * @var string
  74. * @since 12.2
  75. */
  76. protected $storeName;
  77. /**
  78. * Holds the JInput object
  79. *
  80. * @var JInput
  81. * @since 12.2
  82. */
  83. private $_input = null;
  84. /**
  85. * Holds the event dispatcher object
  86. *
  87. * @var JEventDispatcher
  88. * @since 12.2
  89. */
  90. private $_dispatcher = null;
  91. /**
  92. * Constructor
  93. *
  94. * @param string $store The type of storage for the session.
  95. * @param array $options Optional parameters
  96. *
  97. * @since 11.1
  98. */
  99. public function __construct($store = 'none', array $options = array())
  100. {
  101. // Need to destroy any existing sessions started with session.auto_start
  102. if (session_id())
  103. {
  104. session_unset();
  105. session_destroy();
  106. }
  107. // Disable transparent sid support
  108. ini_set('session.use_trans_sid', '0');
  109. // Only allow the session ID to come from cookies and nothing else.
  110. ini_set('session.use_only_cookies', '1');
  111. // Create handler
  112. $this->_store = JSessionStorage::getInstance($store, $options);
  113. $this->storeName = $store;
  114. // Set options
  115. $this->_setOptions($options);
  116. $this->_setCookieParams();
  117. $this->_state = 'inactive';
  118. }
  119. /**
  120. * Magic method to get read-only access to properties.
  121. *
  122. * @param string $name Name of property to retrieve
  123. *
  124. * @return mixed The value of the property
  125. *
  126. * @since 12.2
  127. */
  128. public function __get($name)
  129. {
  130. if ($name === 'storeName')
  131. {
  132. return $this->$name;
  133. }
  134. if ($name === 'state' || $name === 'expire')
  135. {
  136. $property = '_' . $name;
  137. return $this->$property;
  138. }
  139. }
  140. /**
  141. * Returns the global Session object, only creating it
  142. * if it doesn't already exist.
  143. *
  144. * @param string $handler The type of session handler.
  145. * @param array $options An array of configuration options.
  146. *
  147. * @return JSession The Session object.
  148. *
  149. * @since 11.1
  150. */
  151. public static function getInstance($handler, $options)
  152. {
  153. if (!is_object(self::$instance))
  154. {
  155. self::$instance = new JSession($handler, $options);
  156. }
  157. return self::$instance;
  158. }
  159. /**
  160. * Get current state of session
  161. *
  162. * @return string The session state
  163. *
  164. * @since 11.1
  165. */
  166. public function getState()
  167. {
  168. return $this->_state;
  169. }
  170. /**
  171. * Get expiration time in minutes
  172. *
  173. * @return integer The session expiration time in minutes
  174. *
  175. * @since 11.1
  176. */
  177. public function getExpire()
  178. {
  179. return $this->_expire;
  180. }
  181. /**
  182. * Get a session token, if a token isn't set yet one will be generated.
  183. *
  184. * Tokens are used to secure forms from spamming attacks. Once a token
  185. * has been generated the system will check the post request to see if
  186. * it is present, if not it will invalidate the session.
  187. *
  188. * @param boolean $forceNew If true, force a new token to be created
  189. *
  190. * @return string The session token
  191. *
  192. * @since 11.1
  193. */
  194. public function getToken($forceNew = false)
  195. {
  196. $token = $this->get('session.token');
  197. // Create a token
  198. if ($token === null || $forceNew)
  199. {
  200. $token = $this->_createToken(12);
  201. $this->set('session.token', $token);
  202. }
  203. return $token;
  204. }
  205. /**
  206. * Method to determine if a token exists in the session. If not the
  207. * session will be set to expired
  208. *
  209. * @param string $tCheck Hashed token to be verified
  210. * @param boolean $forceExpire If true, expires the session
  211. *
  212. * @return boolean
  213. *
  214. * @since 11.1
  215. */
  216. public function hasToken($tCheck, $forceExpire = true)
  217. {
  218. // Check if a token exists in the session
  219. $tStored = $this->get('session.token');
  220. // Check token
  221. if (($tStored !== $tCheck))
  222. {
  223. if ($forceExpire)
  224. {
  225. $this->_state = 'expired';
  226. }
  227. return false;
  228. }
  229. return true;
  230. }
  231. /**
  232. * Method to determine a hash for anti-spoofing variable names
  233. *
  234. * @param boolean $forceNew If true, force a new token to be created
  235. *
  236. * @return string Hashed var name
  237. *
  238. * @since 11.1
  239. */
  240. public static function getFormToken($forceNew = false)
  241. {
  242. $user = JFactory::getUser();
  243. $session = JFactory::getSession();
  244. // TODO: Decouple from legacy JApplication class.
  245. if (is_callable(array('JApplication', 'getHash')))
  246. {
  247. $hash = JApplication::getHash($user->get('id', 0) . $session->getToken($forceNew));
  248. }
  249. else
  250. {
  251. $hash = md5(JFactory::getApplication()->get('secret') . $user->get('id', 0) . $session->getToken($forceNew));
  252. }
  253. return $hash;
  254. }
  255. /**
  256. * Retrieve an external iterator.
  257. *
  258. * @return ArrayIterator Return an ArrayIterator of $_SESSION.
  259. *
  260. * @since 12.2
  261. */
  262. public function getIterator()
  263. {
  264. return new ArrayIterator($_SESSION);
  265. }
  266. /**
  267. * Checks for a form token in the request.
  268. *
  269. * Use in conjunction with JHtml::_('form.token') or JSession::getFormToken.
  270. *
  271. * @param string $method The request method in which to look for the token key.
  272. *
  273. * @return boolean True if found and valid, false otherwise.
  274. *
  275. * @since 12.1
  276. */
  277. public static function checkToken($method = 'post')
  278. {
  279. $token = self::getFormToken();
  280. $app = JFactory::getApplication();
  281. if (!$app->input->$method->get($token, '', 'alnum'))
  282. {
  283. $session = JFactory::getSession();
  284. if ($session->isNew())
  285. {
  286. // Redirect to login screen.
  287. $app->redirect(JRoute::_('index.php'), JText::_('JLIB_ENVIRONMENT_SESSION_EXPIRED'));
  288. $app->close();
  289. }
  290. else
  291. {
  292. return false;
  293. }
  294. }
  295. else
  296. {
  297. return true;
  298. }
  299. }
  300. /**
  301. * Get session name
  302. *
  303. * @return string The session name
  304. *
  305. * @since 11.1
  306. */
  307. public function getName()
  308. {
  309. if ($this->_state === 'destroyed')
  310. {
  311. // @TODO : raise error
  312. return null;
  313. }
  314. return session_name();
  315. }
  316. /**
  317. * Get session id
  318. *
  319. * @return string The session name
  320. *
  321. * @since 11.1
  322. */
  323. public function getId()
  324. {
  325. if ($this->_state === 'destroyed')
  326. {
  327. // @TODO : raise error
  328. return null;
  329. }
  330. return session_id();
  331. }
  332. /**
  333. * Get the session handlers
  334. *
  335. * @return array An array of available session handlers
  336. *
  337. * @since 11.1
  338. */
  339. public static function getStores()
  340. {
  341. $connectors = array();
  342. // Get an iterator and loop trough the driver classes.
  343. $iterator = new DirectoryIterator(__DIR__ . '/storage');
  344. foreach ($iterator as $file)
  345. {
  346. $fileName = $file->getFilename();
  347. // Only load for php files.
  348. // Note: DirectoryIterator::getExtension only available PHP >= 5.3.6
  349. if (!$file->isFile() || substr($fileName, strrpos($fileName, '.') + 1) != 'php')
  350. {
  351. continue;
  352. }
  353. // Derive the class name from the type.
  354. $class = str_ireplace('.php', '', 'JSessionStorage' . ucfirst(trim($fileName)));
  355. // If the class doesn't exist we have nothing left to do but look at the next type. We did our best.
  356. if (!class_exists($class))
  357. {
  358. continue;
  359. }
  360. // Sweet! Our class exists, so now we just need to know if it passes its test method.
  361. if ($class::isSupported())
  362. {
  363. // Connector names should not have file extensions.
  364. $connectors[] = str_ireplace('.php', '', $fileName);
  365. }
  366. }
  367. return $connectors;
  368. }
  369. /**
  370. * Shorthand to check if the session is active
  371. *
  372. * @return boolean
  373. *
  374. * @since 12.2
  375. */
  376. public function isActive()
  377. {
  378. return (bool) ($this->_state == 'active');
  379. }
  380. /**
  381. * Check whether this session is currently created
  382. *
  383. * @return boolean True on success.
  384. *
  385. * @since 11.1
  386. */
  387. public function isNew()
  388. {
  389. $counter = $this->get('session.counter');
  390. return (bool) ($counter === 1);
  391. }
  392. /**
  393. * Check whether this session is currently created
  394. *
  395. * @param JInput $input JInput object for the session to use.
  396. * @param JEventDispatcher $dispatcher Dispatcher object for the session to use.
  397. *
  398. * @return void.
  399. *
  400. * @since 12.2
  401. */
  402. public function initialise(JInput $input, JEventDispatcher $dispatcher = null)
  403. {
  404. $this->_input = $input;
  405. $this->_dispatcher = $dispatcher;
  406. }
  407. /**
  408. * Get data from the session store
  409. *
  410. * @param string $name Name of a variable
  411. * @param mixed $default Default value of a variable if not set
  412. * @param string $namespace Namespace to use, default to 'default'
  413. *
  414. * @return mixed Value of a variable
  415. *
  416. * @since 11.1
  417. */
  418. public function get($name, $default = null, $namespace = 'default')
  419. {
  420. // Add prefix to namespace to avoid collisions
  421. $namespace = '__' . $namespace;
  422. if ($this->_state !== 'active' && $this->_state !== 'expired')
  423. {
  424. // @TODO :: generated error here
  425. $error = null;
  426. return $error;
  427. }
  428. if (isset($_SESSION[$namespace][$name]))
  429. {
  430. return $_SESSION[$namespace][$name];
  431. }
  432. return $default;
  433. }
  434. /**
  435. * Set data into the session store.
  436. *
  437. * @param string $name Name of a variable.
  438. * @param mixed $value Value of a variable.
  439. * @param string $namespace Namespace to use, default to 'default'.
  440. *
  441. * @return mixed Old value of a variable.
  442. *
  443. * @since 11.1
  444. */
  445. public function set($name, $value = null, $namespace = 'default')
  446. {
  447. // Add prefix to namespace to avoid collisions
  448. $namespace = '__' . $namespace;
  449. if ($this->_state !== 'active')
  450. {
  451. // @TODO :: generated error here
  452. return null;
  453. }
  454. $old = isset($_SESSION[$namespace][$name]) ? $_SESSION[$namespace][$name] : null;
  455. if (null === $value)
  456. {
  457. unset($_SESSION[$namespace][$name]);
  458. }
  459. else
  460. {
  461. $_SESSION[$namespace][$name] = $value;
  462. }
  463. return $old;
  464. }
  465. /**
  466. * Check whether data exists in the session store
  467. *
  468. * @param string $name Name of variable
  469. * @param string $namespace Namespace to use, default to 'default'
  470. *
  471. * @return boolean True if the variable exists
  472. *
  473. * @since 11.1
  474. */
  475. public function has($name, $namespace = 'default')
  476. {
  477. // Add prefix to namespace to avoid collisions.
  478. $namespace = '__' . $namespace;
  479. if ($this->_state !== 'active')
  480. {
  481. // @TODO :: generated error here
  482. return null;
  483. }
  484. return isset($_SESSION[$namespace][$name]);
  485. }
  486. /**
  487. * Unset data from the session store
  488. *
  489. * @param string $name Name of variable
  490. * @param string $namespace Namespace to use, default to 'default'
  491. *
  492. * @return mixed The value from session or NULL if not set
  493. *
  494. * @since 11.1
  495. */
  496. public function clear($name, $namespace = 'default')
  497. {
  498. // Add prefix to namespace to avoid collisions
  499. $namespace = '__' . $namespace;
  500. if ($this->_state !== 'active')
  501. {
  502. // @TODO :: generated error here
  503. return null;
  504. }
  505. $value = null;
  506. if (isset($_SESSION[$namespace][$name]))
  507. {
  508. $value = $_SESSION[$namespace][$name];
  509. unset($_SESSION[$namespace][$name]);
  510. }
  511. return $value;
  512. }
  513. /**
  514. * Start a session.
  515. *
  516. * @return void
  517. *
  518. * @since 12.2
  519. */
  520. public function start()
  521. {
  522. if ($this->_state === 'active')
  523. {
  524. return;
  525. }
  526. $this->_start();
  527. $this->_state = 'active';
  528. // Initialise the session
  529. $this->_setCounter();
  530. $this->_setTimers();
  531. // Perform security checks
  532. $this->_validate();
  533. if ($this->_dispatcher instanceof JEventDispatcher)
  534. {
  535. $this->_dispatcher->trigger('onAfterSessionStart');
  536. }
  537. }
  538. /**
  539. * Start a session.
  540. *
  541. * Creates a session (or resumes the current one based on the state of the session)
  542. *
  543. * @return boolean true on success
  544. *
  545. * @since 11.1
  546. */
  547. protected function _start()
  548. {
  549. // Start session if not started
  550. if ($this->_state === 'restart')
  551. {
  552. session_regenerate_id(true);
  553. }
  554. else
  555. {
  556. $session_name = session_name();
  557. // Get the JInputCookie object
  558. $cookie = $this->_input->cookie;
  559. if (is_null($cookie->get($session_name)))
  560. {
  561. $session_clean = $this->_input->get($session_name, false, 'string');
  562. if ($session_clean)
  563. {
  564. session_id($session_clean);
  565. $cookie->set($session_name, '', time() - 3600);
  566. }
  567. }
  568. }
  569. /**
  570. * Write and Close handlers are called after destructing objects since PHP 5.0.5.
  571. * Thus destructors can use sessions but session handler can't use objects.
  572. * So we are moving session closure before destructing objects.
  573. *
  574. * Replace with session_register_shutdown() when dropping compatibility with PHP 5.3
  575. */
  576. register_shutdown_function('session_write_close');
  577. session_cache_limiter('none');
  578. session_start();
  579. return true;
  580. }
  581. /**
  582. * Frees all session variables and destroys all data registered to a session
  583. *
  584. * This method resets the $_SESSION variable and destroys all of the data associated
  585. * with the current session in its storage (file or DB). It forces new session to be
  586. * started after this method is called. It does not unset the session cookie.
  587. *
  588. * @return boolean True on success
  589. *
  590. * @see session_destroy()
  591. * @see session_unset()
  592. * @since 11.1
  593. */
  594. public function destroy()
  595. {
  596. // Session was already destroyed
  597. if ($this->_state === 'destroyed')
  598. {
  599. return true;
  600. }
  601. /*
  602. * In order to kill the session altogether, such as to log the user out, the session id
  603. * must also be unset. If a cookie is used to propagate the session id (default behavior),
  604. * then the session cookie must be deleted.
  605. */
  606. if (isset($_COOKIE[session_name()]))
  607. {
  608. $config = JFactory::getConfig();
  609. $cookie_domain = $config->get('cookie_domain', '');
  610. $cookie_path = $config->get('cookie_path', '/');
  611. setcookie(session_name(), '', time() - 42000, $cookie_path, $cookie_domain);
  612. }
  613. session_unset();
  614. session_destroy();
  615. $this->_state = 'destroyed';
  616. return true;
  617. }
  618. /**
  619. * Restart an expired or locked session.
  620. *
  621. * @return boolean True on success
  622. *
  623. * @see destroy
  624. * @since 11.1
  625. */
  626. public function restart()
  627. {
  628. $this->destroy();
  629. if ($this->_state !== 'destroyed')
  630. {
  631. // @TODO :: generated error here
  632. return false;
  633. }
  634. // Re-register the session handler after a session has been destroyed, to avoid PHP bug
  635. $this->_store->register();
  636. $this->_state = 'restart';
  637. // Regenerate session id
  638. session_regenerate_id(true);
  639. $this->_start();
  640. $this->_state = 'active';
  641. $this->_validate();
  642. $this->_setCounter();
  643. return true;
  644. }
  645. /**
  646. * Create a new session and copy variables from the old one
  647. *
  648. * @return boolean $result true on success
  649. *
  650. * @since 11.1
  651. */
  652. public function fork()
  653. {
  654. if ($this->_state !== 'active')
  655. {
  656. // @TODO :: generated error here
  657. return false;
  658. }
  659. // Save values
  660. $values = $_SESSION;
  661. // Keep session config
  662. $cookie = session_get_cookie_params();
  663. // Kill session
  664. session_destroy();
  665. // Re-register the session store after a session has been destroyed, to avoid PHP bug
  666. $this->_store->register();
  667. // Restore config
  668. session_set_cookie_params($cookie['lifetime'], $cookie['path'], $cookie['domain'], $cookie['secure'], true);
  669. // Restart session with new id
  670. session_regenerate_id(true);
  671. session_start();
  672. return true;
  673. }
  674. /**
  675. * Writes session data and ends session
  676. *
  677. * Session data is usually stored after your script terminated without the need
  678. * to call JSession::close(), but as session data is locked to prevent concurrent
  679. * writes only one script may operate on a session at any time. When using
  680. * framesets together with sessions you will experience the frames loading one
  681. * by one due to this locking. You can reduce the time needed to load all the
  682. * frames by ending the session as soon as all changes to session variables are
  683. * done.
  684. *
  685. * @return void
  686. *
  687. * @see session_write_close()
  688. * @since 11.1
  689. */
  690. public function close()
  691. {
  692. session_write_close();
  693. }
  694. /**
  695. * Set session cookie parameters
  696. *
  697. * @return void
  698. *
  699. * @since 11.1
  700. */
  701. protected function _setCookieParams()
  702. {
  703. $cookie = session_get_cookie_params();
  704. if ($this->_force_ssl)
  705. {
  706. $cookie['secure'] = true;
  707. }
  708. $config = JFactory::getConfig();
  709. if ($config->get('cookie_domain', '') != '')
  710. {
  711. $cookie['domain'] = $config->get('cookie_domain');
  712. }
  713. if ($config->get('cookie_path', '') != '')
  714. {
  715. $cookie['path'] = $config->get('cookie_path');
  716. }
  717. session_set_cookie_params($cookie['lifetime'], $cookie['path'], $cookie['domain'], $cookie['secure'], true);
  718. }
  719. /**
  720. * Create a token-string
  721. *
  722. * @param integer $length Length of string
  723. *
  724. * @return string Generated token
  725. *
  726. * @since 11.1
  727. */
  728. protected function _createToken($length = 32)
  729. {
  730. static $chars = '0123456789abcdef';
  731. $max = strlen($chars) - 1;
  732. $token = '';
  733. $name = session_name();
  734. for ($i = 0; $i < $length; ++$i)
  735. {
  736. $token .= $chars[(rand(0, $max))];
  737. }
  738. return md5($token . $name);
  739. }
  740. /**
  741. * Set counter of session usage
  742. *
  743. * @return boolean True on success
  744. *
  745. * @since 11.1
  746. */
  747. protected function _setCounter()
  748. {
  749. $counter = $this->get('session.counter', 0);
  750. ++$counter;
  751. $this->set('session.counter', $counter);
  752. return true;
  753. }
  754. /**
  755. * Set the session timers
  756. *
  757. * @return boolean True on success
  758. *
  759. * @since 11.1
  760. */
  761. protected function _setTimers()
  762. {
  763. if (!$this->has('session.timer.start'))
  764. {
  765. $start = time();
  766. $this->set('session.timer.start', $start);
  767. $this->set('session.timer.last', $start);
  768. $this->set('session.timer.now', $start);
  769. }
  770. $this->set('session.timer.last', $this->get('session.timer.now'));
  771. $this->set('session.timer.now', time());
  772. return true;
  773. }
  774. /**
  775. * Set additional session options
  776. *
  777. * @param array $options List of parameter
  778. *
  779. * @return boolean True on success
  780. *
  781. * @since 11.1
  782. */
  783. protected function _setOptions(array $options)
  784. {
  785. // Set name
  786. if (isset($options['name']))
  787. {
  788. session_name(md5($options['name']));
  789. }
  790. // Set id
  791. if (isset($options['id']))
  792. {
  793. session_id($options['id']);
  794. }
  795. // Set expire time
  796. if (isset($options['expire']))
  797. {
  798. $this->_expire = $options['expire'];
  799. }
  800. // Get security options
  801. if (isset($options['security']))
  802. {
  803. $this->_security = explode(',', $options['security']);
  804. }
  805. if (isset($options['force_ssl']))
  806. {
  807. $this->_force_ssl = (bool) $options['force_ssl'];
  808. }
  809. // Sync the session maxlifetime
  810. ini_set('session.gc_maxlifetime', $this->_expire);
  811. return true;
  812. }
  813. /**
  814. * Do some checks for security reason
  815. *
  816. * - timeout check (expire)
  817. * - ip-fixiation
  818. * - browser-fixiation
  819. *
  820. * If one check failed, session data has to be cleaned.
  821. *
  822. * @param boolean $restart Reactivate session
  823. *
  824. * @return boolean True on success
  825. *
  826. * @see http://shiflett.org/articles/the-truth-about-sessions
  827. * @since 11.1
  828. */
  829. protected function _validate($restart = false)
  830. {
  831. // Allow to restart a session
  832. if ($restart)
  833. {
  834. $this->_state = 'active';
  835. $this->set('session.client.address', null);
  836. $this->set('session.client.forwarded', null);
  837. $this->set('session.client.browser', null);
  838. $this->set('session.token', null);
  839. }
  840. // Check if session has expired
  841. if ($this->_expire)
  842. {
  843. $curTime = $this->get('session.timer.now', 0);
  844. $maxTime = $this->get('session.timer.last', 0) + $this->_expire;
  845. // Empty session variables
  846. if ($maxTime < $curTime)
  847. {
  848. $this->_state = 'expired';
  849. return false;
  850. }
  851. }
  852. // Record proxy forwarded for in the session in case we need it later
  853. if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
  854. {
  855. $this->set('session.client.forwarded', $_SERVER['HTTP_X_FORWARDED_FOR']);
  856. }
  857. // Check for client address
  858. if (in_array('fix_adress', $this->_security) && isset($_SERVER['REMOTE_ADDR']))
  859. {
  860. $ip = $this->get('session.client.address');
  861. if ($ip === null)
  862. {
  863. $this->set('session.client.address', $_SERVER['REMOTE_ADDR']);
  864. }
  865. elseif ($_SERVER['REMOTE_ADDR'] !== $ip)
  866. {
  867. $this->_state = 'error';
  868. return false;
  869. }
  870. }
  871. // Check for clients browser
  872. if (in_array('fix_browser', $this->_security) && isset($_SERVER['HTTP_USER_AGENT']))
  873. {
  874. $browser = $this->get('session.client.browser');
  875. if ($browser === null)
  876. {
  877. $this->set('session.client.browser', $_SERVER['HTTP_USER_AGENT']);
  878. }
  879. elseif ($_SERVER['HTTP_USER_AGENT'] !== $browser)
  880. {
  881. // @todo remove code: $this->_state = 'error';
  882. // @todo remove code: return false;
  883. }
  884. }
  885. return true;
  886. }
  887. }