Initial Version
This commit is contained in:
78
core/lib/Http/Response/FileResponse.php
Normal file
78
core/lib/Http/Response/FileResponse.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user