joefallon/phpsession

A simple age and activity based session library.

Installs: 131

Dependents: 2

Suggesters: 0

Security: 0

Stars: 2

Watchers: 2

Forks: 0

Open Issues: 0

pkg:composer/joefallon/phpsession

v5.0.1 2025-10-12 23:08 UTC

This package is auto-updated.

Last update: 2025-10-12 23:12:04 UTC


README

phpsession is a small, well-tested PHP library that wraps the PHP session API and provides two common session-expiration strategies:

  • max age (time since the session was created)
  • last-activity timeout (time since the session was last accessed)

It is intentionally tiny, dependency-free, and designed for safe use in web applications where predictable session-expiration and non-blocking session access are important.

Why use phpsession?

  • Small and focused: one class that does one job well.
  • Non-blocking-friendly: the implementation opens the session only for the duration of an operation and closes it immediately afterwards, which reduces the chance of session-lock contention in concurrent requests (for example, AJAX-heavy frontends).
  • Well tested: comes with unit tests that exercise the public API and edge cases.
  • Composer-friendly and PSR-4 compatible.

Requirements

  • PHP 7.4 or later

Installation

Install with Composer (recommended):

composer require joefallon/phpsession

or add this to your composer.json and run composer install:

{
  "require": {
    "joefallon/phpsession": "*"
  }
}

Quick start

The class is namespaced under JoeFallon\PhpSession. Typical usage:

use JoeFallon\PhpSession\Session;

$session = new Session();
$session->write('user_id', '42');
$userId = $session->read('user_id');

// Remove a key
$session->unsetSessionValue('user_id');

// Destroy the whole session (and its cookie)
$session->destroy();

Constructor and configuration

The constructor accepts two optional integer parameters (seconds):

  • __construct(int $maxAgeInSecs = Session::HOUR, int $lastActivityInSecs = Session::HOUR)
    • $maxAgeInSecs — maximum age of the session since creation. Set to 0 to disable.
    • $lastActivityInSecs — timeout measured from the last read/write/unset. Set to 0 to disable.

Note: The constructor validates inputs and throws InvalidArgumentException if values are negative or if maxAgeInSecs is less than lastActivityInSecs. This is deliberate: the maximum age must be at least as long as the activity window.

Public API (methods)

  • public function read(string $key)

    • Return the stored value for $key or null if not present or if an empty key is passed. Reading updates the last-activity timestamp.
  • public function write(string $key, string $val): void

    • Stores $val under $key. Throws InvalidArgumentException if $key is empty. Writing updates the last-activity timestamp.
  • public function unsetSessionValue(string $key): void

    • Removes a session key (if present) and updates the last-activity timestamp.
  • public function isMaxAgeTimeoutExpired(): bool

    • Returns true when the time since session creation is greater than or equal to the configured max age. On first call this method initializes the creation timestamp and will return false.
  • public function isLastActivityTimeoutExpired(): bool

    • Returns true when the time since the last activity is greater than or equal to the configured activity timeout. On first call this method initializes the last-activity timestamp and will return false.
  • public function destroy(): void

    • Clears session data, removes the session cookie (if cookies are used), regenerates the session id to remove old data, and destroys the session.

Constants

  • Session::HOUR — 3600
  • Session::DAY — 86400
  • Session::WEEK — 604800

Detailed examples

  1. Short-lived session that expires after 30 seconds of inactivity:
$session = new Session(Session::HOUR, 30);
$session->write('cart', ['sku' => 'x', 'qty' => 1]);

// Later
if ($session->isLastActivityTimeoutExpired()) {
    // Force re-login or refresh the session
}
  1. Max-age-only session (ignore activity):
// Max age 24 hours, activity never expires
$session = new Session(Session::DAY, 0);
  1. Checking and rotating sessions safely

If you use isMaxAgeTimeoutExpired() or isLastActivityTimeoutExpired() in request logic, prefer to let the session management decide when to destroy the session. Example flow:

$session = new Session();
if ($session->isMaxAgeTimeoutExpired() || $session->isLastActivityTimeoutExpired()) {
    // Tear down and force a re-auth
    $session->destroy();
    // redirect to login
}

Security and best practices

  • Use secure cookies (HTTPS) and set session.cookie_secure=1 in PHP when serving over TLS.
  • Consider setting session.cookie_httponly=1 to reduce the risk of XSS-based cookie theft.
  • Regenerate session ids on privilege changes (e.g. login) using session_regenerate_id(true) in your authentication code path. This library intentionally does not regenerate an id on every open to keep behavior predictable and to avoid interfering with timeout logic.
  • Store only non-sensitive identifiers in sessions when possible. If you must store secrets, ensure your session storage is protected (e.g. server-side storage, not client-supplied).

Performance considerations

  • This library opens and closes the session around each operation which helps avoid long-lived session locks in high-concurrency environments (AJAX requests, concurrent fetches).
  • Avoid storing extremely large datasets in sessions to reduce IO and lock durations.

Testing

This project uses PHPUnit 9.6 for unit tests (the last PHPUnit series that supports PHP 7.4). The repository includes a phpunit.xml.dist and a tests/bootstrap.php bootstrap file.

Install dev dependencies (recommended):

Unix/macOS:

composer install --no-interaction --prefer-dist

Windows (cmd.exe / PowerShell):

composer install --no-interaction --prefer-dist

Run the test suite:

Unix/macOS:

./vendor/bin/phpunit --configuration phpunit.xml.dist

Windows (cmd.exe / PowerShell):

vendor\bin\phpunit --configuration phpunit.xml.dist

Notes and troubleshooting

  • If you previously used the project's legacy KissTest runner, it has been replaced by PHPUnit as part of the migration. There is no need to run php tests/index.php for automated test runs anymore.

  • If you see messages from Xdebug such as "Could not connect to debugging client" or other output before tests run, those messages can cause session_start() to fail because headers were already sent. The test bootstrap starts output buffering and the Session class includes a safe emulation fallback for environments where headers are already sent to keep tests deterministic. If you still encounter issues:

    • Temporarily disable Xdebug while running tests, or
    • Ensure your terminal environment is not emitting extra startup output.
  • To run a single test file or method, supply the path and optionally a filter, for example:

./vendor/bin/phpunit tests/JoeFallon/PhpSession/SessionTest.php
# or run a single test method
./vendor/bin/phpunit --filter test_read_write tests/JoeFallon/PhpSession/SessionTest.php

Continuous Integration

Example GitHub Actions job snippet (runs on Ubuntu):

steps:
  - uses: actions/checkout@v3
  - name: Set up PHP
    uses: shivammathur/setup-php@v2
    with:
      php-version: '7.4'
  - name: Install dependencies
    run: composer install --no-progress --no-suggest --prefer-dist
  - name: Run tests
    run: vendor/bin/phpunit --configuration phpunit.xml.dist

Contributing

Contributions are welcome. A good contribution path:

  1. Fork the repository.
  2. Create a small, focused branch for your change.
  3. Add tests that cover the behavior you change or add.
  4. Run the test suite and ensure everything is green.
  5. Open a pull request with a clear description of the change.

License

MIT — see the LICENSE file for details.

Acknowledgements

Built by Joe Fallon. The test framework was migrated from the small KissTest runner to PHPUnit 9.6 to keep compatibility with PHP 7.4; thanks to the authors of both projects.

Contact

If you have questions or need help integrating phpsession, open an issue on GitHub: https://github.com/joefallon/phpsession

Built with ❤️ and the KISS principle.