Files
server/core/lib/Http/Response/FileResponse.php
2025-12-21 10:09:54 -05:00

79 lines
2.5 KiB
PHP

<?php
declare(strict_types = 1);
namespace KTXC\Http\Response;
/**
* Simple file response that reads a file from disk and serves it.
*
* Only supports sending full file contents (no range / streaming for now).
*/
class FileResponse extends Response
{
private string $filePath;
public function __construct(string $filePath, int $status = 200, array $headers = [])
{
if (!is_file($filePath) || !is_readable($filePath)) {
throw new \InvalidArgumentException(sprintf('FileResponse: file not found or not readable: %s', $filePath));
}
$this->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;
}
}