auth.php 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Admin;
  4. use App\App\Bootstrap;
  5. if (realpath((string) ($_SERVER['SCRIPT_FILENAME'] ?? '')) === __FILE__) {
  6. http_response_code(404);
  7. exit;
  8. }
  9. final class Auth
  10. {
  11. /** @var array<string, mixed> */
  12. private array $app;
  13. public function __construct()
  14. {
  15. $this->app = Bootstrap::config('app');
  16. }
  17. public function isLoggedIn(): bool
  18. {
  19. return isset($_SESSION['admin_logged_in'], $_SESSION['admin_username'])
  20. && $_SESSION['admin_logged_in'] === true
  21. && is_string($_SESSION['admin_username'])
  22. && $_SESSION['admin_username'] !== '';
  23. }
  24. public function login(string $username, string $password): bool
  25. {
  26. $username = trim($username);
  27. if ($username === '' || $password === '') {
  28. return false;
  29. }
  30. $credentials = $this->credentialTable();
  31. foreach ($credentials as $entry) {
  32. if (!is_array($entry)) {
  33. continue;
  34. }
  35. $configuredUsername = trim((string) ($entry['username'] ?? ''));
  36. $hash = (string) ($entry['password_hash'] ?? '');
  37. if ($configuredUsername === '' || $hash === '') {
  38. continue;
  39. }
  40. if (!hash_equals(strtolower($configuredUsername), strtolower($username))) {
  41. continue;
  42. }
  43. if (!password_verify($password, $hash)) {
  44. return false;
  45. }
  46. $_SESSION['admin_logged_in'] = true;
  47. $_SESSION['admin_username'] = $configuredUsername;
  48. $_SESSION['admin_login_at'] = time();
  49. session_regenerate_id(true);
  50. return true;
  51. }
  52. return false;
  53. }
  54. public function logout(): void
  55. {
  56. $_SESSION = [];
  57. if (ini_get('session.use_cookies')) {
  58. $params = session_get_cookie_params();
  59. setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], (bool) $params['secure'], (bool) $params['httponly']);
  60. }
  61. session_destroy();
  62. }
  63. public function requireLogin(): void
  64. {
  65. $timeout = (int) ($this->app['admin']['session_timeout_seconds'] ?? 3600);
  66. $loginAt = (int) ($_SESSION['admin_login_at'] ?? 0);
  67. if ($this->isLoggedIn() && $loginAt > 0 && (time() - $loginAt) > $timeout) {
  68. $this->logout();
  69. }
  70. if (!$this->isLoggedIn()) {
  71. header('Location: ' . Bootstrap::url('admin/login.php'));
  72. exit;
  73. }
  74. }
  75. /** @return array<int, array{username?: mixed, password_hash?: mixed}> */
  76. private function credentialTable(): array
  77. {
  78. $table = $this->app['admin']['credentials'] ?? [];
  79. return is_array($table) ? $table : [];
  80. }
  81. }