filePath = $filePath; // Determine content type (very small helper; rely on common extensions) $mime = self::guessMimeType($filePath) ?? 'application/octet-stream'; $headers['Content-Type'] = $headers['Content-Type'] ?? $mime; $headers['Content-Length'] = (string) filesize($filePath); $headers['Last-Modified'] = gmdate('D, d M Y H:i:s', filemtime($filePath)) . ' GMT'; $headers['Cache-Control'] = $headers['Cache-Control'] ?? 'public, max-age=60'; parent::__construct('', $status, $headers); // Defer reading file until sendContent to avoid memory usage. } public function getFilePath(): string { return $this->filePath; } public function sendContent(): static { // Output file contents directly readfile($this->filePath); return $this; } private static function guessMimeType(string $filePath): ?string { $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION)); return match ($ext) { 'html', 'htm' => 'text/html; charset=UTF-8', 'css' => 'text/css; charset=UTF-8', 'js' => 'application/javascript; charset=UTF-8', 'json' => 'application/json; charset=UTF-8', 'png' => 'image/png', 'jpg', 'jpeg' => 'image/jpeg', 'gif' => 'image/gif', 'svg' => 'image/svg+xml', 'txt' => 'text/plain; charset=UTF-8', 'xml' => 'application/xml; charset=UTF-8', default => self::finfoMime($filePath), }; } private static function finfoMime(string $filePath): ?string { if (function_exists('finfo_open')) { $f = finfo_open(FILEINFO_MIME_TYPE); if ($f) { $mime = finfo_file($f, $filePath) ?: null; finfo_close($f); return $mime; } } return null; } }