baraja-core / session
Simple performance package for storage your sessions to database by native PDO.
Installs: 2 419
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 1
Forks: 1
Open Issues: 4
pkg:composer/baraja-core/session
Requires
- php: ^8.1
- ext-pdo: *
Requires (Dev)
- baraja-core/doctrine: ^3.0
- nette/di: ^3.0
- nette/http: ^3.1
- phpstan/extension-installer: ^1.1
- phpstan/phpstan: ^1.0
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-nette: ^1.0
- phpstan/phpstan-strict-rules: ^1.0
- roave/security-advisories: dev-master
- spaze/phpstan-disallowed-calls: ^2.0
- tracy/tracy: ^2.9
This package is auto-updated.
Last update: 2026-01-04 11:12:56 UTC
README
Simple, high-performance package for storing PHP sessions in a MySQL database using native \PDO. This package provides a robust database-backed session handler that works seamlessly with both native PHP applications and the Nette Framework.
π― Key Features
- Native PDO Implementation - Uses PHP's native PDO extension for reliable database connections with prepared statements
- Framework Agnostic - Works with native PHP applications out of the box
- Nette Framework Integration - Includes DI extension for seamless Nette integration
- Doctrine ORM Support - Optional entity mapping for Doctrine-based applications
- Automatic Garbage Collection - Probabilistic GC with configurable session lifetime (14 days default)
- CLI Safe - Automatically skips session operations in CLI mode to prevent errors
- Binary Data Support - Automatic Base64 encoding fallback for problematic session data
- Tracy Debugger Integration - Logs errors to Tracy when available
- Custom Table Names - Configurable database table name for multi-tenant applications
ποΈ Architecture Overview
The package consists of three main components that work together to provide database session storage:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Native PHP Nette Framework β
β βββββββββββ βββββββββββββββ β
β session_set_save_handler() SessionExtension β
β β β β
β β β β
β βΌ βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SessionStorage β β
β β implements \SessionHandlerInterface β β
β β β β
β β β’ open() - Initialize connection β β
β β β’ close() - Cleanup β β
β β β’ read() - Load session data β β
β β β’ write() - Persist session data β β
β β β’ destroy() - Remove session β β
β β β’ gc() - Garbage collection β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β β PDO β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β MySQL Database β β
β β core__session_storage table β β
β β β β
β β β’ id (varchar 26) - Session identifier β β
β β β’ haystack (longtext) - Serialized data β β
β β β’ last_update (datetime) - Last modification β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Optional: SessionEntity (Doctrine ORM mapping) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π§© Components
SessionStorage
The core component implementing PHP's \SessionHandlerInterface. It handles all session operations:
- Connection Management: Creates a dedicated PDO connection with proper character encoding (UTF-8) and error handling
- Session Reading: Retrieves session data from database, handles Base64-encoded data transparently
- Session Writing: Persists session data with automatic timestamp updates, falls back to Base64 encoding for binary data
- Session Destruction: Removes session records from the database
- Garbage Collection: Probabilistic cleanup (0.1% chance per request) removing sessions older than 14 days, limited to 500 records per run
SessionExtension
A Nette Framework DI extension that provides:
- Automatic Service Registration: Registers
SessionStorageas a service - Doctrine Integration: Automatically registers entity paths when Doctrine is present
- DBAL Connection Reuse: Can inherit database credentials from existing Doctrine DBAL connection
- Session Handler Setup: Automatically configures Nette's Session to use the database handler
SessionEntity
A Doctrine ORM entity class providing:
- Entity Mapping: Proper ORM annotations for the session table
- Type Safety: Strongly typed properties for session data
- Immutable Timestamps: Uses
DateTimeImmutablefor the last update field
π¦ Installation
It's best to use Composer for installation, and you can also find the package on Packagist and GitHub.
To install, simply use the command:
$ composer require baraja-core/session
You can use the package manually by creating an instance of the internal classes, or register a DIC extension to link the services directly to the Nette Framework.
Requirements
- PHP 8.1 or higher
- PDO extension (
ext-PDO) - MySQL database
ποΈ Database Setup
Create the database table core__session_storage (table name can be configured) or use Doctrine for automatic schema generation.
MySQL Table Schema
SET NAMES utf8; SET time_zone = '+00:00'; SET foreign_key_checks = 0; SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; CREATE TABLE `core__session_storage` ( `id` varchar(26) COLLATE utf8_unicode_ci NOT NULL, `haystack` longtext COLLATE utf8_unicode_ci NOT NULL, `last_update` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Note: The table can be used with Doctrine ORM or as a standalone MySQL table.
Using Doctrine Migrations
If you're using Doctrine ORM, the schema can be generated automatically from the SessionEntity class. Simply run your standard Doctrine migration commands:
$ php bin/console doctrine:schema:update --force
βοΈ Configuration
Native PHP Usage
For standalone PHP applications, create a SessionStorage instance and register it as the session handler:
$handler = new \Baraja\Session\SessionStorage( '127.0.0.1', // MySQL host 'my_application', // Database name 'root', // Username '****' // Password ); session_set_save_handler($handler); session_start();
Warning: The session handler must be registered before calling
session_start()!
Nette Framework Usage
Register the extension in your NEON configuration file:
extensions: barajaPdoSession: Baraja\Session\SessionExtension
The session storage will be configured automatically.
Manual Configuration
If you need to specify database credentials explicitly:
extensions: barajaPdoSession: Baraja\Session\SessionExtension barajaPdoSession: host: 127.0.0.1 dbName: my_application username: root password: **** table: core__session_storage # optional, this is the default
Automatic Doctrine DBAL Integration
When using the baraja-core/doctrine package, the extension automatically inherits database credentials from your existing DBAL connection. No additional configuration is required!
π§ Advanced Configuration
Custom Table Name
You can customize the database table name in two ways:
1. Via Constructor Parameter:
$handler = new \Baraja\Session\SessionStorage( 'localhost', 'mydb', 'user', 'password', 'my_custom_sessions_table' // Custom table name );
2. Via Setter Method:
$handler = new \Baraja\Session\SessionStorage(/* ... */); $handler->setTable('my_custom_sessions_table');
3. Via NEON Configuration (Nette):
barajaPdoSession: table: my_custom_sessions_table
Note: The default table name is
core__session_storage. While the table name can be changed at runtime, it is not recommended.
Garbage Collection
The garbage collector runs automatically with a 0.1% probability on each request. It:
- Removes sessions that haven't been updated in 14 days
- Processes a maximum of 500 records per run to prevent long-running queries
- Is skipped entirely in CLI mode
π Security Considerations
Session Data Encoding
When session data contains characters incompatible with MySQL's UTF-8 encoding, the package automatically:
- Detects the encoding failure via PDO exception
- Re-encodes the data using Base64 with a
_BASE:prefix - Transparently decodes on read
This ensures binary data and special characters are safely stored without data loss.
CLI Mode Protection
Session operations are automatically skipped in CLI mode (detected by absence of $_SERVER['REMOTE_ADDR']). This prevents:
- Errors when running console commands
- Unnecessary database connections in CLI scripts
- Accidental session manipulation from cron jobs
Error Handling
- Database query failures throw
\RuntimeExceptionwith helpful error messages - Session corruption errors are logged to Tracy (if available) and display a user-friendly error message
- Failed session writes gracefully degrade without crashing the application
π How It Works
Session Lifecycle
- Initialization: When a request arrives,
SessionStoragecreates a PDO connection - Reading: The
read()method fetches session data by ID, creating a new record if none exists - Processing: Your application uses
$_SESSIONas normal - Writing: At request end,
write()updates the session record with new data and timestamp - Cleanup: GC randomly triggers to remove old sessions (0.1% probability)
Data Flow
βββββββββββββββ ββββββββββββββββββββ ββββββββββββββββ
β Request ββββββΆβ SessionStorage ββββββΆβ Database β
β β β β β β
β read SID β β SELECT by ID β β Return row β
βββββββββββββββ ββββββββββββββββββββ ββββββββββββββββ
β β β
β βΌ β
β ββββββββββββββββββββ β
β β Decode haystack β β
β β (Base64 if needed)β β
β ββββββββββββββββββββ β
β β β
βΌ βΌ βΌ
βββββββββββββββ ββββββββββββββββββββ ββββββββββββββββ
β Response βββββββ SessionStorage βββββββ Database β
β β β β β β
β write data β β UPDATE record β β Store row β
βββββββββββββββ ββββββββββββββββββββ ββββββββββββββββ
Retry Mechanism
The loadById() method includes a retry mechanism (up to 5 attempts) for handling race conditions when creating new session records. This ensures reliability under concurrent access.
π API Reference
SessionStorage
class SessionStorage implements \SessionHandlerInterface { public function __construct( string $host, string $dbName, string $username, ?string $password = null, ?string $table = null, ); public function setTable(string $table): void; public function open($savePath, $sessionName): bool; public function close(): bool; public function read($id): string; public function write($id, $data): bool; public function destroy($id): bool; public function gc($maxlifetime): int|false; }
SessionExtension (Nette)
Configuration schema:
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
host |
string |
No* | - | MySQL host |
dbName |
string |
No* | - | Database name |
username |
string |
No* | - | Database username |
password |
string |
No* | - | Database password |
table |
string |
No | core__session_storage |
Table name |
* Required unless Doctrine DBAL is available (credentials are then inherited automatically).
π Troubleshooting
"Session was corrupted" Error
This error appears when session data cannot be written due to encoding issues. The package attempts to re-encode using Base64, but if this also fails:
- Check your MySQL character set configuration
- Ensure the
haystackcolumn usesutf8_unicode_ciorutf8mb4_unicode_ci - Clear corrupted sessions:
DELETE FROM core__session_storage WHERE id = 'problematic_id'
"mb_substr" Function Not Available
The error Function "mb_substr" is not available indicates the mbstring extension is not installed. Install it:
# Debian/Ubuntu sudo apt-get install php-mbstring # CentOS/RHEL sudo yum install php-mbstring
Session Not Persisting
- Verify the handler is registered before
session_start() - Check database credentials and connectivity
- Ensure the session table exists with correct schema
- Verify you're not in CLI mode (sessions are disabled in CLI)
π€ Author
Jan BarΓ‘Ε‘ek
- Website: https://baraja.cz
- GitHub: https://github.com/baraja-core
π License
baraja-core/session is licensed under the MIT license. See the LICENSE file for more details.