| Current Path : /var/www/www.indacotrentino.com/www/vendor/laminas/laminas-session/src/Config/ |
| Current File : /var/www/www.indacotrentino.com/www/vendor/laminas/laminas-session/src/Config/SessionConfig.php |
<?php
namespace Laminas\Session\Config;
use Laminas\Session\Exception;
use SessionHandlerInterface;
use function array_merge;
use function array_search;
use function array_shift;
use function class_exists;
use function explode;
use function hash_algos;
use function implode;
use function in_array;
use function ini_get;
use function ini_set;
use function is_a;
use function is_numeric;
use function is_string;
use function ob_get_clean;
use function ob_start;
use function preg_match;
use function preg_split;
use function restore_error_handler;
use function session_set_save_handler;
use function session_start;
use function session_status;
use function session_write_close;
use function set_error_handler;
use function sprintf;
use function str_contains;
use function strtolower;
use function trigger_error;
use function trim;
use const E_USER_DEPRECATED;
use const E_WARNING;
use const INFO_MODULES;
use const PHP_SESSION_ACTIVE;
use const PHP_VERSION_ID;
/**
* Session configuration proxying to session INI options
*/
class SessionConfig extends StandardConfig
{
/**
* @internal
*
* @var callable
*/
public static $phpinfo = 'phpinfo';
/**
* @internal
*
* @var callable
*/
public static $sessionModuleName = 'session_module_name';
/**
* List of known PHP save handlers.
*
* @var null|array
*/
protected $knownSaveHandlers;
/**
* Used with {@link handleError()}; stores PHP error code
*
* @var int
*/
protected $phpErrorCode = false;
/**
* Used with {@link handleError()}; stores PHP error message
*
* @var string
*/
protected $phpErrorMessage = false;
/** @var int Default number of seconds to make session sticky, when rememberMe() is called */
protected $rememberMeSeconds = 1_209_600; // 2 weeks
/**
* Name of the save handler currently in use. This will either be a PHP
* built-in save handler name, or the name of a SessionHandlerInterface
* class being used as a save handler.
*
* @var null|string
*/
protected $saveHandler;
/** @var string session.serialize_handler */
protected $serializeHandler;
/** @var array Valid cache limiters (per session.cache_limiter) */
protected $validCacheLimiters = [
'',
'nocache',
'public',
'private',
'private_no_expire',
];
/** @var array Valid hash bits per character (per session.hash_bits_per_character) */
protected $validHashBitsPerCharacters = [
4,
5,
6,
];
/** @var array Valid sid bits per character (per session.sid_bits_per_character) */
protected $validSidBitsPerCharacters = [
4,
5,
6,
];
/** @var array Valid hash functions (per session.hash_function) */
protected $validHashFunctions;
/**
* Override standard option setting.
*
* Provides an overload for setting the save handler.
*
* {@inheritDoc}
*/
public function setOption($option, $value)
{
switch (strtolower($option)) {
case 'save_handler':
$this->setPhpSaveHandler($value);
return $this;
default:
return parent::setOption($option, $value);
}
}
/**
* Set storage option in backend configuration store
*
* @param string $storageName
* @param mixed $storageValue
* @return SessionConfig
* @throws Exception\InvalidArgumentException
*/
public function setStorageOption($storageName, $storageValue)
{
switch ($storageName) {
case 'remember_me_seconds':
// do nothing; not an INI option
return;
case 'url_rewriter_tags':
$key = 'url_rewriter.tags';
break;
case 'save_handler':
// Save handlers must be treated differently due to changes
// introduced in PHP 7.2. Do not alter running INI setting.
return $this;
default:
$key = 'session.' . $storageName;
break;
}
$iniGet = ini_get($key);
$storageValue = (string) $storageValue;
if (false !== $iniGet && (string) $iniGet === $storageValue) {
return $this;
}
$sessionRequiresRestart = false;
if (session_status() === PHP_SESSION_ACTIVE) {
session_write_close();
$sessionRequiresRestart = true;
}
$result = ini_set($key, $storageValue);
if ($sessionRequiresRestart) {
session_start();
}
if (false === $result) {
throw new Exception\InvalidArgumentException(
"'{$key}' is not a valid sessions-related ini setting."
);
}
return $this;
}
/**
* Retrieve a storage option from a backend configuration store
*
* Used to retrieve default values from a backend configuration store.
*
* @param string $storageOption
* @return mixed
*/
public function getStorageOption($storageOption)
{
return match ($storageOption) {
// No remote storage option; just return the current value
'remember_me_seconds' => $this->rememberMeSeconds,
'url_rewriter_tags' => ini_get('url_rewriter.tags'),
// The following all need a transformation on the retrieved value;
// however they use the same key naming scheme
'use_cookies',
'use_only_cookies',
'use_trans_sid',
'cookie_httponly' => (bool) ini_get('session.' . $storageOption),
'save_handler' => $this->saveHandler ?? $this->sessionModuleName(),
default => ini_get('session.' . $storageOption),
};
}
/**
* Proxy to setPhpSaveHandler()
*
* Prevents calls to `setSaveHandler()` from hitting `setOption()` instead,
* and thus bypassing the logic of `setPhpSaveHandler()`.
*
* @param string $phpSaveHandler
* @return SessionConfig
* @throws Exception\InvalidArgumentException
*/
public function setSaveHandler($phpSaveHandler)
{
return $this->setPhpSaveHandler($phpSaveHandler);
}
/**
* Set session.save_handler
*
* @param string $phpSaveHandler
* @return SessionConfig
* @throws Exception\InvalidArgumentException
*/
public function setPhpSaveHandler($phpSaveHandler)
{
$this->saveHandler = $this->performSaveHandlerUpdate($phpSaveHandler);
$this->options['save_handler'] = $this->saveHandler;
return $this;
}
/**
* Set session.save_path
*
* @param string $savePath
* @return SessionConfig
* @throws Exception\InvalidArgumentException On invalid path.
*/
public function setSavePath($savePath)
{
if ($this->getOption('save_handler') === 'files') {
parent::setSavePath($savePath);
}
$this->savePath = $savePath;
$this->setOption('save_path', $savePath);
return $this;
}
/**
* Set session.serialize_handler
*
* @param string $serializeHandler
* @return SessionConfig
* @throws Exception\InvalidArgumentException
*/
public function setSerializeHandler($serializeHandler)
{
$serializeHandler = (string) $serializeHandler;
set_error_handler([$this, 'handleError']);
ini_set('session.serialize_handler', $serializeHandler);
restore_error_handler();
if ($this->phpErrorCode >= E_WARNING) {
throw new Exception\InvalidArgumentException('Invalid serialize handler specified');
}
$this->serializeHandler = (string) $serializeHandler;
return $this;
}
// session.cache_limiter
/**
* Set cache limiter
*
* @param string $cacheLimiter
* @return SessionConfig
* @throws Exception\InvalidArgumentException
*/
public function setCacheLimiter($cacheLimiter)
{
$cacheLimiter = (string) $cacheLimiter;
if (! in_array($cacheLimiter, $this->validCacheLimiters)) {
throw new Exception\InvalidArgumentException('Invalid cache limiter provided');
}
$this->setOption('cache_limiter', $cacheLimiter);
ini_set('session.cache_limiter', $cacheLimiter);
return $this;
}
/**
* Set session.hash_function
*
* @deprecated removed in PHP 7.1
*
* @param string|int $hashFunction
* @return SessionConfig
* @throws Exception\InvalidArgumentException
*/
public function setHashFunction($hashFunction)
{
if (PHP_VERSION_ID >= 70100) {
trigger_error('session.hash_function is removed starting with PHP 7.1', E_USER_DEPRECATED);
}
$hashFunction = (string) $hashFunction;
$validHashFunctions = $this->getHashFunctions();
if (! in_array($hashFunction, $validHashFunctions, true)) {
throw new Exception\InvalidArgumentException('Invalid hash function provided');
}
$this->setOption('hash_function', $hashFunction);
ini_set('session.hash_function', $hashFunction);
return $this;
}
/**
* Set session.hash_bits_per_character
*
* @deprecated removed in PHP 7.1
*
* @param int $hashBitsPerCharacter
* @return SessionConfig
* @throws Exception\InvalidArgumentException
*/
public function setHashBitsPerCharacter($hashBitsPerCharacter)
{
if (PHP_VERSION_ID >= 70100) {
trigger_error('session.hash_bits_per_character is removed starting with PHP 7.1', E_USER_DEPRECATED);
}
if (
! is_numeric($hashBitsPerCharacter)
|| ! in_array($hashBitsPerCharacter, $this->validHashBitsPerCharacters)
) {
throw new Exception\InvalidArgumentException('Invalid hash bits per character provided');
}
$hashBitsPerCharacter = (int) $hashBitsPerCharacter;
$this->setOption('hash_bits_per_character', $hashBitsPerCharacter);
ini_set('session.hash_bits_per_character', $hashBitsPerCharacter);
return $this;
}
/**
* Set session.sid_bits_per_character
*
* @param int $sidBitsPerCharacter
* @return SessionConfig
* @throws Exception\InvalidArgumentException
*/
public function setSidBitsPerCharacter($sidBitsPerCharacter)
{
if (
! is_numeric($sidBitsPerCharacter)
|| ! in_array($sidBitsPerCharacter, $this->validSidBitsPerCharacters)
) {
throw new Exception\InvalidArgumentException('Invalid sid bits per character provided');
}
$sidBitsPerCharacter = (int) $sidBitsPerCharacter;
$this->setOption('sid_bits_per_character', $sidBitsPerCharacter);
ini_set('session.sid_bits_per_character', (string) $sidBitsPerCharacter);
return $this;
}
/**
* Retrieve list of valid hash functions
*
* @return array
*/
protected function getHashFunctions()
{
if (empty($this->validHashFunctions)) {
/**
* @link http://php.net/manual/en/session.configuration.php#ini.session.hash-function
* "0" and "1" refer to MD5-128 and SHA1-160, respectively, and are
* valid in addition to whatever is reported by hash_algos()
*/
$this->validHashFunctions = array_merge(['0', '1'], hash_algos());
}
return $this->validHashFunctions;
}
/**
* Handle PHP errors
*
* @param int $code
* @param string $message
* @return void
*/
protected function handleError($code, $message)
{
$this->phpErrorCode = $code;
$this->phpErrorMessage = $message;
}
/**
* Determine what save handlers are available.
*
* The only way to get at this information is via phpinfo(), and the output
* of that function varies based on the SAPI.
*
* Strips the handler "user" from the list, as PHP 7.2 does not allow
* setting that as a handler, because it essentially requires you to have
* already set a custom handler via `session_set_save_handler()`. It
* wasn't really valid in prior versions, either; the language simply did
* not complain previously.
*
* @return array
*/
private function locateRegisteredSaveHandlers()
{
if (null !== $this->knownSaveHandlers) {
return $this->knownSaveHandlers;
}
if (! preg_match('#Registered save handlers.*#m', $this->getPhpInfoForModules(), $matches)) {
$this->knownSaveHandlers = [];
return $this->knownSaveHandlers;
}
$content = array_shift($matches);
$handlers = str_contains($content, '</td>')
? $this->parseSaveHandlersFromHtml($content)
: $this->parseSaveHandlersFromPlainText($content);
if (false !== ($index = array_search('user', $handlers, true))) {
unset($handlers[$index]);
}
$this->knownSaveHandlers = $handlers;
return $this->knownSaveHandlers;
}
/**
* Perform a session.save_handler update.
*
* Determines if the save handler represents a PHP built-in
* save handler, and, if so, passes that value to session_module_name
* in order to activate it. The save handler name is then returned.
*
* If it is not, it tests to see if it is a SessionHandlerInterface
* implementation. If the string is a class implementing that interface,
* it creates an instance of it. In such cases, it then calls
* session_set_save_handler to activate it. The class name of the
* handler is returned.
*
* In all other cases, an exception is raised.
*
* @param string|SessionHandlerInterface $phpSaveHandler
* @return string
* @throws Exception\InvalidArgumentException If an error occurs when
* setting a PHP session save handler module.
* @throws Exception\InvalidArgumentException If the $phpSaveHandler
* is a string that does not represent a class implementing
* SessionHandlerInterface.
* @throws Exception\InvalidArgumentException If $phpSaveHandler is
* a non-string value that does not implement SessionHandlerInterface.
*/
private function performSaveHandlerUpdate($phpSaveHandler)
{
if (is_string($phpSaveHandler)) {
$knownHandlers = $this->locateRegisteredSaveHandlers();
if (in_array($phpSaveHandler, $knownHandlers, true)) {
$phpSaveHandler = strtolower($phpSaveHandler);
set_error_handler([$this, 'handleError']);
$this->sessionModuleName($phpSaveHandler);
restore_error_handler();
if ($this->phpErrorCode >= E_WARNING) {
throw new Exception\InvalidArgumentException(sprintf(
'Error setting session save handler module "%s": %s',
$phpSaveHandler,
$this->phpErrorMessage
));
}
return $phpSaveHandler;
}
if (
! class_exists($phpSaveHandler)
|| ! is_a($phpSaveHandler, SessionHandlerInterface::class, true)
) {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid save handler specified ("%s"); must be one of [%s]'
. ' or a class implementing %s',
$phpSaveHandler,
implode(', ', $knownHandlers),
SessionHandlerInterface::class
));
}
$phpSaveHandler = new $phpSaveHandler();
}
if (! $phpSaveHandler instanceof SessionHandlerInterface) {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid save handler specified ("%s"); must implement %s',
$phpSaveHandler::class,
SessionHandlerInterface::class
));
}
session_set_save_handler($phpSaveHandler);
return $phpSaveHandler::class;
}
/**
* Grab module information from phpinfo.
*
* Requires capturing an output buffer, as phpinfo does not have an option
* to return the value as a string.
*
* @return string
*/
private function getPhpInfoForModules()
{
$phpinfo = self::$phpinfo;
ob_start();
$phpinfo(INFO_MODULES);
return ob_get_clean();
}
/**
* Parse a list of PHP session save handlers from HTML.
*
* Format is "<tr><td class="e">Registered save handlers</td><td class="v">{handlers}</td></tr>".
*
* @param string $content
* @return array
*/
private function parseSaveHandlersFromHtml($content)
{
if (! preg_match('#<td class="v">(?P<handlers>[^<]+)</td>#', $content, $matches)) {
return [];
}
$handlers = trim($matches['handlers']);
return preg_split('#\s+#', $handlers);
}
/**
* Parse a list of PHP session save handlers from plain text.
*
* Format is "Registered save handlers => <handlers>".
*
* @param string $content
* @return array
*/
private function parseSaveHandlersFromPlainText($content)
{
[$prefix, $handlers] = explode('=>', $content);
$handlers = trim($handlers);
return preg_split('#\s+#', $handlers);
}
/** @return false|string */
private function sessionModuleName(?string $module = null)
{
$callback = self::$sessionModuleName;
// session_module_name behaves differently when passed an explicit
// `null` than it does when passed no arguments.
if (null !== $module) {
return $callback($module);
}
return $callback();
}
}