Skip to content

codemonster-ru/session

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

codemonster-ru/session

Latest Version on Packagist Total Downloads License Tests Coverage

Lightweight session management library for PHP - object-oriented.

Installation

composer require codemonster-ru/session

Usage

Basic example

use Codemonster\Session\Session;

// Start session (default: file storage)
Session::start();

// Store values
Session::put('user', 'Vasya');
Session::put('role', 'admin');

// Retrieve values
echo Session::get('user'); // Vasya

// Remove values
Session::forget('role');

// Get all session data
print_r(Session::all());

// Destroy current session
Session::destroy();

Regenerating session ID (fixation protection)

// Rotate ID after login or privilege change
Session::regenerate();

Regenerating on start

// Force new ID at start (keeps data, destroys old session)
Session::start(options: ['regenerate' => true]);

Cookie options

Session::start(options: [
    'cookie' => [
        'secure' => true,
        'samesite' => 'Strict',
        'lifetime' => 3600,
        'path' => '/',
        'domain' => 'example.com'
    ]
]);

Notes:

  • If secure is not provided, it is set automatically when HTTPS is detected.
  • If samesite is None, secure is forced to true.

Production cookie example

Session::start(options: [
    'cookie' => [
        'secure' => true,
        'httponly' => true,
        'samesite' => 'Strict',
        'lifetime' => 60 * 60 * 24,
        'path' => '/'
    ]
]);

Encryption

use Codemonster\Session\Session;

$key = random_bytes(32);

Session::start(options: [
    'encryption' => [
        'key' => $key,
        // Optional: allow decrypting existing plaintext sessions
        // Also triggers auto-migration to encrypted payload on first read
        'allow_plaintext' => true,
        // Optional: previous keys for rotation
        'previous_keys' => []
    ]
]);

Encryption key rotation

$oldKey = random_bytes(32);
$newKey = random_bytes(32);

Session::start(options: [
    'encryption' => [
        'key' => $oldKey,
        'allow_plaintext' => true
    ]
]);

// rotate to a new key, keeping the old key for decryption
Session::rotateEncryptionKey($newKey, [$oldKey]);

Production encryption example

// Store keys in env/secret manager; use base64 for readability.
$currentKey = base64_decode(getenv('SESSION_KEY'), true);
$previousKey = base64_decode(getenv('SESSION_KEY_PREV'), true);

Session::start(options: [
    'encryption' => [
        'key' => $currentKey,
        'previous_keys' => array_filter([$previousKey]),
        'allow_plaintext' => false
    ]
]);

Key rotation strategy

  1. Deploy with previous_keys containing the old key and key as the new key.
  2. Keep allow_plaintext=false if you already migrated to encryption.
  3. After rotation window, remove the old key from previous_keys.

Using Array handler (for tests or CLI)

Session::start('array');
Session::put('debug', true);

echo Session::get('debug'); // true

Handy helpers

Session::put('count', 1);
Session::increment('count', 2); // 3

Session::put('token', 'abc');
Session::has('token'); // true
Session::pull('token'); // 'abc'
Session::has('token'); // false

Session::put('a', 1);
Session::put('b', 2);
Session::forgetMany(['a', 'b']);

// Flash data lasts for the next start and is then removed
Session::flash('notice', 'Saved');

TTL for keys

Session::putWithTtl('token', 'abc', 60); // expires in 60 seconds
Session::sweepExpired(); // optional manual cleanup
Session::ttl('token'); // remaining seconds
Session::expiresAt('token'); // unix timestamp
Session::touch('token', 120); // extend TTL

Namespaced sessions

$admin = Session::for('admin');
$user = Session::for('user');

$admin->put('token', 'admin123');
$user->put('token', 'user456');

Namespace helpers

$admin = Session::for('admin');
$admin->keys(); // ['token', ...]
$admin->forgetNamespace();
Session::count(); // count of user keys
Session::touchAll(120); // extend TTL for all keys
Session::touchAll(120, 'admin.'); // extend only for namespace

Session::keys(); // ['admin.token', 'user.token', ...]
Session::forgetNamespace('user');

Custom namespace delimiter

$scope = Session::for('admin', ':');
$scope->put('token', 'x'); // stored as admin:token

Debug helpers

Session::dump(); // array of user-visible keys/values
Session::dump(['token']); // redact selected keys
Session::dump([], ['user*']); // redact by pattern
Session::size(); // payload size in bytes

Key helpers

Session::keys(); // all keys
Session::keysMatch('user*'); // wildcard match

Session manager (non-static)

$manager = Session::manager();
$manager->put('token', 'abc');

$scoped = $manager->for('admin');
$scoped->put('token', 'admin123');

Using custom handler

use Codemonster\Session\Session;
use App\Session\RedisSessionHandler;

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$handler = new RedisSessionHandler($redis);

Session::start(customHandler: $handler);
Session::put('user_id', 42);

Using Redis handler

use Codemonster\Session\Handlers\RedisSessionHandler;
use Codemonster\Session\Session;

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$handler = new RedisSessionHandler($redis, prefix: 'sess_', ttl: 3600, retries: 2, retryDelayMs: 100);

Session::start(customHandler: $handler);

Using Redis Cluster handler

use Codemonster\Session\Handlers\RedisClusterSessionHandler;
use Codemonster\Session\Session;

$cluster = new RedisCluster(null, ['127.0.0.1:7000', '127.0.0.1:7001']);

$handler = new RedisClusterSessionHandler($cluster, prefix: 'sess_', ttl: 3600, retries: 2, retryDelayMs: 100);

Session::start(customHandler: $handler);

Using Redis Sentinel handler

use Codemonster\Session\Handlers\RedisSentinelSessionHandler;
use Codemonster\Session\Session;

$sentinel = new RedisSentinel('127.0.0.1', 26379);

$handler = new RedisSentinelSessionHandler(
    $sentinel,
    service: 'mymaster',
    prefix: 'sess_',
    ttl: 3600,
    retries: 2,
    retryDelayMs: 100
);

Session::start(customHandler: $handler);

Using Predis handler

use Codemonster\Session\Handlers\PredisSessionHandler;
use Codemonster\Session\Session;
use Predis\Client;

$client = new Client('tcp://127.0.0.1:6379');

$handler = new PredisSessionHandler($client, prefix: 'sess_', ttl: 3600, retries: 2, retryDelayMs: 100);

Session::start(customHandler: $handler);

Using PSR-16 cache handler

use Codemonster\Session\Handlers\CacheSessionHandler;
use Codemonster\Session\Session;
use Psr\SimpleCache\CacheInterface;

/** @var CacheInterface $cache */
$handler = new CacheSessionHandler($cache, prefix: 'sess_', ttl: 3600, retries: 2, retryDelayMs: 100);

Session::start(customHandler: $handler);

Testing

You can run tests with the command:

composer test

Static analysis:

composer analyse
composer psalm

Redis integration tests (optional):

REDIS_TESTS=1 composer test

Redis Sentinel/Cluster integration tests (optional):

REDIS_SENTINEL_TESTS=1 composer test
REDIS_CLUSTER_TESTS=1 composer test

Stress test (optional):

composer stress
composer stress -- 20000 array
composer stress -- 20000 file
REDIS_HOST=127.0.0.1 REDIS_PORT=6379 composer stress -- 20000 redis

# With thresholds: iterations, driver, min_ops, max_seconds
composer stress -- 20000 array 3400 6
composer stress -- 10000 file 1700 6
composer stress -- 20000 redis 400 6

Note: thresholds depend on runner performance; recalibrate if CI hardware changes.

Security

Security reports: email admin@codemonster.net with a clear description and steps to reproduce.

Security checklist:

  • Use HTTPS and secure cookies in production.
  • Set SameSite to Strict or Lax based on your flow.
  • Use httponly to reduce XSS access to cookies.
  • Rotate session IDs after login or privilege changes.
  • Consider payload encryption (encryption.key) for sensitive data.
  • Keep session storage private and with proper file permissions.

Author

Kirill Kolesnikov

License

MIT

About

Lightweight session management library for PHP with pluggable handlers

Topics

Resources

License

Stars

Watchers

Forks

Languages