55 lines
1.6 KiB
PHP
55 lines
1.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once dirname(__DIR__, 2) . '/src/App/bootstrap.php';
|
|
|
|
use App\AppPaths;
|
|
use ModulesCore\ModuleRegistry;
|
|
|
|
$projectRoot = dirname(__DIR__, 2);
|
|
$module = trim((string) ($_GET['module'] ?? ''));
|
|
$path = trim((string) ($_GET['path'] ?? ''));
|
|
|
|
if ($module === '' || $path === '' || str_contains($path, '..')) {
|
|
http_response_code(400);
|
|
exit('Invalid module asset request.');
|
|
}
|
|
|
|
$registry = new ModuleRegistry(AppPaths::customAppsRoot($projectRoot));
|
|
$modulePath = $registry->modulePath($module);
|
|
|
|
if ($modulePath === null) {
|
|
http_response_code(404);
|
|
exit('Module not found.');
|
|
}
|
|
|
|
$assetPath = realpath($modulePath . '/' . ltrim($path, '/'));
|
|
$allowedRoot = realpath($modulePath);
|
|
|
|
if ($assetPath === false || $allowedRoot === false || !str_starts_with($assetPath, $allowedRoot . DIRECTORY_SEPARATOR) || !is_file($assetPath)) {
|
|
http_response_code(404);
|
|
exit('Asset not found.');
|
|
}
|
|
|
|
$extension = strtolower(pathinfo($assetPath, PATHINFO_EXTENSION));
|
|
$contentType = match ($extension) {
|
|
'css' => 'text/css; charset=utf-8',
|
|
'js' => 'application/javascript; charset=utf-8',
|
|
'json' => 'application/json; charset=utf-8',
|
|
'svg' => 'image/svg+xml',
|
|
'png' => 'image/png',
|
|
'jpg', 'jpeg' => 'image/jpeg',
|
|
'gif' => 'image/gif',
|
|
'webp' => 'image/webp',
|
|
default => 'application/octet-stream',
|
|
};
|
|
|
|
$mtime = filemtime($assetPath);
|
|
if ($mtime !== false) {
|
|
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $mtime) . ' GMT');
|
|
}
|
|
header('Content-Type: ' . $contentType);
|
|
header('Cache-Control: public, max-age=300');
|
|
readfile($assetPath);
|