231 lines
7.4 KiB
PHP
Executable File
231 lines
7.4 KiB
PHP
Executable File
<?php
|
|
|
|
/**
|
|
* Script to manage user sessions
|
|
* Usage:
|
|
* php scripts/session-manager.php list [user_id] - List sessions for a user (or all if no user_id)
|
|
* php scripts/session-manager.php expire [user_id] - Expire all sessions for a user
|
|
*/
|
|
|
|
require __DIR__.'/../vendor/autoload.php';
|
|
|
|
$app = require_once __DIR__.'/../bootstrap/app.php';
|
|
$kernel = $app->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);
|
|
}
|