bootstrap.php 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  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. /**
  21. * Read a config value by dot path, e.g. config('s3.bucket').
  22. */
  23. function config(string $path, mixed $default = null): mixed
  24. {
  25. $value = $GLOBALS['config'];
  26. foreach (explode('.', $path) as $part) {
  27. if (!is_array($value) || !array_key_exists($part, $value)) {
  28. return $default;
  29. }
  30. $value = $value[$part];
  31. }
  32. return $value;
  33. }
  34. /** HTML-escape for output. */
  35. function e(?string $s): string
  36. {
  37. return htmlspecialchars($s ?? '', ENT_QUOTES, 'UTF-8');
  38. }
  39. /** Start the session with hardened cookie settings (idempotent). */
  40. function session_boot(): void
  41. {
  42. if (session_status() === PHP_SESSION_ACTIVE) {
  43. return;
  44. }
  45. session_set_cookie_params([
  46. 'lifetime' => 0,
  47. 'path' => '/',
  48. 'secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
  49. 'httponly' => true,
  50. 'samesite' => 'Lax',
  51. ]);
  52. session_name('fpsid');
  53. session_start();
  54. }
  55. /** Redirect and stop. */
  56. function redirect(string $url): never
  57. {
  58. header('Location: ' . $url);
  59. exit;
  60. }
  61. /** Send a JSON response and stop (used by admin/api.php). */
  62. function json_response(array $payload, int $status = 200): never
  63. {
  64. http_response_code($status);
  65. header('Content-Type: application/json; charset=utf-8');
  66. echo json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
  67. exit;
  68. }