Config.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. <?php
  2. /**
  3. * Session configuration object
  4. *
  5. * Copyright © Magento, Inc. All rights reserved.
  6. * See COPYING.txt for license details.
  7. */
  8. namespace Magento\Framework\Session;
  9. use Magento\Framework\App\DeploymentConfig;
  10. use Magento\Framework\App\Filesystem\DirectoryList;
  11. use Magento\Framework\Filesystem;
  12. use Magento\Framework\Session\Config\ConfigInterface;
  13. /**
  14. * Magento session configuration
  15. *
  16. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  17. */
  18. class Config implements ConfigInterface
  19. {
  20. /** Configuration path for session save method */
  21. const PARAM_SESSION_SAVE_METHOD = 'session/save';
  22. /** Configuration path for session save path */
  23. const PARAM_SESSION_SAVE_PATH = 'session/save_path';
  24. /** Configuration path for session cache limiter */
  25. const PARAM_SESSION_CACHE_LIMITER = 'session/cache_limiter';
  26. /** Configuration path for cookie domain */
  27. const XML_PATH_COOKIE_DOMAIN = 'web/cookie/cookie_domain';
  28. /** Configuration path for cookie lifetime */
  29. const XML_PATH_COOKIE_LIFETIME = 'web/cookie/cookie_lifetime';
  30. /** Configuration path for cookie http only param */
  31. const XML_PATH_COOKIE_HTTPONLY = 'web/cookie/cookie_httponly';
  32. /** Configuration path for cookie path */
  33. const XML_PATH_COOKIE_PATH = 'web/cookie/cookie_path';
  34. /** Cookie default lifetime */
  35. const COOKIE_LIFETIME_DEFAULT = 3600;
  36. /**
  37. * All options
  38. *
  39. * @var array
  40. */
  41. protected $options = [];
  42. /**
  43. * @var \Magento\Framework\App\Config\ScopeConfigInterface
  44. */
  45. protected $_scopeConfig;
  46. /**
  47. * @var \Magento\Framework\Stdlib\StringUtils
  48. */
  49. protected $_stringHelper;
  50. /**
  51. * @var \Magento\Framework\App\RequestInterface
  52. */
  53. protected $_httpRequest;
  54. /**
  55. * List of boolean options
  56. *
  57. * @var string[]
  58. */
  59. protected $booleanOptions = [
  60. 'session.use_cookies',
  61. 'session.use_only_cookies',
  62. 'session.use_trans_sid',
  63. 'session.cookie_httponly',
  64. ];
  65. /**
  66. * @var string
  67. */
  68. protected $_scopeType;
  69. /**
  70. * @var string
  71. */
  72. protected $lifetimePath;
  73. /**
  74. * @var \Magento\Framework\ValidatorFactory
  75. */
  76. protected $_validatorFactory;
  77. /**
  78. * @param \Magento\Framework\ValidatorFactory $validatorFactory
  79. * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  80. * @param \Magento\Framework\Stdlib\StringUtils $stringHelper
  81. * @param \Magento\Framework\App\RequestInterface $request
  82. * @param Filesystem $filesystem
  83. * @param DeploymentConfig $deploymentConfig
  84. * @param string $scopeType
  85. * @param string $lifetimePath
  86. * @SuppressWarnings(PHPMD.NPathComplexity)
  87. */
  88. public function __construct(
  89. \Magento\Framework\ValidatorFactory $validatorFactory,
  90. \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  91. \Magento\Framework\Stdlib\StringUtils $stringHelper,
  92. \Magento\Framework\App\RequestInterface $request,
  93. Filesystem $filesystem,
  94. DeploymentConfig $deploymentConfig,
  95. $scopeType,
  96. $lifetimePath = self::XML_PATH_COOKIE_LIFETIME
  97. ) {
  98. $this->_validatorFactory = $validatorFactory;
  99. $this->_scopeConfig = $scopeConfig;
  100. $this->_stringHelper = $stringHelper;
  101. $this->_httpRequest = $request;
  102. $this->_scopeType = $scopeType;
  103. $this->lifetimePath = $lifetimePath;
  104. /**
  105. * Session path
  106. */
  107. $savePath = $deploymentConfig->get(self::PARAM_SESSION_SAVE_PATH);
  108. if (!$savePath && !ini_get('session.save_path')) {
  109. $sessionDir = $filesystem->getDirectoryWrite(DirectoryList::SESSION);
  110. $savePath = $sessionDir->getAbsolutePath();
  111. $sessionDir->create();
  112. }
  113. if ($savePath) {
  114. $this->setSavePath($savePath);
  115. }
  116. /**
  117. * Session save handler - memcache, files, etc
  118. */
  119. $saveHandler = $deploymentConfig->get(self::PARAM_SESSION_SAVE_METHOD);
  120. if ($saveHandler) {
  121. $this->setOption('session.save_handler', $saveHandler);
  122. }
  123. /**
  124. * Session cache limiter
  125. */
  126. $cacheLimiter = $deploymentConfig->get(self::PARAM_SESSION_CACHE_LIMITER);
  127. if ($cacheLimiter) {
  128. $this->setOption('session.cache_limiter', $cacheLimiter);
  129. }
  130. /**
  131. * Cookie settings: lifetime, path, domain, httpOnly. These govern settings for the session cookie.
  132. */
  133. $lifetime = $this->_scopeConfig->getValue($this->lifetimePath, $this->_scopeType);
  134. $this->setCookieLifetime($lifetime, self::COOKIE_LIFETIME_DEFAULT);
  135. $path = $this->_scopeConfig->getValue(self::XML_PATH_COOKIE_PATH, $this->_scopeType);
  136. $path = empty($path) ? $this->_httpRequest->getBasePath() : $path;
  137. $this->setCookiePath($path, $this->_httpRequest->getBasePath());
  138. $domain = $this->_scopeConfig->getValue(self::XML_PATH_COOKIE_DOMAIN, $this->_scopeType);
  139. $domain = empty($domain) ? $this->_httpRequest->getHttpHost() : $domain;
  140. $this->setCookieDomain((string)$domain, $this->_httpRequest->getHttpHost());
  141. $this->setCookieHttpOnly(
  142. $this->_scopeConfig->getValue(self::XML_PATH_COOKIE_HTTPONLY, $this->_scopeType)
  143. );
  144. $secureURL = $this->_scopeConfig->getValue('web/secure/base_url', $this->_scopeType);
  145. $unsecureURL = $this->_scopeConfig->getValue('web/unsecure/base_url', $this->_scopeType);
  146. $isFullySecuredURL = $secureURL == $unsecureURL;
  147. $this->setCookieSecure($isFullySecuredURL && $this->_httpRequest->isSecure());
  148. }
  149. /**
  150. * Set many options at once
  151. *
  152. * @param array $options
  153. * @param array $default
  154. * @return $this
  155. */
  156. public function setOptions($options, $default = [])
  157. {
  158. $options = (!is_array($options) && !$options instanceof \Traversable) ? $default : $options;
  159. if (is_array($options) || $options instanceof \Traversable) {
  160. foreach ($options as $option => $value) {
  161. $setter = 'set' . $this->_stringHelper->upperCaseWords($option, '_', '');
  162. if (method_exists($this, $setter)) {
  163. $this->{$setter}($value);
  164. } else {
  165. $this->setOption($option, $value);
  166. }
  167. }
  168. }
  169. return $this;
  170. }
  171. /**
  172. * Get all options set
  173. *
  174. * @return array
  175. */
  176. public function getOptions()
  177. {
  178. return $this->options;
  179. }
  180. /**
  181. * Set an individual option
  182. *
  183. * @param string $option
  184. * @param mixed $value
  185. * @return $this
  186. */
  187. public function setOption($option, $value)
  188. {
  189. $option = $this->getFixedOptionName($option);
  190. $this->options[$option] = $value;
  191. return $this;
  192. }
  193. /**
  194. * Get an individual option
  195. *
  196. * @param string $option
  197. * @return mixed
  198. */
  199. public function getOption($option)
  200. {
  201. $option = $this->getFixedOptionName($option);
  202. if (array_key_exists($option, $this->options)) {
  203. return $this->options[$option];
  204. }
  205. $value = $this->getStorageOption($option);
  206. if (null !== $value) {
  207. $this->options[$option] = $value;
  208. return $value;
  209. }
  210. return null;
  211. }
  212. /**
  213. * Convert config to array
  214. *
  215. * @return array
  216. */
  217. public function toArray()
  218. {
  219. return $this->getOptions();
  220. }
  221. /**
  222. * Set session.name
  223. *
  224. * @param string $name
  225. * @param string|null $default
  226. * @return $this
  227. */
  228. public function setName($name, $default = null)
  229. {
  230. $name = (string)$name;
  231. $name = empty($name) ? $default : $name;
  232. if (!empty($name)) {
  233. $this->setOption('session.name', $name);
  234. }
  235. return $this;
  236. }
  237. /**
  238. * Get session.name
  239. *
  240. * @return string
  241. */
  242. public function getName()
  243. {
  244. return (string)$this->getOption('session.name');
  245. }
  246. /**
  247. * Set session.save_path
  248. *
  249. * @param string $savePath
  250. * @return $this
  251. */
  252. public function setSavePath($savePath)
  253. {
  254. $this->setOption('session.save_path', $savePath);
  255. return $this;
  256. }
  257. /**
  258. * Set session.save_path
  259. *
  260. * @return string
  261. */
  262. public function getSavePath()
  263. {
  264. return (string)$this->getOption('session.save_path');
  265. }
  266. /**
  267. * Set session.cookie_lifetime
  268. *
  269. * @param int $cookieLifetime
  270. * @param int|null $default
  271. * @return $this
  272. */
  273. public function setCookieLifetime($cookieLifetime, $default = null)
  274. {
  275. $validator = $this->_validatorFactory->create(
  276. [],
  277. \Magento\Framework\Session\Config\Validator\CookieLifetimeValidator::class
  278. );
  279. if ($validator->isValid($cookieLifetime)) {
  280. $this->setOption('session.cookie_lifetime', (int)$cookieLifetime);
  281. } elseif (null !== $default && $validator->isValid($default)) {
  282. $this->setOption('session.cookie_lifetime', (int)$default);
  283. }
  284. return $this;
  285. }
  286. /**
  287. * Get session.cookie_lifetime
  288. *
  289. * @return int
  290. */
  291. public function getCookieLifetime()
  292. {
  293. return (int)$this->getOption('session.cookie_lifetime');
  294. }
  295. /**
  296. * Set session.cookie_path
  297. *
  298. * @param string $cookiePath
  299. * @param string|null $default
  300. * @return $this
  301. */
  302. public function setCookiePath($cookiePath, $default = null)
  303. {
  304. $cookiePath = (string)$cookiePath;
  305. $validator = $this->_validatorFactory->create(
  306. [],
  307. \Magento\Framework\Session\Config\Validator\CookiePathValidator::class
  308. );
  309. if ($validator->isValid($cookiePath)) {
  310. $this->setOption('session.cookie_path', $cookiePath);
  311. } elseif (null !== $default && $validator->isValid($default)) {
  312. $this->setOption('session.cookie_path', $default);
  313. }
  314. return $this;
  315. }
  316. /**
  317. * Get session.cookie_path
  318. *
  319. * @return string
  320. */
  321. public function getCookiePath()
  322. {
  323. return (string)$this->getOption('session.cookie_path');
  324. }
  325. /**
  326. * Set session.cookie_domain
  327. *
  328. * @param string $cookieDomain
  329. * @param string|null $default
  330. * @return $this
  331. */
  332. public function setCookieDomain($cookieDomain, $default = null)
  333. {
  334. $validator = $this->_validatorFactory->create(
  335. [],
  336. \Magento\Framework\Session\Config\Validator\CookieDomainValidator::class
  337. );
  338. if ($validator->isValid($cookieDomain)) {
  339. $this->setOption('session.cookie_domain', $cookieDomain);
  340. } elseif (null !== $default && $validator->isValid($default)) {
  341. $this->setOption('session.cookie_domain', $default);
  342. }
  343. return $this;
  344. }
  345. /**
  346. * Get session.cookie_domain
  347. *
  348. * @return string
  349. */
  350. public function getCookieDomain()
  351. {
  352. return (string)$this->getOption('session.cookie_domain');
  353. }
  354. /**
  355. * Set session.cookie_secure
  356. *
  357. * @param bool $cookieSecure
  358. * @return $this
  359. */
  360. public function setCookieSecure($cookieSecure)
  361. {
  362. $this->setOption('session.cookie_secure', (bool)$cookieSecure);
  363. return $this;
  364. }
  365. /**
  366. * Get session.cookie_secure
  367. *
  368. * @return bool
  369. * @SuppressWarnings(PHPMD.BooleanGetMethodName)
  370. */
  371. public function getCookieSecure()
  372. {
  373. return (bool)$this->getOption('session.cookie_secure');
  374. }
  375. /**
  376. * Set session.cookie_httponly
  377. *
  378. * @param bool $cookieHttpOnly
  379. * @return $this
  380. */
  381. public function setCookieHttpOnly($cookieHttpOnly)
  382. {
  383. $this->setOption('session.cookie_httponly', (bool)$cookieHttpOnly);
  384. return $this;
  385. }
  386. /**
  387. * Get session.cookie_httponly
  388. *
  389. * @return bool
  390. * @SuppressWarnings(PHPMD.BooleanGetMethodName)
  391. */
  392. public function getCookieHttpOnly()
  393. {
  394. return (bool)$this->getOption('session.cookie_httponly');
  395. }
  396. /**
  397. * Set session.use_cookies
  398. *
  399. * @param bool $useCookies
  400. * @return $this
  401. */
  402. public function setUseCookies($useCookies)
  403. {
  404. $this->setOption('session.use_cookies', (bool)$useCookies);
  405. return $this;
  406. }
  407. /**
  408. * Get session.use_cookies
  409. *
  410. * @return bool
  411. * @SuppressWarnings(PHPMD.BooleanGetMethodName)
  412. */
  413. public function getUseCookies()
  414. {
  415. return (bool)$this->getOption('session.use_cookies');
  416. }
  417. /**
  418. * Retrieve a storage option from a backend configuration store
  419. *
  420. * @param string $option
  421. * @return string|bool
  422. */
  423. protected function getStorageOption($option)
  424. {
  425. $value = ini_get($option);
  426. if (in_array($option, $this->booleanOptions)) {
  427. $value = (bool)$value;
  428. }
  429. return $value;
  430. }
  431. /**
  432. * Fix session option name
  433. *
  434. * @param string $option
  435. * @return string
  436. */
  437. protected function getFixedOptionName($option)
  438. {
  439. $option = strtolower($option);
  440. switch ($option) {
  441. case 'url_rewriter_tags':
  442. $option = 'url_rewriter.tags';
  443. break;
  444. default:
  445. if (strpos($option, 'session.') !== 0) {
  446. $option = 'session.' . $option;
  447. }
  448. break;
  449. }
  450. return $option;
  451. }
  452. /**
  453. * Intercept get*() and set*() methods
  454. *
  455. * Intercepts getters and setters and passes them to getOption() and setOption(),
  456. * respectively.
  457. *
  458. * @param string $method
  459. * @param array $args
  460. * @return mixed
  461. * @throws \BadMethodCallException On non-getter/setter method
  462. */
  463. public function __call($method, $args)
  464. {
  465. $prefix = substr($method, 0, 3);
  466. $option = substr($method, 3);
  467. $key = strtolower(preg_replace('#(?<=[a-z])([A-Z])#', '_\1', $option));
  468. if ($prefix === 'set') {
  469. $value = array_shift($args);
  470. return $this->setOption($key, $value);
  471. } elseif ($prefix === 'get') {
  472. return $this->getOption($key);
  473. } else {
  474. throw new \BadMethodCallException(sprintf('Method "%s" does not exist in %s', $method, get_class($this)));
  475. }
  476. }
  477. }