PHPackages                             seba1rx/sessionadmin - 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. seba1rx/sessionadmin

ActiveComposer-plugin[Security](/categories/security)

seba1rx/sessionadmin
====================

php session admin featuring url control and security against hijicking

2.1.0(1w ago)261MITPHPPHP &gt;=8.1

Since Jan 26Pushed 1w ago1 watchersCompare

[ Source](https://github.com/seba1rx/SessionAdmin)[ Packagist](https://packagist.org/packages/seba1rx/sessionadmin)[ RSS](/packages/seba1rx-sessionadmin/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (7)Dependencies (3)Versions (9)Used By (0)

seba1rx/sessionadmin
====================

[](#seba1rxsessionadmin)

PHP session management library with security hardening and optional per-browser-tab session isolation.

```
composer require seba1rx/sessionadmin
```

---

Features
--------

[](#features)

**Session security**

- Named sessions with configurable cookie parameters
- Hijacking detection: IP prefix + User-Agent fingerprint verified on every request
- Proxy-aware IP detection (reads `X-Forwarded-For` and equivalent headers)
- Session destruction when a request arrives after the configured lifetime
- Session ID regenerated on login and randomly (~3% of requests) to resist fixation

**URL authorization (MPA)**

- Define an `$allowedUrls` list; guests are redirected to `index.php` on any unlisted page
- Expandable per user role or profile
- Disable entirely for SPA apps (`$appIsSpa = true`, the default)

**Per-tab session isolation**

- Each browser tab gets its own scoped `$_SESSION` space via a UUID cookie
- Tabs tracked server-side: active/inactive status, last-active timestamp, stored keys
- Automatic stale-tab cleanup via `TabManager::cleanupInactiveTabs()`
- Optional close notification when a tab is closed (`SESSIONADMIN_AUTO_DESTROY`)
- Zero manual routing — endpoints registered automatically via `autoload.files`

---

Quick start
-----------

[](#quick-start)

`SessionAdmin` is abstract with no abstract methods. Extend it and define a constructor:

```
// App/MySession.php
namespace App;

use Seba1rx\SessionAdmin\SessionAdmin;

class MySession extends SessionAdmin
{
    public function __construct()
    {
        $this->sessionName     = 'my_app';
        $this->sessionLifetime = 3600;          // seconds
        $this->keys            = ['theme' => 'light']; // pre-seeded session keys
    }
}
```

Then on every entry point, before any output:

```
require 'vendor/autoload.php';

$session = new App\MySession();
$session->useAuthorization  = false; // true for MPA URL enforcement
$session->useTabIndexation  = true;  // false to disable TabManager
$session->activateSession();         // replaces session_start()

// On login:
$session->createUserSession($userId);

// On logout:
$session->terminate();

// Auth check:
if (!empty($_SESSION['sessionadmin']['isUser'])) {
    // authenticated
}
```

### Public API

[](#public-api)

MethodDescription`activateSession()`Starts or resumes the session; runs all security checks`createUserSession(mixed $id)`Marks session as authenticated, regenerates session ID`terminate()`Destroys session, reinitialises as guest, redirects to `index.php` (MPA)`setSessionHandler(\SessionHandlerInterface $handler)`Plug in a custom storage backend; call before `activateSession()`The full class is documented via docblocks — your IDE will surface every property and its purpose.

### Session data written to `$_SESSION['sessionadmin']`

[](#session-data-written-to-_sessionsessionadmin)

KeyPresentDescription`appType`Always`'SPA'` or `'MPA'` — reflects the `$appIsSpa` flag`isUser`Always`true` when authenticated, `false` for guests`id_user`After loginValue passed to `createUserSession()``msg`AlwaysHuman-readable state label`uniqueId`Always12-char hex token, stable for the session lifetime`ipPrefix`AlwaysFirst N octets of the client IP (hijacking detection)`userAgent`AlwaysUser-Agent string (hijacking detection)`time_atRequest`AlwaysUnix timestamp of the last request`time_sinceLastRequest`AlwaysSeconds elapsed since the previous request`allowedUrl`**MPA only**Copy of `$allowedUrls` used for URL authorization`urlIsAllowedToLoad`**MPA only**`true` when the current URL is in the allow-list`allowedUrl` and `urlIsAllowedToLoad` are omitted entirely in SPA mode — they only make sense when URL authorization is active.

---

Custom session storage
----------------------

[](#custom-session-storage)

By default the package uses PHP's native file-based session storage. Pass any [`SessionHandlerInterface`](https://www.php.net/manual/en/class.sessionhandlerinterface.php) implementation to `setSessionHandler()` before calling `activateSession()` to swap the backend:

```
$session = new App\MySession();
$session->setSessionHandler(new RedisSessionHandler($redis));
$session->activateSession();
```

Any PSR-compatible or custom handler works — Redis, database, encrypted file store, etc. The handler must be set **before** `activateSession()` because PHP applies the handler prior to calling `session_start()`.

---

Contracts (interfaces)
----------------------

[](#contracts-interfaces)

The package ships two interfaces under `Seba1rx\SessionAdmin\Contracts` that you can type-hint against to decouple your code from the concrete classes:

InterfaceImplemented byMethods`SessionInterface``SessionAdmin``activateSession()`, `createUserSession()`, `terminate()``TabStorageInterface``TabManager``set()`, `get()`, `isTabIndexed()`, `touchTab()`, `cleanupInactiveTabs()`**Example — type-hint in a service class:**

```
use Seba1rx\SessionAdmin\Contracts\SessionInterface;
use Seba1rx\SessionAdmin\Contracts\TabStorageInterface;

class CartService
{
    public function __construct(
        private readonly SessionInterface    $session,
        private readonly TabStorageInterface $tabs,
    ) {}

    public function addItem(string $sku, int $qty): void
    {
        $cart = $this->tabs->get('cart', []);
        $cart[$sku] = ($cart[$sku] ?? 0) + $qty;
        $this->tabs->set('cart', $cart);
    }
}
```

**Example — mock in tests:**

```
$mockSession = $this->createMock(SessionInterface::class);
$mockSession->expects($this->once())->method('activateSession');
```

---

Tab isolation
-------------

[](#tab-isolation)

When `$useTabIndexation = true` (the default), a `TabManager` instance is available at `$session->tabManager` after `activateSession()`.

Set `$autoIndexTab = true` to index the current tab from the `SESSIONADMIN_TABID` cookie on every request, without waiting for the JS beacon. This guarantees the tab entry exists immediately on page load, and also keeps `last_active` fresh on every request so the cleanup TTL is accurate.

Set `$autoCleanupTabs` to a positive integer to automatically remove closed-tab data. On every call to `activateSession()`, tabs that have been marked inactive (via the `/sessionadmin/tab-close` beacon) for longer than the threshold are deleted. Set to `0` (default) to disable automatic cleanup.

```
$session->useTabIndexation = true;
$session->autoIndexTab     = true;   // index + touch tab on every request
$session->autoCleanupTabs  = 30;     // auto-remove tabs inactive for > 30 s
$session->activateSession();
```

**PHP:**

```
// Store data scoped to the current browser tab
$session->tabManager->set('cart', ['apple' => 3]);

// Retrieve it
$cart = $session->tabManager->get('cart');

// Check whether the current tab has a session entry
$session->tabManager->isTabIndexed();

// Remove stale inactive tabs (e.g. call periodically to prevent session bloat)
$session->tabManager->cleanupInactiveTabs(3600); // remove tabs inactive for > 1 hour
```

**HTML — include the JS client** (published to your project root on `composer install`):

```

    window.SESSIONADMIN_AUTO_DESTROY = true;  // notify server on tab close (optional)

```

`init()` runs synchronously as soon as the script is parsed (no DOMContentLoaded wait), so any flags must be in an inline `` that precedes the script tag.

The script generates a UUIDv4 per tab using `crypto.randomUUID()`, persists it in `sessionStorage`, and writes it to the `SESSIONADMIN_TABID` cookie so every PHP request can identify its tab. The navigation type (`performance.navigation.type`) is used to distinguish reloads (TYPE\_RELOAD = 1, reuses UUID) from new navigations and duplicated tabs (TYPE\_NAVIGATE = 0, generates fresh UUID). Back/forward navigation (TYPE\_BACK\_FORWARD = 2) also preserves the UUID.

---

Built-in endpoints
------------------

[](#built-in-endpoints)

Registered automatically via `autoload.files` — no route configuration needed:

MethodPathPurpose`POST``/sessionadmin/new-tab`Index a new tab (called by JS on open)`POST``/sessionadmin/tab-close`Mark tab inactive (called by JS on close)---

Demos
-----

[](#demos)

DemoDescription[`demo/basic/`](demo/basic/)Minimal login/logout, no tab indexation — the simplest possible implementation[`demo/MPA/`](demo/MPA/)Multi-page app with URL authorization and `$allowedUrls`[`demo/SPA/`](demo/SPA/)Single-page app, SPA mode, AJAX login[`demo/TABS/`](demo/TABS/)Full feature set: tab isolation, TabManager CRUDEach demo is self-contained with its own `composer.json`.

### Running a demo locally

[](#running-a-demo-locally)

1. Install dependencies for the chosen demo:

```
cd demo/TABS
composer install
```

2. Start PHP's built-in web server from the demo directory:

```
php -S localhost:8000
```

3. Open your browser and navigate to:

```
http://localhost:8000

```

> The built-in server serves `index.php` by default. Change the port if `8000` is already in use (`php -S localhost:8080`).

###  Health Score

46

—

FairBetter than 93% of packages

Maintenance98

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity56

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 ~138 days

Recently: every ~54 days

Total

7

Last Release

9d ago

Major Versions

1.2.2 → 2.0.02025-10-14

### Community

Maintainers

![](https://www.gravatar.com/avatar/e3924979c02f4c461760be3ed08486572f30a4b92a56d6cab2f41509548c04bf?d=identicon)[seba1rx](/maintainers/seba1rx)

---

Top Contributors

[![seba1rx](https://avatars.githubusercontent.com/u/15786046?v=4)](https://github.com/seba1rx "seba1rx (78 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/seba1rx-sessionadmin/health.svg)

```
[![Health](https://phpackages.com/badges/seba1rx-sessionadmin/health.svg)](https://phpackages.com/packages/seba1rx-sessionadmin)
```

###  Alternatives

[roave/security-advisories

Prevents installation of composer packages with known security vulnerabilities: no API, simply require it

2.9k97.3M6.4k](/packages/roave-security-advisories)[mews/purifier

Laravel 5/6/7/8/9/10 HtmlPurifier Package

2.0k16.7M113](/packages/mews-purifier)[drupal/core-vendor-hardening

Hardens the vendor directory for when it's in the docroot.

174.5M28](/packages/drupal-core-vendor-hardening)[acmephp/ssl

PHP wrapper around OpenSSL extension providing SSL encoding, decoding, parsing and signing features

141.2M4](/packages/acmephp-ssl)[mxr576/ddqg-composer-audit

Drupal Dependency Quality Gate Composer Audit plugin

1056.7k2](/packages/mxr576-ddqg-composer-audit)[plan2net/typo3-update-check

A Composer plugin that checks for TYPO3 updates and provides detailed information about breaking changes and security updates

204.5k](/packages/plan2net-typo3-update-check)

PHPackages © 2026

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