1
0

harden: web/index.php — runtime fingerprint, API channel isolation, extract() safety

Three robustness improvements to the request entry point:

P1a: Module runtime stale-detection via fingerprint
- ModuleRuntimePageBuilder gains writeFingerprint/readFingerprint/expectedFingerprint
- module-build.php writes storage/runtime/.module-fingerprint after each build
- web/index.php validates fingerprint on every request; throws RuntimeException
  with actionable message if stale (replaces silent auto-build in request path)
- Eliminates P2 (concurrency) by removing build from hot path entirely

P1b: API requests skip session/auth/cookie flows
- Channel detection (isApiRequest) moved before Session::start()
- Session::start(), remember-me, session timeout, tenant refresh and locale
  resolution wrapped in if-not-API guard
- API endpoints no longer set cookies or trigger login redirects
- Default locale set separately for API so t() works in error responses

P3: extract(Router::getParameters(), EXTR_SKIP)
- Prevents URL parameters from overwriting existing scope variables

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-18 22:41:59 +01:00
parent c328067aa6
commit 476f688bd8
3 changed files with 210 additions and 145 deletions

View File

@@ -103,6 +103,44 @@ final class ModuleRuntimePageBuilder
}
}
// ── Fingerprint: detect stale runtime state ─────────────────────
/**
* Compute the expected fingerprint for a set of modules.
*
* @param array<string, ModuleManifest> $modules
*/
public static function expectedFingerprint(array $modules): string
{
$ids = array_map(static fn (ModuleManifest $m): string => $m->id, $modules);
sort($ids);
return implode(',', $ids);
}
/**
* Read the persisted fingerprint from disk.
*/
public static function readFingerprint(string $runtimeDir): string
{
$file = dirname($runtimeDir) . '/.module-fingerprint';
return is_file($file) ? trim((string) file_get_contents($file)) : '';
}
/**
* Write a fingerprint after a successful build so web/index.php can
* detect stale runtime state without rebuilding on every request.
*
* @param array<string, ModuleManifest> $modules
*/
public static function writeFingerprint(string $runtimeDir, array $modules): void
{
$file = dirname($runtimeDir) . '/.module-fingerprint';
file_put_contents($file, self::expectedFingerprint($modules));
}
private function removeDirectoryContents(string $dir): void
{
$entries = scandir($dir);