Sessions

Rhapsody\Core\Session is a small static wrapper around PHP's native sessions. It gives you one consistent place to store per-visitor data (the logged-in user, one-time flash messages, the CSRF token) with secure cookie settings applied for you. There is nothing to instantiate: every method is static.

use Rhapsody\Core\Session;

Session::set('cart_id', 42);

$cartId = Session::get('cart_id');          // 42
$theme  = Session::get('theme', 'light');   // 'light' (the default) when the key is not set
Start it once per request: Session::start() must have run before you read or write session data, and it must run only once per request. See Flash Messages for why a second call causes trouble.

Reading and Writing Values

Method What it does
Session::set($key, $value)Stores a value under a key.
Session::get($key, $default = null)Returns the stored value, or $default when the key is not set.
Session::has($key)Returns true if the key is set and its value is not null.
Session::pull($key, $default = null)Returns the value and removes it in one step. Returns $default if the key was not set.
Session::remove($key)Deletes a key.

has() treats a null value as “not set”. If you need to store a deliberate null and tell it apart from a missing key, store a different marker value instead.

Read once with pull()

pull() is the right tool for any value that should be used exactly once, such as a one-time confirmation code or the URL a visitor was trying to reach before being sent to the login page:

// Before redirecting to the login form
Session::set('intended_url', $request->getPath());

// After a successful login
$destination = Session::pull('intended_url', '/dashboard');
// 'intended_url' is now gone from the session

Flash Messages

A flash message is a value that lives just long enough to be shown after a redirect, then disappears by itself. This is the usual “Profile saved” or “Invalid credentials” pattern.

// In the controller that handles the form POST
Session::flash('success', 'Your profile was saved.');
// ...then redirect to the profile page

// In the controller that shows the next page
$success = Session::getFlash('success');   // 'Your profile was saved.' or null
Method What it does
Session::flash($key, $message)Stores a flash message under a key.
Session::getFlash($key, $default = null)Returns the message as a string and removes it immediately. Returns null if there is no message, or if the stored value is not a scalar.
Session::hasFlash($key)Returns true if a message exists for the key. It does not remove it.

How long a flash message lives

  1. The message is available for the rest of the request that created it.
  2. It stays available for the next request.
  3. At the start of the request after that, Session::start() deletes it.

Reading a message with getFlash() removes it straight away, so read it once and keep the result in a variable if you need it more than once on the same page.

Danger: The aging of flash messages happens inside Session::start(). Calling it a second time in the same request ages the messages again and discards them before your page can show them.

Flash messages are stored under the key you give them, in the same namespace as values saved with set(). Choose flash keys (success, error, status) that you don't also use for ordinary session data.


Login, Logout, and Session Security

After a login: regenerate()

Always regenerate the session ID immediately after a user authenticates. This prevents session fixation, where an attacker plants a known session ID in a victim's browser and waits for them to log in. The old session is deleted.

// credentials verified...
Session::regenerate();
Session::set('user_id', $user->getId());

On logout: destroy()

destroy() does all three things needed to end a session properly. Doing only one or two leaves a usable session behind:

  1. Empties $_SESSION immediately, so the data is gone for the remainder of the request.
  2. Expires the session cookie in the visitor's browser.
  3. Destroys the session on the server.
Session::destroy();

Before a redirect: close()

close() writes the session data to storage and releases it. Call it before a redirect if you want to be sure everything you set is saved first. Changes made after close() are not saved.

Session::set('last_visit', time());
Session::close();

CSRF tokens

The session also holds the CSRF token that protects your forms.

$token = Session::csrfToken();               // created on first use, then reused

if (!Session::verifyCsrfToken($submitted)) {
    // reject the request
}

verifyCsrfToken() compares the tokens with hash_equals(), so the check is safe against timing attacks, and it returns false when no token has been issued yet. In templates you rarely call these yourself: put {{ csrf_field() }} inside every POST form and it outputs a hidden _token input holding the session's token. See Security for the full CSRF workflow.


Session Cookie Settings

Session::start() configures the session cookie before PHP starts the session:

  • Lifetime: 0, so the cookie lasts until the browser is closed.
  • Path: /, so the session works across your whole site.
  • HttpOnly: always on, so JavaScript cannot read the session ID.
  • SameSite: Lax, which blocks the cookie on most cross-site POST requests.
  • Secure: turned on automatically when the request is served over HTTPS, including behind a proxy that sends X-Forwarded-Proto: https.

If a session is already active, start() skips starting a new one, but it still ages the flash messages, which is why it must only run once per request.


Reserved Keys

The session uses three keys internally. Don't write to them yourself:

  • _token – the CSRF token.
  • _flash_new and _flash_old – the bookkeeping that tracks which flash messages to delete.

Related Documentation