bootstrap.php 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. <?php
  2. /**
  3. * Application bootstrap. Every entry script in public/ includes this first.
  4. */
  5. declare(strict_types=1);
  6. define('APP_ROOT', dirname(__DIR__));
  7. define('DATA_DIR', APP_ROOT . '/data');
  8. define('MEDIA_DIR', APP_ROOT . '/public/media');
  9. define('CONFIG_DIR', APP_ROOT . '/config');
  10. if (!is_file(CONFIG_DIR . '/config.php')) {
  11. http_response_code(500);
  12. exit('Missing config/config.php — copy config/config.sample.php and adjust it.');
  13. }
  14. $GLOBALS['config'] = require CONFIG_DIR . '/config.php';
  15. date_default_timezone_set(config('site.timezone', 'UTC'));
  16. require APP_ROOT . '/app/storage.php';
  17. require APP_ROOT . '/app/csrf.php';
  18. require APP_ROOT . '/app/auth.php';
  19. require APP_ROOT . '/app/s3.php';
  20. require APP_ROOT . '/app/partials.php';
  21. /**
  22. * Read a config value by dot path, e.g. config('s3.bucket').
  23. */
  24. function config(string $path, mixed $default = null): mixed
  25. {
  26. $value = $GLOBALS['config'];
  27. foreach (explode('.', $path) as $part) {
  28. if (!is_array($value) || !array_key_exists($part, $value)) {
  29. return $default;
  30. }
  31. $value = $value[$part];
  32. }
  33. return $value;
  34. }
  35. /** HTML-escape for output. */
  36. function e(?string $s): string
  37. {
  38. return htmlspecialchars($s ?? '', ENT_QUOTES, 'UTF-8');
  39. }
  40. /** Start the session with hardened cookie settings (idempotent). */
  41. function session_boot(): void
  42. {
  43. if (session_status() === PHP_SESSION_ACTIVE) {
  44. return;
  45. }
  46. session_set_cookie_params([
  47. 'lifetime' => 0,
  48. 'path' => '/',
  49. 'secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
  50. 'httponly' => true,
  51. 'samesite' => 'Lax',
  52. ]);
  53. session_name('fpsid');
  54. session_start();
  55. }
  56. /** Redirect and stop. */
  57. function redirect(string $url): never
  58. {
  59. header('Location: ' . $url);
  60. exit;
  61. }
  62. /** Send a JSON response and stop (used by admin/api.php). */
  63. function json_response(array $payload, int $status = 200): never
  64. {
  65. http_response_code($status);
  66. header('Content-Type: application/json; charset=utf-8');
  67. echo json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
  68. exit;
  69. }