Request Lifecycle
Browser
│
├─ .htaccess rewrites all .php requests to __flexagon.php
│
├─ __flexagon.php ──► flexagon.php ──► Bootstrap.php
│ │
│ ├─ defines constants (PROJECT_ROOT, PUBLIC_ROOT, _FLEXAGON_ROOT ...)
│ ├─ registers the autoloader
│ ├─ loads _Const.php / _Global.php / _Config.php
│ └─ parses the URL → _Global::$URL_PARAM
│
├─ public/_entry.php ① request-start hook (site title, shared headers, etc.)
├─ [automatic session start] ② when $SESSION_AUTO_START is true
├─ public/_prepare.php ③ post-session hook (authorization checks, etc.)
└─ public/_router.php ④ dispatch — default implementation uses TemplateLoader::content()
→ executes public/<URL path>.php
The three hooks run at distinct stages of the request lifecycle.
| File | Stage | Purpose |
|---|---|---|
_entry.php |
Before session | Site metadata, response headers, locale |
_prepare.php |
After session | Authentication/authorization checks, shared data loading |
_router.php |
Dispatch | Executes the page. Replace this file when custom routing is needed |
URL Mapping Rules
| Request URL | Executed file |
|---|---|
/ |
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 |
Request paths are normalized first by HttpUtil::normalizePath(). It removes NUL bytes, converts backslashes to /, and removes empty segments, ., and .., preventing traversal to parent directories.
TemplateLoader then resolves the final path with realpath() and includes it only after verifying that it remains inside public/ (or _Template/). Paths outside that boundary are rejected with a 404. This protection is enforced by the framework itself rather than relying solely on web-server path normalization.
The parsed result is stored in _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'
Custom Routing
To dispatch requests manually instead of using file mapping, replace 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();
}