Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 4 additions & 36 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,9 @@
<MissingReturnType>
<code><![CDATA[initializeValidatorChain]]></code>
</MissingReturnType>
<MixedArgument>
<code><![CDATA[$validator]]></code>
</MixedArgument>
<MixedAssignment>
<code><![CDATA[$validator]]></code>
<code><![CDATA[$validatorValues]]></code>
</MixedAssignment>
<MixedMethodCall>
<code><![CDATA[new $validator(null)]]></code>
</MixedMethodCall>
<MoreSpecificImplementedParamType>
<code><![CDATA[$id]]></code>
</MoreSpecificImplementedParamType>
Expand Down Expand Up @@ -445,24 +438,10 @@
<code><![CDATA[static]]></code>
</PossiblyUnusedReturnValue>
</file>
<file src="src/Validator/HttpUserAgent.php">
<PossiblyNullPropertyAssignmentValue>
<code><![CDATA[$data]]></code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="src/ValidatorChain.php">
<MixedArgumentTypeCoercion>
<code><![CDATA[$callback]]></code>
</MixedArgumentTypeCoercion>
<MixedAssignment>
<code><![CDATA[$data]]></code>
<code><![CDATA[$data]]></code>
<code><![CDATA[$validator]]></code>
<code><![CDATA[$validators]]></code>
</MixedAssignment>
<MixedMethodCall>
<code><![CDATA[new $validator($data)]]></code>
</MixedMethodCall>
<PossiblyUnusedReturnValue>
<code><![CDATA[callable]]></code>
</PossiblyUnusedReturnValue>
Expand Down Expand Up @@ -815,6 +794,7 @@
<code><![CDATA[$_SESSION[$key]]]></code>
<code><![CDATA[$_SESSION[$key]]]></code>
<code><![CDATA[$_SESSION['__Laminas']['_VALID']]]></code>
<code><![CDATA[$_SESSION['__Laminas']['environment']]]></code>
</MixedArrayAccess>
<MixedAssignment>
<code><![CDATA[$header]]></code>
Expand Down Expand Up @@ -879,6 +859,9 @@
</MixedArrayAccess>
</file>
<file src="test/TestAsset/TestFailingValidator.php">
<PossiblyUnusedProperty>
<code><![CDATA[$current]]></code>
</PossiblyUnusedProperty>
<PossiblyUnusedReturnValue>
<code><![CDATA[bool]]></code>
</PossiblyUnusedReturnValue>
Expand Down Expand Up @@ -927,21 +910,6 @@
<code><![CDATA[gc]]></code>
</PossiblyUnusedMethod>
</file>
<file src="test/TestAsset/TestSaveHandlerWithValidator.php">
<ImplementedParamTypeMismatch>
<code><![CDATA[$data]]></code>
</ImplementedParamTypeMismatch>
<ImplementedReturnTypeMismatch>
<code><![CDATA[bool]]></code>
</ImplementedReturnTypeMismatch>
<ParamNameMismatch>
<code><![CDATA[$maxlifetime]]></code>
</ParamNameMismatch>
<PossiblyUnusedMethod>
<code><![CDATA[close]]></code>
<code><![CDATA[gc]]></code>
</PossiblyUnusedMethod>
</file>
<file src="test/TestAsset/TestSimpleCacheAdapter.php">
<MixedAssignment>
<code><![CDATA[$result]]></code>
Expand Down
43 changes: 34 additions & 9 deletions src/SessionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -24,6 +29,7 @@
use function session_status;
use function session_write_close;
use function setcookie;
use function unserialize;

use const PHP_SESSION_ACTIVE;

Expand Down Expand Up @@ -60,6 +66,8 @@ class SessionManager extends AbstractManager
/** @var EventManagerInterface Validation chain to determine if session is valid */
protected $validatorChain;

protected array $options = [];

/**
* Constructor
*
Expand All @@ -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']);
}
Expand Down Expand Up @@ -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<string, mixed> $storage */
$storage = $this->getStorage()->getMetadata();

/**
* @var class-string<ValidatorInterface> $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']);
}
}
Expand Down Expand Up @@ -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);
Expand Down
38 changes: 38 additions & 0 deletions src/Validator/Environment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Laminas\Session\Validator;

use function is_string;
use function session_id;

final class Environment
{
public function __construct(
public readonly ?string $userAgent = null,
public readonly ?string $remoteAddr = null,
public readonly ?string $forwardedFor = null,
public readonly ?string $sessionId = null
) {
}

public static function fromGlobals(array $server): self
{
$userAgent = isset($server['HTTP_USER_AGENT']) && is_string($server['HTTP_USER_AGENT'])
? $server['HTTP_USER_AGENT']
: null;

$remoteAddr = isset($server['REMOTE_ADDR']) && is_string($server['REMOTE_ADDR'])
? $server['REMOTE_ADDR']
: null;

$forwardedFor = isset($server['HTTP_X_FORWARDED_FOR']) && is_string($server['HTTP_X_FORWARDED_FOR'])
? $server['HTTP_X_FORWARDED_FOR']
: null;

$sessionId = session_id();

return new self($userAgent, $remoteAddr, $forwardedFor, $sessionId);
}
}
37 changes: 7 additions & 30 deletions src/Validator/HttpUserAgent.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,17 @@

namespace Laminas\Session\Validator;

/**
* @implements ValidatorInterface<string>
*/
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 = []
) {
}

/**
Expand All @@ -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;
Comment thread
gsteel marked this conversation as resolved.
}

/**
Expand Down
29 changes: 7 additions & 22 deletions src/Validator/Id.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@
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;
use const PHP_VERSION_ID;

/**
* session_id validator
*
* @implements ValidatorInterface<string|null>
*/
final class Id implements ValidatorInterface
{
Expand All @@ -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 = []
) {
}

/**
Expand All @@ -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;
}

Expand All @@ -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);
}

/**
Expand Down
Loading