By itself, this middleware is incomplete, as it fails to set a session cookie in the PSR-7 response whenever the session ID changes.
For my own use, I have extended this as follows:
<?php
use Middlewares\PhpSession;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
class PhpSessionMiddleware extends PhpSession
{
/**
* @var string|null
*/
protected $name;
/**
* @var string|null
*/
protected $id;
public function __construct()
{
if (ini_get('session.use_trans_sid') != false) {
throw new RuntimeException('session.use_trans_sid must be false');
}
if (ini_get('session.use_cookies') != false) {
throw new RuntimeException('session.use_cookies must be false');
}
if (ini_get('session.use_only_cookies') != true) {
throw new RuntimeException('session.use_only_cookies must be true');
}
if (ini_get('session.cache_limiter') !== '') {
throw new RuntimeException('session.cache_limiter must be an empty string');
}
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
// Preemptively read and inject the session name and ID. This saves us from
// re-implementing a bunch of private methods from the parent class, and
// we need the starting session ID to allow us to detect when to write a
// session cookie since the parent class doesn't handle doing that
$this->name = $this->name ?: session_name();
if ($this->name) {
$this->id = $this->id ?: self::readSessionCookie($request, $this->name);
}
$response = parent::process($request, $handler);
if (session_id() !== $this->id) {
$response = self::writeSessionCookie(
$response,
session_name(),
session_id(),
time(),
session_get_cookie_params()
);
}
return $response;
}
private static function readSessionCookie(ServerRequestInterface $request, string $name): string
{
$cookies = $request->getCookieParams();
return $cookies[$name] ?? '';
}
private static function writeSessionCookie(ResponseInterface $response, string $name, string $id, int $now, array $params): ResponseInterface
{
$cookie = urlencode($name) . '=' . urlencode($id);
if ($params['lifetime']) {
$expires = gmdate('D, d M Y H:i:s T', $now + $params['lifetime']);
$cookie .= "; expires={$expires}; max-age={$params['lifetime']}";
}
if ($params['domain']) {
$cookie .= "; domain={$params['domain']}";
}
if ($params['path']) {
$cookie .= "; path={$params['path']}";
}
if ($params['secure']) {
$cookie .= '; secure';
}
if ($params['httponly']) {
$cookie .= '; httponly';
}
return $response->withAddedHeader('Set-Cookie', $cookie);
}
}
It would be nice to see this functionality incorporated.
By itself, this middleware is incomplete, as it fails to set a session cookie in the PSR-7 response whenever the session ID changes.
For my own use, I have extended this as follows:
It would be nice to see this functionality incorporated.