요청 처리 흐름

브라우저
  │
  ├─ .htaccess          모든 .php 요청을 __flexagon.php 로 rewrite
  │
  ├─ __flexagon.php ──► flexagon.php ──► Bootstrap.php
  │                                        │
  │                                        ├─ 상수 정의 (PROJECT_ROOT, PUBLIC_ROOT, _FLEXAGON_ROOT ...)
  │                                        ├─ 오토로더 등록
  │                                        ├─ _Const.php / _Global.php / _Config.php 로드
  │                                        └─ URL 파싱 → _Global::$URL_PARAM
  │
  ├─ public/_entry.php      ① 요청 시작 훅 (사이트 제목, 공통 헤더 등)
  ├─ [세션 자동 시작]        ② $SESSION_AUTO_START 가 true 인 경우
  ├─ public/_prepare.php    ③ 세션 이후 훅 (권한 검사 등)
  └─ public/_router.php     ④ 디스패치 — 기본 구현은 TemplateLoader::content()
                                 → public/<URL 경로>.php 실행

세 개의 훅은 각각 다른 시점을 담당합니다.

파일 시점 용도
_entry.php 세션 이전 사이트 메타 정보, 응답 헤더, 로케일
_prepare.php 세션 이후 인증·인가 검사, 공통 데이터 로드
_router.php 디스패치 페이지 실행. 커스텀 라우팅이 필요하면 이 파일을 교체

URL 매핑 규칙

요청 URL 실행되는 파일
/ public/index.php
/hello public/hello.php
/user/profile public/user/profile.php
/user/ public/user/index.php
/user/profile?id=3 public/user/profile.php

요청 경로는 HttpUtil::normalizePath()가 먼저 정규화합니다. NUL 바이트를 제거하고 백슬래시를 /로 접은 뒤 빈 세그먼트·.·..를 걷어내므로, ..로 상위 디렉터리를 가리킬 수 없습니다.

그리고 TemplateLoader는 최종 경로를 realpath()로 확정한 다음 public/(또는 _Template/) 안에 있는지 검사한 뒤에만 include합니다. 경계를 벗어나면 include하지 않고 404를 냅니다. 웹 서버의 경로 정규화에 기대지 않고 프레임워크가 직접 봉쇄합니다.

해석 결과는 _Global::$URL_PARAM(UrlParamsModel)에 담깁니다.

_Global::$URL_PARAM->filePath;       // 'user/profile'
_Global::$URL_PARAM->filePathArray;  // ['user', 'profile']
_Global::$URL_PARAM->filePathEnd;    // 'profile'
_Global::$URL_PARAM->params;         // '?id=3'

커스텀 라우팅

파일 매핑 대신 직접 디스패치하려면 public/_router.php를 바꿉니다.

<?php
// public/_router.php
$path = _Global::$URL_PARAM->filePath;

if (str_starts_with($path, 'api/')) {
    header('Content-Type: application/json');
    include_once PUBLIC_ROOT . '/api/_dispatch.php';
} else {
    TemplateLoader::content();
}