3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Session\Config
;
13 use Zend\Session\Exception
;
14 use Zend\Validator\Hostname
as HostnameValidator
;
17 * Standard session configuration
19 class StandardConfig
implements ConfigInterface
36 * session.cookie_lifetime
40 protected $cookieLifetime;
47 protected $cookiePath;
50 * session.cookie_domain
54 protected $cookieDomain;
57 * session.cookie_secure
61 protected $cookieSecure;
64 * session.cookie_httponly
68 protected $cookieHttpOnly;
75 protected $rememberMeSeconds;
82 protected $useCookies;
89 protected $options = array();
92 * Set many options at once
94 * If a setter method exists for the key, that method will be called;
95 * otherwise, a standard option will be set with the value provided via
96 * {@link setOption()}.
98 * @param array|Traversable $options
99 * @return StandardConfig
100 * @throws Exception\InvalidArgumentException
102 public function setOptions($options)
104 if (!is_array($options) && !$options instanceof Traversable
) {
105 throw new Exception\
InvalidArgumentException(sprintf(
106 'Parameter provided to %s must be an array or Traversable',
111 foreach ($options as $key => $value) {
112 $setter = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)));
113 if (method_exists($this, $setter)) {
114 $this->{$setter}($value);
116 $this->setOption($key, $value);
123 * Get all options set
127 public function getOptions()
129 return $this->options
;
133 * Set an individual option
135 * Keys are normalized to lowercase. After setting internally, calls
136 * {@link setStorageOption()} to allow further processing.
139 * @param string $option
140 * @param mixed $value
141 * @return StandardConfig
143 public function setOption($option, $value)
145 $option = strtolower($option);
146 $this->options
[$option] = $value;
147 $this->setStorageOption($option, $value);
152 * Get an individual option
154 * Keys are normalized to lowercase. If the option is not found, attempts
155 * to retrieve it via {@link getStorageOption()}; if a value is returned
156 * from that method, it will be set as the internal value and returned.
158 * Returns null for unfound options
160 * @param string $option
163 public function getOption($option)
165 $option = strtolower($option);
166 if (array_key_exists($option, $this->options
)) {
167 return $this->options
[$option];
170 $value = $this->getStorageOption($option);
171 if (null !== $value) {
172 $this->setOption($option, $value);
180 * Check to see if an internal option has been set for the key provided.
182 * @param string $option
185 public function hasOption($option)
187 $option = strtolower($option);
188 return array_key_exists($option, $this->options
);
192 * Set storage option in backend configuration store
194 * Does nothing in this implementation; others might use it to set things
195 * such as INI settings.
197 * @param string $storageName
198 * @param mixed $storageValue
199 * @return StandardConfig
201 public function setStorageOption($storageName, $storageValue)
207 * Retrieve a storage option from a backend configuration store
209 * Used to retrieve default values from a backend configuration store.
211 * @param string $storageOption
214 public function getStorageOption($storageOption)
220 * Set session.save_path
222 * @param string $savePath
223 * @return StandardConfig
224 * @throws Exception\InvalidArgumentException on invalid path
226 public function setSavePath($savePath)
228 if (!is_dir($savePath)) {
229 throw new Exception\
InvalidArgumentException('Invalid save_path provided; not a directory');
231 if (!is_writable($savePath)) {
232 throw new Exception\
InvalidArgumentException('Invalid save_path provided; not writable');
235 $this->savePath
= $savePath;
236 $this->setStorageOption('save_path', $savePath);
241 * Set session.save_path
243 * @return string|null
245 public function getSavePath()
247 if (null === $this->savePath
) {
248 $this->savePath
= $this->getStorageOption('save_path');
250 return $this->savePath
;
256 * @param string $name
257 * @return StandardConfig
258 * @throws Exception\InvalidArgumentException
260 public function setName($name)
262 $this->name
= (string) $name;
263 if (empty($this->name
)) {
264 throw new Exception\
InvalidArgumentException('Invalid session name; cannot be empty');
266 $this->setStorageOption('name', $this->name
);
273 * @return null|string
275 public function getName()
277 if (null === $this->name
) {
278 $this->name
= $this->getStorageOption('name');
284 * Set session.gc_probability
286 * @param int $gcProbability
287 * @return StandardConfig
288 * @throws Exception\InvalidArgumentException
290 public function setGcProbability($gcProbability)
292 if (!is_numeric($gcProbability)) {
293 throw new Exception\
InvalidArgumentException('Invalid gc_probability; must be numeric');
295 $gcProbability = (int) $gcProbability;
296 if (0 > $gcProbability ||
100 < $gcProbability) {
297 throw new Exception\
InvalidArgumentException('Invalid gc_probability; must be a percentage');
299 $this->setOption('gc_probability', $gcProbability);
300 $this->setStorageOption('gc_probability', $gcProbability);
305 * Get session.gc_probability
309 public function getGcProbability()
311 if (!isset($this->options
['gc_probability'])) {
312 $this->options
['gc_probability'] = $this->getStorageOption('gc_probability');
315 return $this->options
['gc_probability'];
319 * Set session.gc_divisor
321 * @param int $gcDivisor
322 * @return StandardConfig
323 * @throws Exception\InvalidArgumentException
325 public function setGcDivisor($gcDivisor)
327 if (!is_numeric($gcDivisor)) {
328 throw new Exception\
InvalidArgumentException('Invalid gc_divisor; must be numeric');
330 $gcDivisor = (int) $gcDivisor;
331 if (1 > $gcDivisor) {
332 throw new Exception\
InvalidArgumentException('Invalid gc_divisor; must be a positive integer');
334 $this->setOption('gc_divisor', $gcDivisor);
335 $this->setStorageOption('gc_divisor', $gcDivisor);
340 * Get session.gc_divisor
344 public function getGcDivisor()
346 if (!isset($this->options
['gc_divisor'])) {
347 $this->options
['gc_divisor'] = $this->getStorageOption('gc_divisor');
350 return $this->options
['gc_divisor'];
356 * @param int $gcMaxlifetime
357 * @return StandardConfig
358 * @throws Exception\InvalidArgumentException
360 public function setGcMaxlifetime($gcMaxlifetime)
362 if (!is_numeric($gcMaxlifetime)) {
363 throw new Exception\
InvalidArgumentException('Invalid gc_maxlifetime; must be numeric');
366 $gcMaxlifetime = (int) $gcMaxlifetime;
367 if (1 > $gcMaxlifetime) {
368 throw new Exception\
InvalidArgumentException('Invalid gc_maxlifetime; must be a positive integer');
371 $this->setOption('gc_maxlifetime', $gcMaxlifetime);
372 $this->setStorageOption('gc_maxlifetime', $gcMaxlifetime);
377 * Get session.gc_maxlifetime
381 public function getGcMaxlifetime()
383 if (!isset($this->options
['gc_maxlifetime'])) {
384 $this->options
['gc_maxlifetime'] = $this->getStorageOption('gc_maxlifetime');
387 return $this->options
['gc_maxlifetime'];
391 * Set session.cookie_lifetime
393 * @param int $cookieLifetime
394 * @return StandardConfig
395 * @throws Exception\InvalidArgumentException
397 public function setCookieLifetime($cookieLifetime)
399 if (!is_numeric($cookieLifetime)) {
400 throw new Exception\
InvalidArgumentException('Invalid cookie_lifetime; must be numeric');
402 if (0 > $cookieLifetime) {
403 throw new Exception\
InvalidArgumentException(
404 'Invalid cookie_lifetime; must be a positive integer or zero'
408 $this->cookieLifetime
= (int) $cookieLifetime;
409 $this->setStorageOption('cookie_lifetime', $this->cookieLifetime
);
414 * Get session.cookie_lifetime
418 public function getCookieLifetime()
420 if (null === $this->cookieLifetime
) {
421 $this->cookieLifetime
= $this->getStorageOption('cookie_lifetime');
423 return $this->cookieLifetime
;
427 * Set session.cookie_path
429 * @param string $cookiePath
430 * @return StandardConfig
431 * @throws Exception\InvalidArgumentException
433 public function setCookiePath($cookiePath)
435 $cookiePath = (string) $cookiePath;
437 $test = parse_url($cookiePath, PHP_URL_PATH
);
438 if ($test != $cookiePath ||
'/' != $test[0]) {
439 throw new Exception\
InvalidArgumentException('Invalid cookie path');
442 $this->cookiePath
= $cookiePath;
443 $this->setStorageOption('cookie_path', $cookiePath);
448 * Get session.cookie_path
452 public function getCookiePath()
454 if (null === $this->cookiePath
) {
455 $this->cookiePath
= $this->getStorageOption('cookie_path');
457 return $this->cookiePath
;
461 * Set session.cookie_domain
463 * @param string $cookieDomain
464 * @return StandardConfig
465 * @throws Exception\InvalidArgumentException
467 public function setCookieDomain($cookieDomain)
469 if (!is_string($cookieDomain)) {
470 throw new Exception\
InvalidArgumentException('Invalid cookie domain: must be a string');
473 $validator = new HostnameValidator(HostnameValidator
::ALLOW_ALL
);
475 if (!empty($cookieDomain) && !$validator->isValid($cookieDomain)) {
476 throw new Exception\
InvalidArgumentException(
477 'Invalid cookie domain: ' . implode('; ', $validator->getMessages())
481 $this->cookieDomain
= $cookieDomain;
482 $this->setStorageOption('cookie_domain', $cookieDomain);
487 * Get session.cookie_domain
491 public function getCookieDomain()
493 if (null === $this->cookieDomain
) {
494 $this->cookieDomain
= $this->getStorageOption('cookie_domain');
496 return $this->cookieDomain
;
500 * Set session.cookie_secure
502 * @param bool $cookieSecure
503 * @return StandardConfig
505 public function setCookieSecure($cookieSecure)
507 $this->cookieSecure
= (bool) $cookieSecure;
508 $this->setStorageOption('cookie_secure', $this->cookieSecure
);
513 * Get session.cookie_secure
517 public function getCookieSecure()
519 if (null === $this->cookieSecure
) {
520 $this->cookieSecure
= $this->getStorageOption('cookie_secure');
522 return $this->cookieSecure
;
526 * Set session.cookie_httponly
528 * case sensitive method lookups in setOptions means this method has an
531 * @param bool $cookieHttpOnly
532 * @return StandardConfig
534 public function setCookieHttpOnly($cookieHttpOnly)
536 $this->cookieHttpOnly
= (bool) $cookieHttpOnly;
537 $this->setStorageOption('cookie_httponly', $this->cookieHttpOnly
);
542 * Get session.cookie_httponly
546 public function getCookieHttpOnly()
548 if (null === $this->cookieHttpOnly
) {
549 $this->cookieHttpOnly
= $this->getStorageOption('cookie_httponly');
551 return $this->cookieHttpOnly
;
555 * Set session.use_cookies
557 * @param bool $useCookies
558 * @return StandardConfig
560 public function setUseCookies($useCookies)
562 $this->useCookies
= (bool) $useCookies;
563 $this->setStorageOption('use_cookies', $this->useCookies
);
568 * Get session.use_cookies
572 public function getUseCookies()
574 if (null === $this->useCookies
) {
575 $this->useCookies
= $this->getStorageOption('use_cookies');
577 return $this->useCookies
;
581 * Set session.entropy_file
583 * @param string $entropyFile
584 * @return StandardConfig
585 * @throws Exception\InvalidArgumentException
587 public function setEntropyFile($entropyFile)
589 if (!is_readable($entropyFile)) {
590 throw new Exception\
InvalidArgumentException(sprintf(
591 "Invalid entropy_file provided: '%s'; doesn't exist or not readable",
596 $this->setOption('entropy_file', $entropyFile);
597 $this->setStorageOption('entropy_file', $entropyFile);
602 * Get session.entropy_file
606 public function getEntropyFile()
608 if (!isset($this->options
['entropy_file'])) {
609 $this->options
['entropy_file'] = $this->getStorageOption('entropy_file');
612 return $this->options
['entropy_file'];
616 * set session.entropy_length
618 * @param int $entropyLength
619 * @return StandardConfig
620 * @throws Exception\InvalidArgumentException
622 public function setEntropyLength($entropyLength)
624 if (!is_numeric($entropyLength)) {
625 throw new Exception\
InvalidArgumentException('Invalid entropy_length; must be numeric');
627 if (0 > $entropyLength) {
628 throw new Exception\
InvalidArgumentException('Invalid entropy_length; must be a positive integer or zero');
631 $this->setOption('entropy_length', $entropyLength);
632 $this->setStorageOption('entropy_length', $entropyLength);
637 * Get session.entropy_length
641 public function getEntropyLength()
643 if (!isset($this->options
['entropy_length'])) {
644 $this->options
['entropy_length'] = $this->getStorageOption('entropy_length');
647 return $this->options
['entropy_length'];
651 * Set session.cache_expire
653 * @param int $cacheExpire
654 * @return StandardConfig
655 * @throws Exception\InvalidArgumentException
657 public function setCacheExpire($cacheExpire)
659 if (!is_numeric($cacheExpire)) {
660 throw new Exception\
InvalidArgumentException('Invalid cache_expire; must be numeric');
663 $cacheExpire = (int) $cacheExpire;
664 if (1 > $cacheExpire) {
665 throw new Exception\
InvalidArgumentException('Invalid cache_expire; must be a positive integer');
668 $this->setOption('cache_expire', $cacheExpire);
669 $this->setStorageOption('cache_expire', $cacheExpire);
674 * Get session.cache_expire
678 public function getCacheExpire()
680 if (!isset($this->options
['cache_expire'])) {
681 $this->options
['cache_expire'] = $this->getStorageOption('cache_expire');
684 return $this->options
['cache_expire'];
688 * Set session.hash_bits_per_character
690 * @param int $hashBitsPerCharacter
691 * @return StandardConfig
692 * @throws Exception\InvalidArgumentException
694 public function setHashBitsPerCharacter($hashBitsPerCharacter)
696 if (!is_numeric($hashBitsPerCharacter)) {
697 throw new Exception\
InvalidArgumentException('Invalid hash bits per character provided');
699 $hashBitsPerCharacter = (int) $hashBitsPerCharacter;
700 $this->setOption('hash_bits_per_character', $hashBitsPerCharacter);
701 $this->setStorageOption('hash_bits_per_character', $hashBitsPerCharacter);
706 * Get session.hash_bits_per_character
710 public function getHashBitsPerCharacter()
712 if (!isset($this->options
['hash_bits_per_character'])) {
713 $this->options
['hash_bits_per_character'] = $this->getStorageOption('hash_bits_per_character');
716 return $this->options
['hash_bits_per_character'];
720 * Set remember_me_seconds
722 * @param int $rememberMeSeconds
723 * @return StandardConfig
724 * @throws Exception\InvalidArgumentException
726 public function setRememberMeSeconds($rememberMeSeconds)
728 if (!is_numeric($rememberMeSeconds)) {
729 throw new Exception\
InvalidArgumentException('Invalid remember_me_seconds; must be numeric');
732 $rememberMeSeconds = (int) $rememberMeSeconds;
733 if (1 > $rememberMeSeconds) {
734 throw new Exception\
InvalidArgumentException('Invalid remember_me_seconds; must be a positive integer');
737 $this->rememberMeSeconds
= $rememberMeSeconds;
738 $this->setStorageOption('remember_me_seconds', $rememberMeSeconds);
743 * Get remember_me_seconds
747 public function getRememberMeSeconds()
749 if (null === $this->rememberMeSeconds
) {
750 $this->rememberMeSeconds
= $this->getStorageOption('remember_me_seconds');
752 return $this->rememberMeSeconds
;
756 * Cast configuration to an array
760 public function toArray()
763 'cookie_domain' => $this->getCookieDomain(),
764 'cookie_httponly' => $this->getCookieHttpOnly(),
765 'cookie_lifetime' => $this->getCookieLifetime(),
766 'cookie_path' => $this->getCookiePath(),
767 'cookie_secure' => $this->getCookieSecure(),
768 'name' => $this->getName(),
769 'remember_me_seconds' => $this->getRememberMeSeconds(),
770 'save_path' => $this->getSavePath(),
771 'use_cookies' => $this->getUseCookies(),
773 return array_merge($this->options
, $extraOpts);
777 * Intercept get*() and set*() methods
779 * Intercepts getters and setters and passes them to getOption() and setOption(),
782 * @param string $method
785 * @throws Exception\BadMethodCallException on non-getter/setter method
787 public function __call($method, $args)
789 $prefix = substr($method, 0, 3);
790 $option = substr($method, 3);
791 $key = strtolower(preg_replace('#(?<=[a-z])([A-Z])#', '_\1', $option));
793 if ($prefix === 'set') {
794 $value = array_shift($args);
795 return $this->setOption($key, $value);
796 } elseif ($prefix === 'get') {
797 return $this->getOption($key);
799 throw new Exception\
BadMethodCallException(sprintf(
800 'Method "%s" does not exist in %s',