Session Storage Handlers

The files handler ties each visitor to one server. Behind a load balancer, use Redis 2,763 via phpredis 10,226 (github.com/phpredis/phpredis (https://github.com/phpredis/phpredis 10,226 ); sudo apt install php8.5-redis, then session.save_handler = redis), Memcached 4,600 , or a class implementing SessionHandlerInterface. Extending the built-in SessionHandler changes only what you override; this one encrypts the files at rest with libsodium (Encryption):

SealedSessionHandler.php: the files handler, encryptedPHP
<?php
declare(strict_types=1);
final class SealedSessionHandler extends SessionHandler      // the files handler, encrypted
  implements SessionUpdateTimestampHandlerInterface
{
  public function __construct(private string $key) {}         // 32 bytes from the environment
  public function read(string $id): string|false {
    $box = parent::read($id);
    if (!$box) return $box;                                     // '' for a new session
    $plain = sodium_crypto_secretbox_open(substr($box, 24), substr($box, 0, 24), $this->key);
    return $plain === false ? '' : $plain;                      // tampered: start empty
  }
  public function write(string $id, string $data): bool {
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);  // 24 bytes
    return parent::write($id, $nonce . sodium_crypto_secretbox($data, $nonce, $this->key));
  }
  public function validateId(string $id): bool {                // restores use_strict_mode
    return is_file(session_save_path() . "/sess_$id");
  }
  public function updateTimestamp(string $id, string $data): bool {   // lazy_write
    return touch(session_save_path() . "/sess_$id");
  }
}

sealed.php registers it with session_set_save_handler() and includes cart.php:

Output of 155
$ curl -s -c s.txt '127.0.0.1:8215/sealed.php?add=BK-101'
BK-101 x 1
$ sudo base64 -w 72 /var/lib/php/sessions/sess_$(awk '$6 == "PHPSESSID" {print $7}' s.txt)
uvWk023MkVwNL0WbUjZNNXmPLNDmGfCI+4GLgWzHKvb+mJn+wLu6y4BHBpzVVJPbIMBo3ZIu
gTY0EajVrZJLgldINSA=
$ curl -si -b PHPSESSID=forged00000000000000000000000001 127.0.0.1:8215/sealed.php \
  | grep -i ^set-cookie | fold_cookies
Set-Cookie: PHPSESSID=2cbb9d30b59473c63c7b9ebaea2336e7;
    path=/; secure; HttpOnly; SameSite=Lax

The forged ID was replaced only thanks to validateId(); without it, this class accepted forged…1, silently disabling strict mode. Handlers must also lock. The files handler holds an flock() until the script ends, so one visitor's requests run in turn: a page holding its session for two seconds delayed a second request by 1.8 s here, and session_write_close() before the slow work cut that to 1 ms. phpredis locks only with redis.session.locking_enabled = 1.