Skip to main content

Overview

The Session helper class provides static methods for managing PHP sessions, user authentication state, and temporary flash messages. It ensures sessions are properly initialized and provides a clean API for session operations. Location: app/Helpers/Session.php
Session is a static helper class - all methods are called statically without instantiation.

Key Features

  • Safe session initialization
  • User session creation and destruction
  • Session state verification
  • Flash messages for temporary user feedback
  • Automatic flash message cleanup after retrieval

Public Methods

start()

Initializes the PHP session if not already started.
public static function start(): void
This method checks if a session is already active before calling session_start(), preventing “headers already sent” errors. Example:
// Safe to call multiple times
Session::start();
Session::start(); // Won't cause an error
Source: app/Helpers/Session.php:8-13
Most Session methods call start() internally, so you rarely need to call it directly.

create()

Creates a user session with the provided user data.
public static function create(array $userData): void
userData
array
required
Associative array containing user information (typically from database after authentication)
User Data Structure:
[
    'id'       => 1,
    'username' => 'admin',
    'email'    => '[email protected]',
    'role'     => 'admin',
    'name'     => 'Administrator'
]
Example:
// After successful authentication
$userModel = new User();
$user = $userModel->authenticate($username, $password);

if ($user) {
    Session::create($user);
    header('Location: ' . BASE_URL . '/dashboard');
    exit;
}
Source: app/Helpers/Session.php:18-22

isActive()

Checks if a user session is currently active.
public static function isActive(): bool
Returns: bool - true if user is logged in, false otherwise Example:
if (Session::isActive()) {
    echo 'User is logged in';
} else {
    echo 'No active session';
}

// Often used with Auth helper
if (Session::isActive()) {
    header('Location: ' . BASE_URL . '/dashboard');
} else {
    header('Location: ' . BASE_URL . '/login');
}
Source: app/Helpers/Session.php:27-31

destroy()

Completely destroys the user session.
public static function destroy(): void
This method:
  • Starts the session if needed
  • Unsets all session variables
  • Destroys the session
Example:
// Logout functionality
public function logout(): void
{
    Session::destroy();
    
    header('Location: ' . BASE_URL . '/login');
    exit;
}
Source: app/Helpers/Session.php:36-41

setFlash()

Stores a temporary flash message in the session.
public static function setFlash(string $key, string $message): void
key
string
required
Flash message identifier (commonly success, error, warning, info)
message
string
required
The message content to display to the user
Example:
// Success message
Session::setFlash('success', 'Reservation created successfully!');

// Error message
Session::setFlash('error', 'Invalid username or password.');

// Warning message
Session::setFlash('warning', 'This room is almost fully booked.');

// Info message
Session::setFlash('info', 'Your reservation is pending approval.');
Source: app/Helpers/Session.php:46-50

getFlash()

Retrieves and deletes a flash message from the session.
public static function getFlash(string $key): ?string
key
string
required
Flash message identifier to retrieve
Returns: ?string - The flash message, or null if not found
Flash messages are automatically deleted after retrieval, ensuring they only display once.
Example:
// In a view file
<?php if ($error = Session::getFlash('error')): ?>
    <div class="alert alert-danger">
        <?= htmlspecialchars($error) ?>
    </div>
<?php endif; ?>

<?php if ($success = Session::getFlash('success')): ?>
    <div class="alert alert-success">
        <?= htmlspecialchars($success) ?>
    </div>
<?php endif; ?>
Source: app/Helpers/Session.php:55-67

Real-World Usage Examples

User Authentication Flow

From AuthController::login():
public function login(): void
{
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        header('Location: ' . BASE_URL . '/login');
        exit;
    }
    
    $user = $_POST['username'] ?? '';
    $pass = $_POST['password'] ?? '';
    
    // Validation
    if (empty($user) || empty($pass)) {
        Session::setFlash('error', 'Todos los campos son obligatorios.');
        header('Location: login');
        exit;
    }
    
    // Authenticate
    $userModel = new User();
    $authResult = $userModel->authenticate($user, $pass);
    
    if (!$authResult) {
        Session::setFlash('error', 'Usuario o contraseña incorrectos.');
        header('Location: ' . BASE_URL . '/login');
        exit;
    }
    
    // Create session
    Session::create($authResult);
    
    header('Location: ' . BASE_URL . '/dashboard');
    exit;
}
Source: app/controllers/AuthController.php:19-51

Logout Flow

From AuthController::logout():
public function logout(): void
{
    // If no session, just redirect
    if (session_status() === PHP_SESSION_NONE) {
        session_start();
    }
    
    // Destroy session properly
    session_unset();
    session_destroy();
    
    // Regenerate ID for security
    session_regenerate_id(true);
    
    // Redirect to login
    header('Location: ' . BASE_URL . '/login');
    exit;
}
Source: app/controllers/AuthController.php:53-70
The logout() method in AuthController uses native PHP session functions instead of Session::destroy(). Consider refactoring to use the helper for consistency.

Redirect If Already Authenticated

From AuthController::showLogin():
public function showLogin(): void
{
    // If already logged in, go to dashboard
    if (Session::isActive()) {
        header('Location: ' . BASE_URL . '/dashboard');
        exit;
    }
    
    require_once dirname(__DIR__) . '/views/auth/login.php';
}
Source: app/controllers/AuthController.php:8-16

Flash Messages in Form Processing

From ReservationController::store():
public function store(): void
{
    Auth::requireLogin();
    
    // Get form data
    $userId   = $_SESSION['user']['id'] ?? null;
    $roomId   = $_POST['room_id'] ?? null;
    $event    = trim($_POST['event_name'] ?? '');
    
    // Validation
    if (!$userId || !$roomId || empty($event)) {
        Session::setFlash('error', 'Datos incompletos.');
        header('Location: ' . BASE_URL . '/reservations/create');
        exit;
    }
    
    if (count($dates) === 0) {
        Session::setFlash('error', 'Debe agregar al menos un horario.');
        header('Location: ' . BASE_URL . '/reservations/create');
        exit;
    }
    
    try {
        $db = Database::getConnection();
        $db->beginTransaction();
        
        // Create reservation and slots...
        
        $db->commit();
        
        Session::setFlash('success', 'La reservación fue creada correctamente.');
        header('Location: ' . BASE_URL . '/dashboard');
        exit;
        
    } catch (Exception $e) {
        if (isset($db) && $db->inTransaction()) {
            $db->rollBack();
        }
        
        Session::setFlash('error', $e->getMessage());
        header('Location: ' . BASE_URL . '/reservations/create');
        exit;
    }
}
Source: app/controllers/ReservationController.php:25-118

Approval/Rejection Feedback

From ReservationController:
public function approve(): void
{
    Auth::requireRole('admin');
    
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        header('Location: ' . BASE_URL . '/reservations');
        exit;
    }
    
    $id = $_POST['id'] ?? null;
    
    if (!$id) {
        Session::setFlash('error', 'Solicitud inválida.');
        header('Location: ' . BASE_URL . '/reservations');
        exit;
    }
    
    $reservationModel = new Reservation();
    $reservationModel->updateStatus((int)$id, 'aprobado');
    
    Session::setFlash('success', 'Solicitud aprobada correctamente.');
    header('Location: ' . BASE_URL . '/reservations');
    exit;
}

public function reject(): void
{
    Auth::requireRole('admin');
    
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        header('Location: ' . BASE_URL . '/reservations');
        exit;
    }
    
    $id = $_POST['id'] ?? null;
    
    if (!$id) {
        Session::setFlash('error', 'Solicitud inválida.');
        header('Location: ' . BASE_URL . '/reservations');
        exit;
    }
    
    $reservationModel = new Reservation();
    $reservationModel->updateStatus((int)$id, 'rechazado');
    
    Session::setFlash('success', 'Solicitud rechazada.');
    header('Location: ' . BASE_URL . '/reservations');
    exit;
}
Source: app/controllers/ReservationController.php:176-237

Flash Message Display Pattern

Common pattern in views for displaying flash messages:
<!-- In view header or layout file -->
<?php
$error = Session::getFlash('error');
$success = Session::getFlash('success');
$warning = Session::getFlash('warning');
$info = Session::getFlash('info');
?>

<?php if ($error): ?>
    <div class="alert alert-danger alert-dismissible fade show" role="alert">
        <?= htmlspecialchars($error) ?>
        <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    </div>
<?php endif; ?>

<?php if ($success): ?>
    <div class="alert alert-success alert-dismissible fade show" role="alert">
        <?= htmlspecialchars($success) ?>
        <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    </div>
<?php endif; ?>

<?php if ($warning): ?>
    <div class="alert alert-warning alert-dismissible fade show" role="alert">
        <?= htmlspecialchars($warning) ?>
        <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    </div>
<?php endif; ?>

<?php if ($info): ?>
    <div class="alert alert-info alert-dismissible fade show" role="alert">
        <?= htmlspecialchars($info) ?>
        <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    </div>
<?php endif; ?>

Implementation Details

Session Initialization Check

public static function start(): void
{
    if (session_status() === PHP_SESSION_NONE) {
        session_start();
    }
}
Source: app/Helpers/Session.php:8-13 This prevents the “headers already sent” error by checking if a session is already active.

Flash Message Storage

Flash messages are stored in a dedicated flash array within $_SESSION:
public static function setFlash(string $key, string $message): void
{
    self::start();
    $_SESSION['flash'][$key] = $message;
}
Source: app/Helpers/Session.php:46-50

Auto-Deletion of Flash Messages

public static function getFlash(string $key): ?string
{
    self::start();
    
    if (!isset($_SESSION['flash'][$key])) {
        return null;
    }
    
    $message = $_SESSION['flash'][$key];
    unset($_SESSION['flash'][$key]);  // Delete after reading
    
    return $message;
}
Source: app/Helpers/Session.php:55-67

Session Security

Consider implementing these security enhancements:
  • Call session_regenerate_id() after login to prevent session fixation
  • Set secure session cookie parameters in php.ini or via session_set_cookie_params()
  • Implement session timeout for inactive users
Enhanced logout example:
public function logout(): void
{
    Session::destroy();
    
    // Regenerate session ID for security
    session_regenerate_id(true);
    
    header('Location: ' . BASE_URL . '/login');
    exit;
}

See Also

Build docs developers (and LLMs) love