make(Illuminate\Contracts\Console\Kernel::class); $kernel->bootstrap(); if ($argc < 2) { echo "Usage:\n"; echo " php session-manager.php list [user_id] - List sessions\n"; echo " php session-manager.php expire [user_id] - Expire sessions\n"; exit(1); } $action = $argv[1]; $userId = isset($argv[2]) ? (int) $argv[2] : null; $sessionDriver = config('session.driver'); echo "Session driver: {$sessionDriver}\n\n"; if ($sessionDriver === 'database') { // Database sessions $table = config('session.table', 'sessions'); echo "Querying database sessions from table '{$table}'...\n"; $query = DB::table($table); if ($userId) { $query->where('user_id', $userId); } else { $query->whereNotNull('user_id'); // Only show logged-in sessions } $dbSessions = $query->get(); echo "Found " . count($dbSessions) . " session(s)\n\n"; } elseif ($sessionDriver === 'redis') { // Redis sessions $redis = \Illuminate\Support\Facades\Redis::connection(config('session.connection') ?: 'default'); $prefix = config('database.redis.options.prefix', ''); echo "Scanning Redis for sessions...\n"; $cursor = '0'; $allKeys = []; do { $result = $redis->scan($cursor, ['match' => '*laravel_session:*', 'count' => 1000]); $cursor = $result[0]; $keys = $result[1] ?? []; $allKeys = array_merge($allKeys, $keys); } while ($cursor !== '0'); echo "Found " . count($allKeys) . " total session keys\n\n"; } else { echo "Unsupported session driver: {$sessionDriver}\n"; exit(1); } function unserializeSession($data) { $result = []; if (empty($data)) return $result; // Try to find user ID in serialized data if (preg_match('/login_web_[a-f0-9]+";i:(\d+)/', $data, $matches)) { $result['user_id'] = (int) $matches[1]; } // Try to find last activity if (preg_match('/last_activity";i:(\d+)/', $data, $matches)) { $result['last_activity'] = $matches[1]; } // Try to find activeProfileType if (preg_match('/activeProfileType";s:\d+:"([^"]+)"/', $data, $matches)) { $result['profile_type'] = $matches[1]; } return $result; } $sessions = []; if ($sessionDriver === 'database') { // Process database sessions foreach ($dbSessions as $session) { $parsed = unserializeSession($session->payload); // Determine guard from column (if exists) or fallback to session data $guard = $session->guard ?? $parsed['profile_type'] ?? 'web'; // Map guard to friendly name $guardMap = [ 'web' => 'User', 'bank' => 'Bank', 'organization' => 'Organization', 'admin' => 'Admin', ]; $profileType = $guardMap[$guard] ?? ucfirst($guard); $sessions[] = [ 'id' => $session->id, 'user_id' => $session->user_id, 'guard' => $guard, 'last_activity' => $session->last_activity, 'profile_type' => $profileType, 'ip_address' => $session->ip_address, 'user_agent' => substr($session->user_agent, 0, 50), ]; } } elseif ($sessionDriver === 'redis') { // Process Redis sessions foreach ($allKeys as $key) { $sessionData = $redis->get($key); if ($sessionData) { $parsed = unserializeSession($sessionData); if (isset($parsed['user_id'])) { // Filter by user if specified if ($userId === null || $parsed['user_id'] === $userId) { $sessions[] = [ 'key' => $key, 'user_id' => $parsed['user_id'], 'last_activity' => $parsed['last_activity'] ?? null, 'profile_type' => $parsed['profile_type'] ?? 'User', 'ttl' => $redis->ttl($key), ]; } } } } } if ($action === 'list') { if (empty($sessions)) { echo "No active sessions found" . ($userId ? " for user {$userId}" : "") . "\n"; } else { echo "Active sessions" . ($userId ? " for user {$userId}" : "") . ":\n"; echo str_repeat("=", 130) . "\n"; if ($sessionDriver === 'database') { printf("%-10s %-12s %-20s %-20s %-20s %-30s\n", "User ID", "Guard", "Last Activity", "Profile Type", "IP Address", "User Agent"); } else { printf("%-10s %-30s %-20s %-15s %s\n", "User ID", "Last Activity", "Profile Type", "TTL (sec)", "Session Key"); } echo str_repeat("-", 130) . "\n"; foreach ($sessions as $session) { $lastActivity = $session['last_activity'] ? date('Y-m-d H:i:s', $session['last_activity']) : 'Unknown'; $profileType = basename(str_replace('\\', '/', $session['profile_type'])); if ($sessionDriver === 'database') { printf("%-10s %-12s %-20s %-20s %-20s %-30s\n", $session['user_id'] ?? 'N/A', $session['guard'] ?? 'web', $lastActivity, $profileType, $session['ip_address'], $session['user_agent'] ); } else { $sessionKey = substr($session['key'], -20); printf("%-10d %-30s %-20s %-15s ...%s\n", $session['user_id'], $lastActivity, $profileType, $session['ttl'], $sessionKey ); } } echo str_repeat("=", 120) . "\n"; echo "Total: " . count($sessions) . " session(s)\n"; } } elseif ($action === 'expire') { if (!$userId) { echo "Error: User ID is required for expire action\n"; exit(1); } $user = \App\Models\User::find($userId); if (!$user) { echo "User {$userId} not found\n"; exit(1); } echo "User: {$user->name} (ID: {$user->id})\n"; echo "Sessions to expire: " . count($sessions) . "\n\n"; if (empty($sessions)) { echo "No sessions found for user {$userId}\n"; } else { $deleted = 0; if ($sessionDriver === 'database') { $table = config('session.table', 'sessions'); foreach ($sessions as $session) { DB::table($table)->where('id', $session['id'])->delete(); $deleted++; echo "✓ Deleted session: " . substr($session['id'], 0, 40) . "\n"; } } elseif ($sessionDriver === 'redis') { foreach ($sessions as $session) { $redis->del($session['key']); $deleted++; echo "✓ Deleted session: " . substr($session['key'], -40) . "\n"; } } echo "\n"; echo str_repeat("=", 50) . "\n"; echo "Total sessions deleted: {$deleted}\n"; echo "{$user->name} has been logged out from all devices\n"; echo str_repeat("=", 50) . "\n"; } } else { echo "Unknown action: {$action}\n"; echo "Valid actions: list, expire\n"; exit(1); }