classes/XLite/Core/Session.php line 130

Open in your IDE?
  1. <?php
  2. /**
  3.  * Copyright (c) 2011-present Qualiteam software Ltd. All rights reserved.
  4.  * See https://www.x-cart.com/license-agreement.html for license details.
  5.  */
  6. namespace XLite\Core;
  7. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  8. use XCart\Container;
  9. use XLite\Model\Profile;
  10. use XLite\Model\Role\Permission;
  11. /**
  12.  * Current session
  13.  */
  14. class Session extends \XLite\Base\Singleton
  15. {
  16.     use FormIdsTrait;
  17.     /**
  18.      * Maximum admin session TTL (12 hours)
  19.      */
  20.     public const MAX_ADMIN_TTL 43200;
  21.     /**
  22.      * Public session id argument name
  23.      */
  24.     public const ARGUMENT_NAME 'xid';
  25.     /**
  26.      * Referer cookie name
  27.      */
  28.     public const LC_REFERER_COOKIE_NAME 'LCRefererCookie';
  29.     /**
  30.      * Name of the cell to store the cURL error code value
  31.      */
  32.     public const CURL_CODE_ERROR 'curl_code_error_in_session';
  33.     /**
  34.      * Name of the cell to store the cURL error code value
  35.      */
  36.     public const CURL_CODE_ERROR_MESSAGE 'curl_error_message_in_session';
  37.     /**
  38.      * Session
  39.      *
  40.      * @var SessionInterface
  41.      */
  42.     protected $session;
  43.     /**
  44.      * Language (cache)
  45.      *
  46.      * @var \XLite\Model\Language
  47.      */
  48.     protected $language;
  49.     /**
  50.      * Get session TTL (seconds)
  51.      *
  52.      * @return integer
  53.      */
  54.     public static function getTTL(): int
  55.     {
  56.         return 0;
  57.     }
  58.     /**
  59.      * Getter
  60.      *
  61.      * @param string $name Session cell name
  62.      *
  63.      * @return mixed
  64.      */
  65.     public function __get(string $name)
  66.     {
  67.         return $this->session->get($name);
  68.     }
  69.     /**
  70.      * Setter
  71.      *
  72.      * @param string $name  Session cell name
  73.      * @param mixed  $value Value
  74.      *
  75.      * @return void
  76.      */
  77.     public function __set(string $name$value)
  78.     {
  79.         $this->session->set($name$value);
  80.     }
  81.     /**
  82.      * Check session cell availability
  83.      *
  84.      * @param string $name Session cell name
  85.      *
  86.      * @return boolean
  87.      */
  88.     public function __isset(string $name)
  89.     {
  90.         return $this->session->has($name);
  91.     }
  92.     /**
  93.      * Remove session cell
  94.      *
  95.      * @param string $name Session cell name
  96.      *
  97.      * @return void
  98.      */
  99.     public function __unset(string $name)
  100.     {
  101.         $this->session->remove($name);
  102.     }
  103.     /**
  104.      * Getter
  105.      * DEPRECATE
  106.      *
  107.      * @param string $name Session cell name
  108.      *
  109.      * @return mixed
  110.      */
  111.     public function get(string $name)
  112.     {
  113.         return $this->session->get($name);
  114.     }
  115.     /**
  116.      * Setter
  117.      * DEPRECATE
  118.      *
  119.      * @param string $name  Session cell name
  120.      * @param mixed  $value Value
  121.      *
  122.      * @return void
  123.      */
  124.     public function set(string $name$value)
  125.     {
  126.         $this->session->set($name$value);
  127.     }
  128.     /**
  129.      * Unset in batch mode
  130.      *
  131.      * @return void
  132.      */
  133.     public function unsetBatch()
  134.     {
  135.         foreach (func_get_args() as $name) {
  136.             $this->session->remove($name);
  137.         }
  138.     }
  139.     public function setProfile(Profile $profile)
  140.     {
  141.         $this->__set('profile_id'$profile->getProfileId());
  142.         if ($profile->isAdmin() && $profile->isPermissionAllowed(Permission::ROOT_ACCESS)) {
  143.             $this->set('isAdmin'true);
  144.             $this->setCookie();
  145.         }
  146.     }
  147.     /**
  148.      * Stores the cURL error code into session
  149.      *
  150.      * @param integer $code cURL error
  151.      *
  152.      * @return void
  153.      */
  154.     public function storeCURLError($code)
  155.     {
  156.         $this->{static::CURL_CODE_ERROR} = $code;
  157.     }
  158.     /**
  159.      * Returns the cURL error code from session
  160.      *
  161.      * @return integer
  162.      */
  163.     public function getCURLError()
  164.     {
  165.         $result $this->{static::CURL_CODE_ERROR};
  166.         $this->storeCURLError(null);
  167.         return $result;
  168.     }
  169.     /**
  170.      * Stores the cURL error message into session
  171.      *
  172.      * @param string $msg cURL error message
  173.      *
  174.      * @return void
  175.      */
  176.     public function storeCURLErrorMessage($msg)
  177.     {
  178.         $this->{static::CURL_CODE_ERROR_MESSAGE} = $msg;
  179.     }
  180.     /**
  181.      * Returns the cURL error message from session
  182.      *
  183.      * @return string
  184.      */
  185.     public function getCURLErrorMessage()
  186.     {
  187.         $result $this->{static::CURL_CODE_ERROR_MESSAGE};
  188.         $this->storeCURLErrorMessage(null);
  189.         return $result;
  190.     }
  191.     /**
  192.      * Get public session id argument name
  193.      *
  194.      * @return string
  195.      */
  196.     public function getName()
  197.     {
  198.         return self::ARGUMENT_NAME;
  199.     }
  200.     /**
  201.      * Get public session id
  202.      *
  203.      * @return string
  204.      */
  205.     public function getID()
  206.     {
  207.         return $this->session->getId();
  208.     }
  209.     /**
  210.      * Load session by public session id
  211.      *
  212.      * @param string $sid Public session id
  213.      *
  214.      * @return void
  215.      */
  216.     public function loadBySid(string $sid): void
  217.     {
  218.         if ($this->session->isStarted()) {
  219.             $this->session->save();
  220.         }
  221.         $this->session->setId($sid);
  222.     }
  223.     /**
  224.      * Session ID for forms
  225.      *
  226.      * @return string
  227.      */
  228.     public function getSessionId(): string
  229.     {
  230.         return $this->session->getId();
  231.     }
  232.     /**
  233.      * Invalidate session
  234.      *
  235.      * @return bool
  236.      */
  237.     public function invalidate(): bool
  238.     {
  239.         return $this->session->invalidate();
  240.     }
  241.     /**
  242.      * @return bool
  243.      */
  244.     public function isAdminSessionExpired(): bool
  245.     {
  246.         return time() - $this->session->getMetadataBag()->getLastUsed() > static::MAX_ADMIN_TTL;
  247.     }
  248.     /**
  249.      * Get language
  250.      *
  251.      * @return \XLite\Model\Language
  252.      */
  253.     public function getLanguage()
  254.     {
  255.         if (!isset($this->language)) {
  256.             $this->language \XLite\Core\Database::getRepo('XLite\Model\Language')
  257.                 ->findOneByCode($this->getCurrentLanguage());
  258.         }
  259.         return $this->language;
  260.     }
  261.     /**
  262.      * Set language
  263.      *
  264.      * @param string $language Language code
  265.      * @param string $zone     Admin/customer zone OPTIONAL
  266.      *
  267.      * @return void
  268.      */
  269.     public function setLanguage($language$zone null)
  270.     {
  271.         $code $this->__get('language');
  272.         if (!isset($zone)) {
  273.             $zone \XLite::isAdminZone() ? 'admin' 'customer';
  274.         }
  275.         if (!is_array($code)) {
  276.             $code = [];
  277.         }
  278.         if (!isset($code[$zone]) || $code[$zone] !== $language) {
  279.             $code[$zone] = $language;
  280.             $this->__set('language'$code);
  281.             $this->language null;
  282.         }
  283.     }
  284.     /**
  285.      * Constructor
  286.      *
  287.      * @return void
  288.      */
  289.     protected function __construct()
  290.     {
  291.         /** @var SessionInterface $session */
  292.         $this->session = !$this->useDumpSession()
  293.             ? Container::getServiceLocator()->getSession()
  294.             : new SessionDump();
  295.         $this->setCookie();
  296.     }
  297.     /**
  298.      * Set cookie
  299.      *
  300.      * @return void
  301.      */
  302.     protected function setCookie()
  303.     {
  304.         if (
  305.             PHP_SAPI !== 'cli'
  306.             && !headers_sent()
  307.             && (
  308.                 \XLite\Core\Request::getInstance()->isHTTPS()
  309.                 || !\XLite\Core\Config::getInstance()->Security->customer_security
  310.             )
  311.         ) {
  312.             if (!$this->useDumpSession()) {
  313.                 $this->setLCRefererCookie();
  314.             }
  315.         }
  316.     }
  317.     /**
  318.      * Set referer cookie (this is stored when user register new profile)
  319.      *
  320.      * @return void
  321.      */
  322.     protected function setLCRefererCookie()
  323.     {
  324.         if (!isset($_COOKIE[static::LC_REFERER_COOKIE_NAME]) && isset($_SERVER['HTTP_REFERER'])) {
  325.             $referer parse_url($_SERVER['HTTP_REFERER']);
  326.             if (isset($referer['host']) && $referer['host'] != $_SERVER['HTTP_HOST']) {
  327.                 \XLite\Core\Request::getInstance()->setCookie(
  328.                     static::LC_REFERER_COOKIE_NAME,
  329.                     $_SERVER['HTTP_REFERER'],
  330.                     $this->getLCRefererCookieTTL()
  331.                 );
  332.             }
  333.         }
  334.     }
  335.     /**
  336.      * Get parsed URL for Set-Cookie
  337.      *
  338.      * @param boolean $secure Secure protocol or not OPTIONAL
  339.      *
  340.      * @return array
  341.      */
  342.     protected function getCookieURL($secure false)
  343.     {
  344.         $url $secure
  345.             'https://' .  \Includes\Utils\ConfigParser::getOptions(['host_details''https_host'])
  346.             : 'http://' \Includes\Utils\ConfigParser::getOptions(['host_details''http_host']);
  347.         $url .= \Includes\Utils\ConfigParser::getOptions(['host_details''web_dir']);
  348.         return parse_url($url);
  349.     }
  350.     /**
  351.      * Get host / domain for Set-Cookie
  352.      *
  353.      * @param boolean $secure Secure protocol or not OPTIONAL
  354.      *
  355.      * @return string
  356.      */
  357.     protected function getCookieDomain($secure false)
  358.     {
  359.         $url $this->getCookieURL($secure);
  360.         return strstr($url['host'], '.') === false false $url['host'];
  361.     }
  362.     /**
  363.      * Get URL path for Set-Cookie
  364.      *
  365.      * @param boolean $secure Secure protocol or not OPTIONAL
  366.      *
  367.      * @return string
  368.      */
  369.     protected function getCookiePath($secure false)
  370.     {
  371.         $url $this->getCookieURL($secure);
  372.         return $url['path'] ?? '/';
  373.     }
  374.     /**
  375.      * Get referer cookie TTL (seconds)
  376.      *
  377.      * @return integer
  378.      */
  379.     protected function getLCRefererCookieTTL()
  380.     {
  381.         return 3600 24 180// TTL is 180 days
  382.     }
  383.     /**
  384.      * Get current language
  385.      *
  386.      * @param string $zone Store zone OPTIONAL
  387.      * @return string Language code
  388.      */
  389.     public function getCurrentLanguage($zone null)
  390.     {
  391.         $code $this->__get('language');
  392.         if (!$zone) {
  393.             $zone \XLite::isAdminZone() ? 'admin' 'customer';
  394.         }
  395.         if (!is_array($code)) {
  396.             $code = [];
  397.         }
  398.         $useCleanUrls defined('LC_USE_CLEAN_URLS') && LC_USE_CLEAN_URLS == true;
  399.         $languageCodeFromRequest \XLite\Core\Request::getInstance()->getLanguageCode();
  400.         if ($useCleanUrls && \XLite\Core\Router::getInstance()->isUseLanguageUrls() && $languageCodeFromRequest) {
  401.             $code array_merge($code, ['customer' => $languageCodeFromRequest]);
  402.         }
  403.         if (!empty($code[$zone])) {
  404.             $language \XLite\Core\Database::getRepo('XLite\Model\Language')->findOneByCode($code[$zone]);
  405.             if (!isset($language) || !$language->getAdded() || !$language->getEnabled()) {
  406.                 unset($code[$zone]);
  407.             } elseif ($useCleanUrls && \XLite\Core\Router::getInstance()->isUseLanguageUrls() && $languageCodeFromRequest) {
  408.                 $lang $this->__get('language') ?: [];
  409.                 $lang['customer'] = $languageCodeFromRequest;
  410.                 $this->__set('language'$lang);
  411.             }
  412.         }
  413.         if (empty($code[$zone])) {
  414.             $this->setLanguage($this->defineCurrentLanguage());
  415.             $code $this->__get('language');
  416.         }
  417.         return $code[$zone];
  418.     }
  419.     /**
  420.      * Define current language
  421.      *
  422.      * @return string Language code
  423.      */
  424.     protected function defineCurrentLanguage()
  425.     {
  426.         $languages \XLite\Core\Database::getRepo('XLite\Model\Language')->findActiveLanguages();
  427.         if (!\XLite::isAdminZone() && !empty($languages)) {
  428.             $language = isset(\XLite\Core\Config::getInstance()->General)
  429.                 ? \XLite\Core\Config::getInstance()->General->default_language
  430.                 'en';
  431.             $result \Includes\Utils\ArrayManager::searchInObjectsArray(
  432.                 $languages,
  433.                 'getCode',
  434.                 $language
  435.             );
  436.         }
  437.         return isset($result) ? $result->getCode() : static::getDefaultLanguage();
  438.     }
  439.     /**
  440.      * Use dump session or not
  441.      *
  442.      * @return boolean
  443.      */
  444.     protected function useDumpSession(): bool
  445.     {
  446.         return PHP_SAPI === 'cli' || \XLite\Core\Request::getInstance()->isBot();
  447.     }
  448.     /**
  449.      * Return array of \XLite\Model\AccessControlCell belongs to this session
  450.      *
  451.      * @return \XLite\Model\AccessControlCell[]
  452.      */
  453.     public function getAccessControlCells(): array
  454.     {
  455.         $cells = [];
  456.         $hashes $this->access_control_cells;
  457.         if (!empty($hashes)) {
  458.             $cells \XLite\Core\Database::getRepo('\XLite\Model\AccessControlCell')->findByHashes($hashes);
  459.             foreach ($cells as $key => $cell) {
  460.                 if (!is_object($cell)) {
  461.                     unset($cells[$key]);
  462.                 }
  463.             }
  464.         }
  465.         return $cells;
  466.     }
  467.     /**
  468.      * @param string $hash
  469.      *
  470.      * @return $this
  471.      */
  472.     public function addAccessControlCellHash(string $hash): Session
  473.     {
  474.         $hashes $this->access_control_cells;
  475.         $hashes[] = $hash;
  476.         $this->access_control_cells array_unique($hashes);
  477.         return $this;
  478.     }
  479. }