- sogoctl: supervisor avec health checks et restart auto - sogoway: gateway HTTP, auth JWT, routing par hostname - sogoms-db: microservice MariaDB avec pool par application - Protocol IPC Unix socket JSON length-prefixed - Config YAML multi-application (prokov) - Deploy script pour container Alpine gw3 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
163 lines
4.2 KiB
PHP
163 lines
4.2 KiB
PHP
<?php
|
|
/**
|
|
* Gestion des sessions en base de données
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
class Session
|
|
{
|
|
private static ?array $currentSession = null;
|
|
private static ?array $currentUser = null;
|
|
|
|
/**
|
|
* Récupérer l'IP réelle du client (derrière proxy)
|
|
*/
|
|
public static function getClientIp(): ?string
|
|
{
|
|
// Headers transmis par le proxy nginx
|
|
$headers = [
|
|
'HTTP_X_REAL_IP',
|
|
'HTTP_X_FORWARDED_FOR',
|
|
'HTTP_CLIENT_IP',
|
|
'REMOTE_ADDR',
|
|
];
|
|
|
|
foreach ($headers as $header) {
|
|
if (!empty($_SERVER[$header])) {
|
|
// X-Forwarded-For peut contenir plusieurs IPs (client, proxy1, proxy2...)
|
|
$ips = explode(',', $_SERVER[$header]);
|
|
$ip = trim($ips[0]);
|
|
|
|
if (filter_var($ip, FILTER_VALIDATE_IP)) {
|
|
return $ip;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Créer une nouvelle session pour un utilisateur
|
|
*/
|
|
public static function create(int $userId, ?string $ipAddress = null, ?string $userAgent = null): string
|
|
{
|
|
$db = Database::getInstance();
|
|
$sessionId = bin2hex(random_bytes(64)); // 128 caractères
|
|
$expiresAt = date('Y-m-d H:i:s', time() + SESSION_LIFETIME);
|
|
|
|
$stmt = $db->prepare('
|
|
INSERT INTO sessions (id, user_id, ip_address, user_agent, expires_at)
|
|
VALUES (:id, :user_id, :ip_address, :user_agent, :expires_at)
|
|
');
|
|
|
|
$stmt->execute([
|
|
'id' => $sessionId,
|
|
'user_id' => $userId,
|
|
'ip_address' => $ipAddress ?? self::getClientIp(),
|
|
'user_agent' => $userAgent ?? $_SERVER['HTTP_USER_AGENT'] ?? null,
|
|
'expires_at' => $expiresAt,
|
|
]);
|
|
|
|
return $sessionId;
|
|
}
|
|
|
|
/**
|
|
* Valider une session et retourner l'utilisateur
|
|
*/
|
|
public static function validate(string $sessionId): ?array
|
|
{
|
|
if (self::$currentSession !== null && self::$currentSession['id'] === $sessionId) {
|
|
return self::$currentUser;
|
|
}
|
|
|
|
$db = Database::getInstance();
|
|
|
|
$stmt = $db->prepare('
|
|
SELECT s.*, u.id as user_id, u.email, u.name
|
|
FROM sessions s
|
|
JOIN users u ON s.user_id = u.id
|
|
WHERE s.id = :id AND s.expires_at > NOW()
|
|
');
|
|
|
|
$stmt->execute(['id' => $sessionId]);
|
|
$result = $stmt->fetch();
|
|
|
|
if (!$result) {
|
|
return null;
|
|
}
|
|
|
|
self::$currentSession = [
|
|
'id' => $result['id'],
|
|
'user_id' => $result['user_id'],
|
|
'expires_at' => $result['expires_at'],
|
|
];
|
|
|
|
self::$currentUser = [
|
|
'id' => $result['user_id'],
|
|
'email' => $result['email'],
|
|
'name' => $result['name'],
|
|
];
|
|
|
|
return self::$currentUser;
|
|
}
|
|
|
|
/**
|
|
* Détruire une session
|
|
*/
|
|
public static function destroy(string $sessionId): bool
|
|
{
|
|
$db = Database::getInstance();
|
|
|
|
$stmt = $db->prepare('DELETE FROM sessions WHERE id = :id');
|
|
$stmt->execute(['id' => $sessionId]);
|
|
|
|
self::$currentSession = null;
|
|
self::$currentUser = null;
|
|
|
|
return $stmt->rowCount() > 0;
|
|
}
|
|
|
|
/**
|
|
* Nettoyer les sessions expirées
|
|
*/
|
|
public static function cleanup(): int
|
|
{
|
|
$db = Database::getInstance();
|
|
|
|
$stmt = $db->prepare('DELETE FROM sessions WHERE expires_at < NOW()');
|
|
$stmt->execute();
|
|
|
|
return $stmt->rowCount();
|
|
}
|
|
|
|
/**
|
|
* Prolonger une session
|
|
*/
|
|
public static function extend(string $sessionId): bool
|
|
{
|
|
$db = Database::getInstance();
|
|
$expiresAt = date('Y-m-d H:i:s', time() + SESSION_LIFETIME);
|
|
|
|
$stmt = $db->prepare('
|
|
UPDATE sessions SET expires_at = :expires_at WHERE id = :id
|
|
');
|
|
|
|
$stmt->execute([
|
|
'id' => $sessionId,
|
|
'expires_at' => $expiresAt,
|
|
]);
|
|
|
|
return $stmt->rowCount() > 0;
|
|
}
|
|
|
|
/**
|
|
* Obtenir l'utilisateur courant (depuis le cache)
|
|
*/
|
|
public static function getCurrentUser(): ?array
|
|
{
|
|
return self::$currentUser;
|
|
}
|
|
}
|