diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 3f44c1c2..9fe0b675 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -241,16 +241,9 @@
-
-
-
-
-
-
-
@@ -445,24 +438,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -815,6 +794,7 @@
+
@@ -879,6 +859,9 @@
+
+
+
@@ -927,21 +910,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/SessionManager.php b/src/SessionManager.php
index 9af5606b..1fbfe5c8 100644
--- a/src/SessionManager.php
+++ b/src/SessionManager.php
@@ -6,15 +6,20 @@
use Laminas\EventManager\Event;
use Laminas\EventManager\EventManagerInterface;
+use Laminas\Session\Validator\Environment;
+use Laminas\Session\Validator\ValidatorInterface;
use Traversable;
use function array_key_exists;
use function array_merge;
+use function assert;
use function headers_sent;
use function is_array;
+use function is_string;
use function iterator_to_array;
use function preg_match;
use function register_shutdown_function;
+use function serialize;
use function session_destroy;
use function session_id;
use function session_name;
@@ -24,6 +29,7 @@
use function session_status;
use function session_write_close;
use function setcookie;
+use function unserialize;
use const PHP_SESSION_ACTIVE;
@@ -60,6 +66,8 @@ class SessionManager extends AbstractManager
/** @var EventManagerInterface Validation chain to determine if session is valid */
protected $validatorChain;
+ protected array $options = [];
+
/**
* Constructor
*
@@ -77,6 +85,8 @@ public function __construct(
$validators = array_merge($this->defaultValidators, $validators);
}
+ $this->options = $options;
+
parent::__construct($config, $storage, $saveHandler, $validators);
register_shutdown_function([$this, 'writeClose']);
}
@@ -160,16 +170,32 @@ public function start($preserveStorage = false)
*/
protected function initializeValidatorChain()
{
- $validatorChain = $this->getValidatorChain();
- $validatorValues = $this->getStorage()->getMetadata('_VALID');
-
- foreach ($this->validators as $validator) {
- // Ignore validators which are already present in Storage
- if (is_array($validatorValues) && array_key_exists($validator, $validatorValues)) {
+ /** @var array $storage */
+ $storage = $this->getStorage()->getMetadata();
+
+ /**
+ * @var class-string $validatorName
+ */
+ foreach ($this->validators as $validatorName) {
+ $validatorValues = $this->getStorage()->getMetadata('_VALID');
+ if (is_array($validatorValues) && array_key_exists($validatorName, $validatorValues)) {
continue;
}
- $validator = new $validator(null);
+ if (isset($storage['environment'])) {
+ assert(is_string($storage['environment']));
+ /** @var Environment $initialEnvironment */
+ $initialEnvironment = unserialize($storage['environment']);
+ } else {
+ $initialEnvironment = Environment::fromGlobals($_SERVER);
+ $this->getStorage()->setMetadata('environment', serialize($initialEnvironment));
+ }
+
+ $currentEnvironment = Environment::fromGlobals($_SERVER);
+
+ $validatorChain = $this->getValidatorChain();
+ $validator = new $validatorName($initialEnvironment, $currentEnvironment, $this->options);
+
$validatorChain->attach('session.validate', [$validator, 'isValid']);
}
}
@@ -399,8 +425,7 @@ public function getValidatorChain()
public function isValid()
{
$validator = $this->getValidatorChain();
-
- $event = new Event();
+ $event = new Event();
$event->setName('session.validate');
$event->setTarget($this);
$event->setParams($this);
diff --git a/src/Validator/Environment.php b/src/Validator/Environment.php
new file mode 100644
index 00000000..a1d15552
--- /dev/null
+++ b/src/Validator/Environment.php
@@ -0,0 +1,38 @@
+
- */
-class HttpUserAgent implements ValidatorInterface
+final class HttpUserAgent implements ValidatorInterface
{
- /**
- * Internal data
- *
- * @var string
- */
- protected $data;
-
/**
* Constructor
* get the current user agent and store it in the session as 'valid data'
- *
- * @param string|null $data
*/
- public function __construct($data = null)
- {
- if ($data === null || $data === '') {
- $data = $_SERVER['HTTP_USER_AGENT'] ?? null;
- }
- $this->data = $data;
+ public function __construct(
+ public readonly Environment $initial,
+ public readonly Environment $current,
+ array $option = []
+ ) {
}
/**
@@ -36,17 +23,7 @@ public function __construct($data = null)
*/
public function isValid(): bool
{
- $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? null;
-
- return $userAgent === $this->getData();
- }
-
- /**
- * Retrieve token for validating call
- */
- public function getData(): mixed
- {
- return $this->data;
+ return $this->initial->userAgent === $this->current->userAgent;
}
/**
diff --git a/src/Validator/Id.php b/src/Validator/Id.php
index 92b917a9..4232cb6a 100644
--- a/src/Validator/Id.php
+++ b/src/Validator/Id.php
@@ -7,7 +7,6 @@
use function ini_get;
use function is_numeric;
use function preg_match;
-use function session_id;
use function trigger_error;
use const E_USER_DEPRECATED;
@@ -15,8 +14,6 @@
/**
* session_id validator
- *
- * @implements ValidatorInterface
*/
final class Id implements ValidatorInterface
{
@@ -26,13 +23,11 @@ final class Id implements ValidatorInterface
* Allows passing the current session_id; if none provided, uses the PHP
* session_id() function to retrieve it.
*/
- public function __construct(protected ?string $id = null)
- {
- if ($id === null || $id === '') {
- $id = session_id();
- }
-
- $this->id = $id;
+ public function __construct(
+ public readonly Environment $initial,
+ public readonly Environment $current,
+ array $options = []
+ ) {
}
/**
@@ -42,9 +37,7 @@ public function __construct(protected ?string $id = null)
*/
public function isValid(): bool
{
- $id = $this->id;
-
- if ($id === null) {
+ if ($this->current->sessionId === null) {
return false;
}
@@ -64,15 +57,7 @@ public function isValid(): bool
default => '#^[0-9a-v]*$#',
};
- return (bool) preg_match($pattern, $id);
- }
-
- /**
- * Retrieve token for validating call (session_id)
- */
- public function getData(): ?string
- {
- return $this->id;
+ return (bool) preg_match($pattern, $this->current->sessionId);
}
/**
diff --git a/src/Validator/RemoteAddr.php b/src/Validator/RemoteAddr.php
index 0fb35583..999acb6b 100644
--- a/src/Validator/RemoteAddr.php
+++ b/src/Validator/RemoteAddr.php
@@ -9,13 +9,8 @@
use function array_diff;
use function array_map;
use function array_pop;
-use function assert;
use function explode;
use function in_array;
-use function is_string;
-use function str_replace;
-use function strpos;
-use function strtoupper;
/**
* @psalm-type OptionsArgument = array{
@@ -23,34 +18,11 @@
* trusted_proxies?: array,
* proxy_header?: non-empty-string,
* }
- * @implements SessionValidator
*/
final class RemoteAddr implements SessionValidator
{
- /**
- * Internal data.
- */
- private ?string $data;
-
- /**
- * Whether to use proxy addresses or not.
- *
- * As default this setting is disabled - IP address is mostly needed to increase
- * security. HTTP_* are not reliable since can easily be spoofed. It can be enabled
- * just for more flexibility, but if user uses proxy to connect to trusted services
- * it's his/her own risk, only reliable field for IP address is $_SERVER['REMOTE_ADDR'].
- */
- private bool $useProxy;
-
- /**
- * List of trusted proxy IP addresses
- */
- private array $trustedProxies;
-
- /**
- * HTTP header to introspect for proxies
- */
- private string $proxyHeader;
+ public ?string $initialData = null;
+ public ?string $currentData = null;
/**
* Constructor
@@ -58,19 +30,18 @@ final class RemoteAddr implements SessionValidator
*
* @param OptionsArgument $options
*/
- public function __construct(?string $data = null, array $options = [])
- {
- $proxyHeader = $options['proxy_header'] ?? 'X_FORWARDED_FOR';
-
- $this->useProxy = isset($options['use_proxy']) && $options['use_proxy'];
- $this->trustedProxies = $options['trusted_proxies'] ?? [];
- $this->proxyHeader = self::normalizeProxyHeader($proxyHeader);
-
- if ($data === null || $data === '') {
- $data = $this->getIpAddress();
+ public function __construct(
+ public readonly Environment $initial,
+ public readonly Environment $current,
+ array $options = []
+ ) {
+ if (isset($options['use_proxy']) && $options['use_proxy'] === true) {
+ $this->initialData = $this->getIpAddress($this->initial, $options);
+ $this->currentData = $this->getIpAddress($this->current, $options);
+ } else {
+ $this->initialData = $this->initial->remoteAddr;
+ $this->currentData = $this->current->remoteAddr;
}
-
- $this->data = $data;
}
/**
@@ -79,63 +50,59 @@ public function __construct(?string $data = null, array $options = [])
*/
public function isValid(): bool
{
- return $this->getIpAddress() === $this->getData();
- }
-
- /**
- * Checks proxy handling setting.
- */
- public function getUseProxy(): bool
- {
- return $this->useProxy;
+ return $this->initialData === $this->currentData;
}
/**
* Returns client IP address.
+ *
+ * @param OptionsArgument $options
*/
- private function getIpAddress(): string
+ public static function getIpAddress(Environment $initial, array $options = []): ?string
{
- $ip = $this->getIpAddressFromProxy();
+ $ip = self::getIpAddressFromProxy($initial, $options);
- if (false !== $ip) {
+ if ($ip !== false) {
return $ip;
}
- // direct IP address
- if (isset($_SERVER['REMOTE_ADDR'])) {
- return $_SERVER['REMOTE_ADDR'];
+ if ($initial->remoteAddr !== null) {
+ return $initial->remoteAddr;
}
- return '';
+ return null;
}
/**
* Attempt to get the IP address for a proxied client
*
* @see http://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded-10#section-5.2
+ *
+ * @param OptionsArgument $options
*/
- private function getIpAddressFromProxy(): string|false
+ private static function getIpAddressFromProxy(Environment $initial, array $options = []): string|false
{
+ $trustedProxies = $options['trusted_proxies'] ?? [];
+
if (
- ! $this->useProxy
- || (isset($_SERVER['REMOTE_ADDR']) && ! in_array($_SERVER['REMOTE_ADDR'], $this->trustedProxies))
+ ! (isset($options['use_proxy']) && $options['use_proxy'])
+ || ($initial->remoteAddr !== null && ! in_array($initial->remoteAddr, $trustedProxies))
) {
return false;
}
- $header = $this->proxyHeader;
+ $proxyHeader = $initial->forwardedFor;
- if (! isset($_SERVER[$header]) || '' === $_SERVER[$header]) {
+ if ($proxyHeader === null || $proxyHeader === '') {
return false;
}
// Extract IPs
- assert(is_string($_SERVER[$header]));
- $ips = explode(',', $_SERVER[$header]);
+ $ips = explode(',', $proxyHeader);
// trim, so we can compare against trusted proxies properly
$ips = array_map('trim', $ips);
// remove trusted proxy IPs
- $ips = array_diff($ips, $this->trustedProxies);
+ $ips = array_diff($ips, $trustedProxies);
// Any left?
if (empty($ips)) {
return false;
@@ -149,30 +116,6 @@ private function getIpAddressFromProxy(): string|false
return array_pop($ips);
}
- /**
- * Normalize a header string
- *
- * Normalizes a header string to a format that is compatible with
- * $_SERVER
- */
- protected static function normalizeProxyHeader(string $header): string
- {
- $header = strtoupper($header);
- $header = str_replace('-', '_', $header);
- if (0 !== strpos($header, 'HTTP_')) {
- $header = 'HTTP_' . $header;
- }
- return $header;
- }
-
- /**
- * Retrieve token for validating call
- */
- public function getData(): ?string
- {
- return $this->data;
- }
-
/**
* Return validator name
*/
diff --git a/src/Validator/ValidatorInterface.php b/src/Validator/ValidatorInterface.php
index 3c5863d9..cf08e264 100644
--- a/src/Validator/ValidatorInterface.php
+++ b/src/Validator/ValidatorInterface.php
@@ -7,10 +7,13 @@
/**
* Session validator interface
*
- * @template T
+ * @psalm-import-type OptionsArgument from RemoteAddr
*/
interface ValidatorInterface
{
+ /** @param OptionsArgument $options */
+ public function __construct(Environment $initial, Environment $current, array $options = []);
+
/**
* This method will be called at the beginning of
* every session to determine if the current environment matches
@@ -18,13 +21,6 @@ interface ValidatorInterface
*/
public function isValid(): bool;
- /**
- * Get data from validator to be used for validation comparisons
- *
- * @return T
- */
- public function getData(): mixed;
-
/**
* Get validator name for use with storing validators between requests
*/
diff --git a/src/ValidatorChain.php b/src/ValidatorChain.php
index 8c00e3c9..03a41d69 100644
--- a/src/ValidatorChain.php
+++ b/src/ValidatorChain.php
@@ -17,12 +17,6 @@ class ValidatorChain extends EventManager
public function __construct(protected StorageInterface $storage)
{
parent::__construct();
- $validators = $storage->getMetadata('_VALID');
- if ($validators) {
- foreach ($validators as $validator => $data) {
- $this->attachValidator('session.validate', [new $validator($data), 'isValid'], 1);
- }
- }
}
/**
@@ -69,11 +63,9 @@ private function attachValidator($event, $callback, $priority)
array_unshift($callback, $test);
}
if ($context instanceof ValidatorInterface) {
- $data = $context->getData();
$name = $context->getName();
- $this->getStorage()->setMetadata('_VALID', [$name => $data]);
+ $this->getStorage()->setMetadata('_VALID', [$name]);
}
-
return parent::attach($event, $callback, $priority);
}
}
diff --git a/test/Service/SessionManagerFactoryTest.php b/test/Service/SessionManagerFactoryTest.php
index a8df7447..affc5bd1 100644
--- a/test/Service/SessionManagerFactoryTest.php
+++ b/test/Service/SessionManagerFactoryTest.php
@@ -184,9 +184,10 @@ public function testFactoryDoesNotAttachValidatorTwoTimes(): void
$storage->setMetadata(
'_VALID',
[
- Validator\RemoteAddr::class => '1.2.3.4',
+ Validator\RemoteAddr::class,
]
);
+
$this->services->setService(StorageInterface::class, $storage);
$this->services->setService(
'config',
@@ -212,7 +213,6 @@ public function testFactoryDoesNotAttachValidatorTwoTimes(): void
$chain = $manager->getValidatorChain();
self::assertInstanceOf(EventManager::class, $chain);
-
$listeners = iterator_to_array($this->getListenersForEvent('session.validate', $chain));
self::assertCount(2, $listeners);
diff --git a/test/SessionManagerTest.php b/test/SessionManagerTest.php
index d788cbd6..aad3385f 100644
--- a/test/SessionManagerTest.php
+++ b/test/SessionManagerTest.php
@@ -14,15 +14,18 @@
use Laminas\Session\Storage\ArrayStorage;
use Laminas\Session\Storage\SessionArrayStorage;
use Laminas\Session\Storage\SessionStorage;
+use Laminas\Session\Validator\Environment;
use Laminas\Session\Validator\Id;
use Laminas\Session\Validator\RemoteAddr;
use LaminasTest\Session\TestAsset\Php81CompatibleStorageInterface;
+use LaminasTest\Session\TestAsset\TestFailingValidator;
use PHPUnit\Framework\Attributes\IgnoreDeprecations;
use PHPUnit\Framework\Attributes\RunInSeparateProcess;
use PHPUnit\Framework\TestCase;
use Traversable;
use function array_merge;
+use function assert;
use function extension_loaded;
use function headers_sent;
use function ini_get;
@@ -38,6 +41,7 @@
use function set_error_handler;
use function stristr;
use function uniqid;
+use function unserialize;
use function var_export;
use function xdebug_get_headers;
@@ -712,17 +716,23 @@ public function testStartingSessionThatFailsAValidatorShouldRaiseException(): vo
{
$this->manager = new SessionManager();
$chain = $this->manager->getValidatorChain();
- $chain->attach('session.validate', [new TestAsset\TestFailingValidator(), 'isValid']);
+ $chain->attach('session.validate', [
+ new TestFailingValidator(
+ Environment::fromGlobals($_SERVER),
+ Environment::fromGlobals($_SERVER)
+ ),
+ 'isValid',
+ ]);
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('failed');
$this->manager->start();
}
#[RunInSeparateProcess]
+ #[IgnoreDeprecations]
public function testResumeSessionThatFailsAValidatorShouldRaiseException(): void
{
- $this->manager = new SessionManager();
- $this->manager->setSaveHandler(new TestAsset\TestSaveHandlerWithValidator());
+ $this->manager = new SessionManager(validators: [TestFailingValidator::class]);
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('failed');
$this->manager->start();
@@ -774,16 +784,25 @@ public function testProducedSessionManagerWillNotReplaceSessionSuperGlobalValues
public function testValidatorChainSessionMetadataIsPreserved(): void
{
$this->manager = new SessionManager();
- $this->manager->getValidatorChain()
- ->attach('session.validate', [new RemoteAddr(), 'isValid']);
-
self::assertFalse($this->manager->sessionExists());
-
$this->manager->start();
+ $environment = unserialize((string) $this->manager->getStorage()->getMetadata('environment'));
+ assert($environment instanceof Environment);
+ $this->manager->getValidatorChain()
+ ->attach('session.validate', [
+ new RemoteAddr(
+ $environment,
+ Environment::fromGlobals($_SERVER)
+ ),
+ 'isValid',
+ ]);
self::assertIsArray($_SESSION['__Laminas']['_VALID']);
- self::assertArrayHasKey(RemoteAddr::class, $_SESSION['__Laminas']['_VALID']);
- self::assertEquals('', $_SESSION['__Laminas']['_VALID'][RemoteAddr::class]);
+ self::assertIsString($_SESSION['__Laminas']['_VALID'][0]);
+ self::assertEquals(
+ Environment::fromGlobals($_SERVER),
+ unserialize((string) $_SESSION['__Laminas']['environment'])
+ );
}
#[RunInSeparateProcess]
@@ -791,7 +810,13 @@ public function testRemoteAddressValidationWillFailOnInvalidAddress(): void
{
$this->manager = new SessionManager();
$this->manager->getValidatorChain()
- ->attach('session.validate', [new RemoteAddr('123.123.123.123'), 'isValid']);
+ ->attach('session.validate', [
+ new RemoteAddr(
+ Environment::fromGlobals($_SERVER),
+ new Environment(remoteAddr: '123.123.123.123')
+ ),
+ 'isValid',
+ ]);
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Session validation failed');
@@ -806,7 +831,7 @@ public function testRemoteAddressValidationWillSucceedWithValidPreSetData(): voi
$_SESSION = [
'__Laminas' => [
'_VALID' => [
- RemoteAddr::class => '',
+ RemoteAddr::class,
],
],
];
@@ -816,30 +841,19 @@ public function testRemoteAddressValidationWillSucceedWithValidPreSetData(): voi
self::assertTrue($this->manager->isValid());
}
- #[RunInSeparateProcess]
- public function testRemoteAddressValidationWillFailWithInvalidPreSetData(): void
- {
- $this->manager = new SessionManager();
- $_SESSION = [
- '__Laminas' => [
- '_VALID' => [
- RemoteAddr::class => '123.123.123.123',
- ],
- ],
- ];
-
- $this->expectException(RuntimeException::class);
- $this->expectExceptionMessage('Session validation failed');
- $this->manager->start();
- }
-
#[RunInSeparateProcess]
#[IgnoreDeprecations]
public function testIdValidationWillFailOnInvalidData(): void
{
$this->manager = new SessionManager();
$this->manager->getValidatorChain()
- ->attach('session.validate', [new Id('invalid-value'), 'isValid']);
+ ->attach('session.validate', [
+ new Id(
+ Environment::fromGlobals($_SERVER),
+ new Environment(sessionId: 'invalid_value')
+ ),
+ 'isValid',
+ ]);
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Session validation failed');
diff --git a/test/TestAsset/TestFailingValidator.php b/test/TestAsset/TestFailingValidator.php
index 60122ecd..9a81ec6b 100644
--- a/test/TestAsset/TestFailingValidator.php
+++ b/test/TestAsset/TestFailingValidator.php
@@ -4,18 +4,16 @@
namespace LaminasTest\Session\TestAsset;
+use Laminas\Session\Validator\Environment;
use Laminas\Session\Validator\ValidatorInterface;
-/**
- * @implements ValidatorInterface
- */
final class TestFailingValidator implements ValidatorInterface
{
- public function getData(): mixed
+ public function __construct(Environment $initial, Environment $current, array $options = [])
{
- return false;
}
+ public ?Environment $current = null;
public function getName(): string
{
return self::class;
@@ -23,6 +21,6 @@ public function getName(): string
public function isValid(): bool
{
- return $this->getData();
+ return false;
}
}
diff --git a/test/TestAsset/TestSaveHandlerWithValidator.php b/test/TestAsset/TestSaveHandlerWithValidator.php
deleted file mode 100644
index 880b33d3..00000000
--- a/test/TestAsset/TestSaveHandlerWithValidator.php
+++ /dev/null
@@ -1,63 +0,0 @@
-getData());
self::assertTrue($validator->isValid());
}
@@ -23,16 +25,14 @@ public function testIsValidWhenNoUserAgentIsSet(): void
{
// technically not needed in CLI
unset($_SERVER['HTTP_USER_AGENT']);
+ $validator = new HttpUserAgent(new Environment(userAgent: null), Environment::fromGlobals($_SERVER));
- $validator = new HttpUserAgent();
-
- self::assertNull($validator->getData());
self::assertTrue($validator->isValid());
}
public function testGetNameReturnsClassName(): void
{
- $validator = new HttpUserAgent();
+ $validator = new HttpUserAgent(new Environment(userAgent: null), Environment::fromGlobals($_SERVER));
self::assertSame(HttpUserAgent::class, $validator->getName());
}
diff --git a/test/Validator/IdTest.php b/test/Validator/IdTest.php
index 9cf85721..8e300958 100644
--- a/test/Validator/IdTest.php
+++ b/test/Validator/IdTest.php
@@ -5,6 +5,7 @@
namespace LaminasTest\Session\Validator;
+use Laminas\Session\Validator\Environment;
use Laminas\Session\Validator\Id;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\IgnoreDeprecations;
@@ -39,17 +40,10 @@ public function testIsValidPhp71(int $bitsPerCharacter, string $id, bool $isVali
{
ini_set('session.sid_bits_per_character', $bitsPerCharacter);
- $validator = new Id($id);
+ $validator = new Id(Environment::fromGlobals($_SERVER), new Environment(sessionId: $id));
self::assertSame($isValid, $validator->isValid());
}
- public function testConstructorSetId(): void
- {
- $id = new Id('1234');
-
- self::assertSame('1234', $id->getData());
- }
-
/**
* @runInSeparateProcess
*/
@@ -57,15 +51,14 @@ public function testInitializedWithSessionIdWhenIdIsNotPassed(): void
{
session_start();
$sessionId = session_id();
+ $id = new Id(Environment::fromGlobals($_SERVER), Environment::fromGlobals($_SERVER));
- $id = new Id();
-
- self::assertSame($sessionId, $id->getData());
+ self::assertSame($sessionId, $id->initial->sessionId);
}
public function testValidatorName(): void
{
- $id = new Id();
+ $id = new Id(Environment::fromGlobals($_SERVER), Environment::fromGlobals($_SERVER));
self::assertSame(Id::class, $id->getName());
}
diff --git a/test/Validator/RemoteAddrTest.php b/test/Validator/RemoteAddrTest.php
index c2ef3388..40afc590 100644
--- a/test/Validator/RemoteAddrTest.php
+++ b/test/Validator/RemoteAddrTest.php
@@ -4,6 +4,7 @@
namespace LaminasTest\Session\Validator;
+use Laminas\Session\Validator\Environment;
use Laminas\Session\Validator\RemoteAddr;
use PHPUnit\Framework\TestCase;
@@ -12,14 +13,7 @@
*/
class RemoteAddrTest extends TestCase
{
- protected array $backup;
-
- protected RemoteAddr $defaultRemoteAddr;
-
- protected function setUp(): void
- {
- $this->defaultRemoteAddr = new RemoteAddr();
- }
+ protected array $backup = [];
protected function backup(): void
{
@@ -36,23 +30,13 @@ protected function restore(): void
$_SERVER = $this->backup;
}
- public function testGetData(): void
- {
- $validator = new RemoteAddr('0.1.2.3');
- self::assertEquals('0.1.2.3', $validator->getData());
- }
-
- public function testDefaultUseProxy(): void
- {
- self::assertFalse($this->defaultRemoteAddr->getUseProxy());
- }
-
public function testRemoteAddrWithoutProxy(): void
{
$this->backup();
$_SERVER['REMOTE_ADDR'] = '0.1.2.3';
- $validator = new RemoteAddr();
- self::assertEquals('0.1.2.3', $validator->getData());
+ $validator =
+ new RemoteAddr(Environment::fromGlobals($_SERVER), Environment::fromGlobals($_SERVER));
+ self::assertEquals('0.1.2.3', $validator->current->remoteAddr);
$this->restore();
}
@@ -60,8 +44,8 @@ public function testIsValid(): void
{
$this->backup();
$_SERVER['REMOTE_ADDR'] = '0.1.2.3';
- $validator = new RemoteAddr();
- $_SERVER['REMOTE_ADDR'] = '1.1.2.3';
+ $validator =
+ new RemoteAddr(new Environment(remoteAddr: '0.1.1.3'), Environment::fromGlobals($_SERVER));
self::assertFalse($validator->isValid());
$this->restore();
}
@@ -71,8 +55,11 @@ public function testIgnoreProxyByDefault(): void
$this->backup();
$_SERVER['REMOTE_ADDR'] = '0.1.2.3';
$_SERVER['HTTP_CLIENT_IP'] = '1.1.2.3';
- $validator = new RemoteAddr();
- self::assertEquals('0.1.2.3', $validator->getData());
+ $validator = new RemoteAddr(
+ Environment::fromGlobals($_SERVER),
+ Environment::fromGlobals($_SERVER)
+ );
+ self::assertEquals('0.1.2.3', $validator->current->remoteAddr);
$this->restore();
}
@@ -85,8 +72,13 @@ public function testHttpXForwardedFor(): void
'use_proxy' => true,
'trusted_proxies' => ['0.1.2.3'],
];
- $validator = new RemoteAddr(null, $options);
- self::assertEquals('1.1.2.3', $validator->getData());
+
+ $validator = new RemoteAddr(
+ Environment::fromGlobals($_SERVER),
+ Environment::fromGlobals($_SERVER),
+ $options
+ );
+ self::assertEquals('1.1.2.3', $validator->currentData);
$this->restore();
}
@@ -102,8 +94,12 @@ public function testHttpClientIp(): void
'trusted_proxies' => ['0.1.2.3'],
];
- $validator = new RemoteAddr(null, $options);
- self::assertEquals('2.1.2.3', $validator->getData());
+ $validator = new RemoteAddr(
+ Environment::fromGlobals($_SERVER),
+ Environment::fromGlobals($_SERVER),
+ $options
+ );
+ self::assertEquals('2.1.2.3', $validator->currentData);
$this->restore();
}
@@ -118,8 +114,13 @@ public function testUsesRightMostAddressWhenMultipleHttpXForwardedForAddressesPr
'trusted_proxies' => ['0.1.2.3'],
];
- $validator = new RemoteAddr(null, $options);
- self::assertEquals('1.1.2.3', $validator->getData());
+ $validator = new RemoteAddr(
+ Environment::fromGlobals($_SERVER),
+ Environment::fromGlobals($_SERVER),
+ $options
+ );
+
+ self::assertEquals('1.1.2.3', $validator->currentData);
$this->restore();
}
@@ -134,8 +135,12 @@ public function testShouldNotUseClientIpHeaderToTestProxyCapabilitiesByDefault()
'trusted_proxies' => ['0.1.2.3'],
];
- $validator = new RemoteAddr(null, $options);
- self::assertEquals('0.1.2.3', $validator->getData());
+ $validator = new RemoteAddr(
+ Environment::fromGlobals($_SERVER),
+ Environment::fromGlobals($_SERVER),
+ $options
+ );
+ self::assertEquals('0.1.2.3', $validator->current->remoteAddr);
$this->restore();
}
@@ -150,8 +155,12 @@ public function testWillOmitTrustedProxyIpsFromXForwardedForMatching(): void
'trusted_proxies' => ['1.1.2.3'],
];
- $validator = new RemoteAddr(null, $options);
- self::assertEquals('2.1.2.3', $validator->getData());
+ $validator = new RemoteAddr(
+ Environment::fromGlobals($_SERVER),
+ Environment::fromGlobals($_SERVER),
+ $options
+ );
+ self::assertEquals('2.1.2.3', $validator->currentData);
$this->restore();
}
@@ -167,14 +176,22 @@ public function testCanSpecifyWhichHeaderToUseStatically(): void
'proxy_header' => 'Client-Ip',
];
- $validator = new RemoteAddr(null, $options);
- self::assertEquals('0.1.2.3', $validator->getData());
+ $validator = new RemoteAddr(
+ Environment::fromGlobals($_SERVER),
+ Environment::fromGlobals($_SERVER),
+ $options
+ );
+ self::assertEquals('0.1.2.3', $validator->current->remoteAddr);
$this->restore();
}
public function testGetName(): void
{
- self::assertEquals(RemoteAddr::class, $this->defaultRemoteAddr->getName());
+ $validator = new RemoteAddr(
+ Environment::fromGlobals($_SERVER),
+ Environment::fromGlobals($_SERVER)
+ );
+ self::assertEquals(RemoteAddr::class, $validator->getName());
}
public function testUnknownServerHeader(): void
@@ -186,8 +203,12 @@ public function testUnknownServerHeader(): void
'proxy_header' => 'Unknown-Header',
];
- $validator = new RemoteAddr(null, $options);
- self::assertEmpty($validator->getData());
+ $validator = new RemoteAddr(
+ Environment::fromGlobals($_SERVER),
+ Environment::fromGlobals($_SERVER),
+ $options
+ );
+ self::assertEmpty($validator->current->remoteAddr);
$this->restore();
}
}
diff --git a/test/Validator/StaticValidatorStub.php b/test/Validator/StaticValidatorStub.php
deleted file mode 100644
index 37209c58..00000000
--- a/test/Validator/StaticValidatorStub.php
+++ /dev/null
@@ -1,31 +0,0 @@
-
- */
-class StaticValidatorStub implements ValidatorInterface
-{
- public static int $isValidCallCount = 0;
-
- public function isValid(): bool
- {
- self::$isValidCallCount++;
- return $this->getData();
- }
-
- public function getData(): mixed
- {
- return false;
- }
-
- public function getName(): string
- {
- return self::class;
- }
-}
diff --git a/test/Validator/ValidatorChainTest.php b/test/Validator/ValidatorChainTest.php
index e74efbf1..de530588 100644
--- a/test/Validator/ValidatorChainTest.php
+++ b/test/Validator/ValidatorChainTest.php
@@ -5,6 +5,7 @@
namespace LaminasTest\Session\Validator;
use Laminas\Session\Storage\ArrayStorage;
+use Laminas\Session\Validator\Environment;
use Laminas\Session\ValidatorChain;
use LaminasTest\Session\TestAsset\TestFailingValidator;
use PHPUnit\Framework\TestCase;
@@ -26,25 +27,11 @@ public function testGetStorage(): void
public function testAttachValidator(): void
{
- $validator = new TestFailingValidator();
+ $validator = new TestFailingValidator(Environment::fromGlobals($_SERVER), Environment::fromGlobals($_SERVER));
$this->validatorChain->attach('test', [$validator, 'isValid']);
$validatorMetadata = $this->validatorChain->getStorage()->getMetadata('_VALID');
self::assertIsArray($validatorMetadata);
- self::assertArrayHasKey($validator->getName(), $validatorMetadata);
- self::assertSame($validatorMetadata[$validator->getName()], $validator->getData());
- }
-
- public function testExistingValidatorsAreAttached(): void
- {
- $validator = new StaticValidatorStub();
- $storage = new ArrayStorage();
- $storage->setMetadata('_VALID', [$validator::class => $validator->getData()]);
-
- $this->validatorChain = new ValidatorChain($storage);
-
- $this->validatorChain->trigger('session.validate');
- self::assertSame(1, $validator::$isValidCallCount);
}
}