Session.php 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. <?php
  2. declare(strict_types=1);
  3. namespace Glacier\Core;
  4. /**
  5. * 会话管理封装(架构约定 docs/architecture.md §3.6)。
  6. * - 安全 Cookie:HttpOnly + SameSite=Lax + Secure(生产自动开启)
  7. * - session 名唯一化(glacier_sid)
  8. * - CSRF Token 生成/校验(表单统一走中间件)
  9. * - 登录后调用 regenerate() 防会话固定(P7 接入登录时使用)
  10. */
  11. final class Session
  12. {
  13. public static function start(): void
  14. {
  15. if (session_status() === PHP_SESSION_ACTIVE) {
  16. return;
  17. }
  18. $debug = (bool) Config::get('app.debug', true);
  19. session_name('glacier_sid');
  20. session_set_cookie_params([
  21. 'lifetime' => 0,
  22. 'path' => '/',
  23. 'domain' => '',
  24. 'secure' => (bool) Config::get('app.secure_cookies', !$debug),
  25. 'httponly' => true,
  26. 'samesite' => 'Lax',
  27. ]);
  28. session_start();
  29. }
  30. public static function get(string $key, mixed $default = null): mixed
  31. {
  32. return $_SESSION[$key] ?? $default;
  33. }
  34. public static function set(string $key, mixed $value): void
  35. {
  36. $_SESSION[$key] = $value;
  37. }
  38. public static function has(string $key): bool
  39. {
  40. return isset($_SESSION[$key]);
  41. }
  42. public static function remove(string $key): void
  43. {
  44. unset($_SESSION[$key]);
  45. }
  46. /** 清空并销毁会话(登出)。 */
  47. public static function destroy(): void
  48. {
  49. $_SESSION = [];
  50. if (ini_get('session.use_cookies')) {
  51. $params = session_get_cookie_params();
  52. setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
  53. }
  54. session_destroy();
  55. }
  56. /** 重置会话 ID(登录成功后调用,防会话固定)。 */
  57. public static function regenerate(): void
  58. {
  59. session_regenerate_id(true);
  60. }
  61. /** 获取(或生成)CSRF Token。 */
  62. public static function csrfToken(): string
  63. {
  64. if (empty($_SESSION['csrf_token'])) {
  65. $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
  66. }
  67. return $_SESSION['csrf_token'];
  68. }
  69. /** 校验 CSRF Token(恒定时间比较)。 */
  70. public static function csrfCheck(string $token): bool
  71. {
  72. $stored = $_SESSION['csrf_token'] ?? '';
  73. return $stored !== '' && hash_equals($stored, $token);
  74. }
  75. }