PHPackages                             chani/safi-session - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. chani/safi-session

ActiveLibrary[Security](/categories/security)

chani/safi-session
==================

Standalone, secure PHP session management library preventing AJAX race conditions and session hijacking.

v0.1.3(today)02↑2900%MITPHPPHP ^8.5

Since Jul 27Pushed todayCompare

[ Source](https://github.com/chani/safi-session)[ Packagist](https://packagist.org/packages/chani/safi-session)[ Docs](https://github.com/chani/safi-session)[ RSS](/packages/chani-safi-session/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (9)Versions (5)Used By (0)

Safi Session Extension (`safi-session`)
=======================================

[](#safi-session-extension-safi-session)

`safi-session` is an isolated PHP 8.5+ session management library engineered to prevent request blocking during concurrent HTTP requests while enforcing client fingerprinting controls.

It operates without required framework dependencies and can be integrated standalone, into any PSR-15 compliant HTTP pipeline, or as a component within the Safi Microframework.

---

Technical Overview
------------------

[](#technical-overview)

### 1. Concurrency Control &amp; Read-Only Inference

[](#1-concurrency-control--read-only-inference)

Standard PHP session management (`session_start()`) acquires an exclusive lock (`LOCK_EX`) on the session storage resource. Simultaneous HTTP requests sharing the same session identifier (such as multiple browser tabs or concurrent SPA fetch operations) are queued and executed serially until the lock is released.

`safi-session` mitigates request blocking via two mechanisms:

- **HTTP Method Inference:** `GET`, `HEAD`, and `OPTIONS` requests trigger `session_start(['read_and_close' => true])`. Session state is loaded into `$_SESSION` and the storage lock is released immediately at request start (0ms lock duration).
- **Deferred Locking (Dirty State Tracking):** If session state is modified (`set()`, `remove()`, `clear()`) during a read-only request, modifications are buffered in memory. The storage lock is acquired briefly at request completion via `commit()` to persist changes.

### 2. Client Hijacking &amp; Subnet Protection (µADR-021 / µADR-035)

[](#2-client-hijacking--subnet-protection-µadr-021--µadr-035)

When `verify_client` is enabled, session initialization records and validates client metadata:

- **User-Agent SHA-256 Fingerprint:** User-Agent headers are hashed using SHA-256 and verified using constant-time comparison (`hash_equals`).
- **IP Subnet Masking:** Network matching applies CIDR masking (`/24` for IPv4, `/64` for IPv6). This prevents session invalidation caused by standard mobile network handoffs or client-side IPv6 privacy extension address rotations.

---

Installation
------------

[](#installation)

```
composer require chani/safi-session
```

---

How-To Guides
-------------

[](#how-to-guides)

### How to Use Standalone in Native PHP

[](#how-to-use-standalone-in-native-php)

```
use Safi\Extensions\Session\SessionService;
use Safi\Extensions\Session\SessionServiceInterface;
use Psr\Log\NullLogger;

/** @var SessionServiceInterface $session */
$session = new SessionService(
    logger: new NullLogger(),
    config: [
        'sessid'        => 'APP_SESSID',
        'lifetime'      => 86400,
        'samesite'      => 'Lax',
        'verify_client' => true,
    ],
    // Optional IP resolution callback or service object with getClientIp(): string
    ipResolver: fn(): string => $_SERVER['HTTP_CF_CONNECTING_IP'] ?? $_SERVER['REMOTE_ADDR'] ?? ''
);

// Start session
$session->start();

// Mutate state
$session->set('user_id', 101);

// Read state
$userId = $session->get('user_id');

// Atomic fetch-and-delete
$flash = $session->pull('flash_message');

// Commit state modifications and release locks
$session->commit();
```

---

### How to Integrate with PSR-15 Pipelines

[](#how-to-integrate-with-psr-15-pipelines)

`SessionMiddleware` implements `Psr\Http\Server\MiddlewareInterface`. It can be attached to any PSR-15 compliant request handler or middleware stack:

```
use Safi\Extensions\Session\SessionService;
use Safi\Extensions\Session\SessionMiddleware;
use Psr\Log\NullLogger;

$sessionService = new SessionService(
    logger: new NullLogger(),
    config: ['verify_client' => true]
);

// Instantiate PSR-15 middleware with automatic read-only inference for GET requests
$middleware = new SessionMiddleware($sessionService, autoInferReadOnly: true);

// Add $middleware to your application pipeline.
// The active SessionServiceInterface instance is injected into request attributes as 'session'.
```

Inside a downstream request handler or controller:

```
use Safi\Extensions\Session\SessionServiceInterface;
use Psr\Http\Message\ServerRequestInterface;

public function handle(ServerRequestInterface $request)
{
    /** @var SessionServiceInterface $session */
    $session = $request->getAttribute('session');
    $userId = $session->get('user_id');
}
```

---

### How to Integrate with Safi Microframework

[](#how-to-integrate-with-safi-microframework)

Register `SessionServiceProvider` in your composition root (`init.inc.php`):

```
use Safi\Extensions\Session\SessionServiceProvider;

$componentManager->bootProviders([
    new SessionServiceProvider([
        'sessid' => 'SAFI_SESSID',
        'verify_client' => true,
    ]),
]);
```

---

Reference
---------

[](#reference)

### `SessionServiceInterface` API

[](#sessionserviceinterface-api)

All session operations comply with `Safi\Extensions\Session\SessionServiceInterface`.

MethodSignatureDescription`start()``start(array $options = []): void`Initializes the session using configured parameters or runtime overrides.`get()``get(string $key, mixed$default = null): mixed`Returns the stored value or fallback default.`set()``set(string $key, mixed$value): void`Assigns a session value and marks state as dirty.`has()``has(string $key): bool`Determines whether a key exists in session memory.`remove()``remove(string $key): void`Unsets a key and marks state as dirty.`pull()``pull(string $key, mixed$default = null): mixed`Fetches and unsets a key in a single step.`clear()``clear(): void`Clears all session keys and marks state as dirty.`commit()``commit(): void`Flushes dirty state changes to persistent storage and releases locks.`close()``close(): void`Manually commits and closes the active write lock.`regenerateId()``regenerateId(bool $deleteOld = true): bool`Issues a new session identifier to prevent session fixation.`destroy()``destroy(): bool`Clears variables, expires client cookies, and destroys active storage.`isDirty()``isDirty(): bool`Returns true if session state has uncommitted changes.### Configuration Parameters

[](#configuration-parameters)

OptionTypeDefaultDescription`sessid``string``'SAFI_SESSID'`Session cookie identifier name.`lifetime``int``0`Cookie max lifetime in seconds (`0` = session duration).`path``string``'/'`Path scoping for session cookie.`domain``string``''`Domain scoping for session cookie.`samesite``string``'Lax'`SameSite cookie attribute (`'Lax'`, `'Strict'`, `'None'`).`read_only``bool``false`Global default read-only flag.`verify_client``bool``false`Enables SHA-256 User-Agent fingerprinting and subnet validation.---

License
-------

[](#license)

Distributed under the **MIT License**. Author: **Jean-Michel Brünn**

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance100

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

4

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/550669?v=4)[Jean-Michel Brünn](/maintainers/chani)[@chani](https://github.com/chani)

---

Top Contributors

[![chani](https://avatars.githubusercontent.com/u/550669?v=4)](https://github.com/chani "chani (8 commits)")

---

Tags

concurrencymiddlewaresecuritypsr-15sessionsession-managersession-middlewaresafi

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/chani-safi-session/health.svg)

```
[![Health](https://phpackages.com/badges/chani-safi-session/health.svg)](https://phpackages.com/packages/chani-safi-session)
```

###  Alternatives

[symfony/symfony

The Symfony PHP framework

31.4k87.2M2.2k](/packages/symfony-symfony)[cakephp/cakephp

The CakePHP framework

8.8k19.5M1.8k](/packages/cakephp-cakephp)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k16](/packages/tempest-framework)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[sunrise/http-router

A powerful solution as the foundation of your project.

17451.8k11](/packages/sunrise-http-router)[typo3/cms-core

TYPO3 CMS Core

3713.2M5.2k](/packages/typo3-cms-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
