Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

208 lignes
5.4KB

  1. <?php
  2. declare(strict_types=1);
  3. use Core\App;
  4. use Core\Auth\KeycloakAuth;
  5. use Core\Auth\PermissionService;
  6. use Core\Database;
  7. use Core\Http\Session;
  8. use Core\MigrationManager;
  9. use Core\Response;
  10. use Core\View;
  11. // ── Framework helpers ─────────────────────────────────────────────────────────
  12. function app(): App
  13. {
  14. static $app = null;
  15. if ($app === null) {
  16. $app = new App();
  17. }
  18. return $app;
  19. }
  20. function view(string $view, array $data = []): Response
  21. {
  22. return View::render($view, $data);
  23. }
  24. function redirect(string $url): Response
  25. {
  26. return Response::redirect($url);
  27. }
  28. // ── Environment helpers ───────────────────────────────────────────────────────
  29. function env(string $key, mixed $default = null): mixed
  30. {
  31. $value = $_ENV[$key] ?? getenv($key);
  32. return ($value === false) ? $default : $value;
  33. }
  34. function loadEnv(string $path): void
  35. {
  36. if (!file_exists($path)) {
  37. return;
  38. }
  39. foreach (file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
  40. $line = trim($line);
  41. if ($line === '' || str_starts_with($line, '#') || !str_contains($line, '=')) {
  42. continue;
  43. }
  44. [$key, $value] = explode('=', $line, 2);
  45. $key = trim($key);
  46. $value = trim($value, " \t\"'");
  47. if (!isset($_ENV[$key]) && getenv($key) === false) {
  48. $_ENV[$key] = $value;
  49. putenv("{$key}={$value}");
  50. }
  51. }
  52. }
  53. // ── Session helper ────────────────────────────────────────────────────────────
  54. function session(): Session
  55. {
  56. static $session = null;
  57. if ($session === null) {
  58. $session = new Session();
  59. }
  60. return $session;
  61. }
  62. // ── Auth helper ───────────────────────────────────────────────────────────────
  63. function auth(): KeycloakAuth
  64. {
  65. static $auth = null;
  66. if ($auth === null) {
  67. $auth = new KeycloakAuth(session(), new PermissionService());
  68. }
  69. return $auth;
  70. }
  71. // ── Database helpers ──────────────────────────────────────────────────────────
  72. function ensureSqlServerDatabase(array $config): void
  73. {
  74. if (!str_starts_with($config['dsn'] ?? '', 'sqlsrv:')) {
  75. return;
  76. }
  77. preg_match('/Server=([^;]+)/', $config['dsn'], $serverMatch);
  78. preg_match('/Database=([^;]+)/', $config['dsn'], $dbMatch);
  79. if (empty($serverMatch[1]) || empty($dbMatch[1])) {
  80. return;
  81. }
  82. $server = $serverMatch[1];
  83. $dbName = $dbMatch[1];
  84. try {
  85. $masterPdo = new PDO(
  86. "sqlsrv:Server={$server};Database=master;LoginTimeout=5;TrustServerCertificate=1",
  87. $config['username'] ?? null,
  88. $config['password'] ?? null,
  89. [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
  90. );
  91. $check = $masterPdo->prepare('SELECT 1 FROM sys.databases WHERE name = ?');
  92. $check->execute([$dbName]);
  93. if (!$check->fetch()) {
  94. $safeName = str_replace(']', ']]', $dbName);
  95. $masterPdo->exec("CREATE DATABASE [{$safeName}]");
  96. }
  97. } catch (\Throwable) {
  98. // Let the main connection fail with its own error if master access fails
  99. }
  100. }
  101. function database(): Database
  102. {
  103. static $database = null;
  104. if ($database === null) {
  105. /** @var array<string, mixed> $config */
  106. $config = require __DIR__ . '/../config/database.php';
  107. ensureSqlServerDatabase($config);
  108. $database = new Database($config);
  109. }
  110. return $database;
  111. }
  112. function migration_manager(): MigrationManager
  113. {
  114. static $migrationManager = null;
  115. if ($migrationManager === null) {
  116. $migrationManager = new MigrationManager(database(), __DIR__ . '/../database/migrations');
  117. }
  118. return $migrationManager;
  119. }
  120. // ── Session / CSRF helpers ────────────────────────────────────────────────────
  121. function ensureSessionStarted(): void
  122. {
  123. if (session_status() === PHP_SESSION_NONE) {
  124. session_start();
  125. }
  126. }
  127. function e(?string $value): string
  128. {
  129. return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
  130. }
  131. function asset(string $path): string
  132. {
  133. return '/' . ltrim($path, '/');
  134. }
  135. function csrf_token(): string
  136. {
  137. ensureSessionStarted();
  138. if (!isset($_SESSION['_csrf_token']) || !is_string($_SESSION['_csrf_token'])) {
  139. $_SESSION['_csrf_token'] = bin2hex(random_bytes(32));
  140. }
  141. return $_SESSION['_csrf_token'];
  142. }
  143. function csrf_field(): string
  144. {
  145. return '<input type="hidden" name="_token" value="' . e(csrf_token()) . '">';
  146. }
  147. function verify_csrf_token(?string $token): bool
  148. {
  149. ensureSessionStarted();
  150. if (!is_string($token) || $token === '') {
  151. return false;
  152. }
  153. $sessionToken = $_SESSION['_csrf_token'] ?? null;
  154. return is_string($sessionToken) && hash_equals($sessionToken, $token);
  155. }

Powered by TurnKey Linux.