add controllers, servoices
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Files;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class FileServeService
|
||||
{
|
||||
public function meta(string $baseDir, string $name, array $allowedExtensions, ?string $downloadName = null): array
|
||||
{
|
||||
return $this->resolveFile($baseDir, $name, $allowedExtensions, $downloadName);
|
||||
}
|
||||
|
||||
public function serveInline(
|
||||
string $baseDir,
|
||||
string $name,
|
||||
array $allowedExtensions,
|
||||
Request $request,
|
||||
?string $downloadName = null,
|
||||
bool $nosniff = false
|
||||
): Response {
|
||||
$meta = $this->resolveFile($baseDir, $name, $allowedExtensions, $downloadName);
|
||||
|
||||
$ifNoneMatch = trim((string) $request->headers->get('If-None-Match', ''), '"');
|
||||
$ifModifiedSince = (string) $request->headers->get('If-Modified-Since', '');
|
||||
$imsTime = $ifModifiedSince !== '' ? strtotime($ifModifiedSince) : false;
|
||||
|
||||
if (($ifNoneMatch !== '' && $ifNoneMatch === $meta['etag']) ||
|
||||
($imsTime !== false && $imsTime >= $meta['mtime'])
|
||||
) {
|
||||
return response('', 304, $this->notModifiedHeaders($meta));
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'Content-Type' => $meta['mime'],
|
||||
'Content-Disposition' => 'inline; filename="' . $meta['download_name'] . '"',
|
||||
'Content-Length' => (string) $meta['size'],
|
||||
'ETag' => $meta['etag'],
|
||||
'Last-Modified' => $meta['last_modified'],
|
||||
'Cache-Control' => 'public, max-age=86400',
|
||||
];
|
||||
|
||||
if ($nosniff) {
|
||||
$headers['X-Content-Type-Options'] = 'nosniff';
|
||||
}
|
||||
|
||||
return response(file_get_contents($meta['path']), 200, $headers);
|
||||
}
|
||||
|
||||
private function resolveFile(string $baseDir, string $name, array $allowedExtensions, ?string $downloadName): array
|
||||
{
|
||||
if ($name !== basename($name)) {
|
||||
throw new HttpException(400, 'Invalid filename');
|
||||
}
|
||||
|
||||
$ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
|
||||
if (!in_array($ext, $allowedExtensions, true)) {
|
||||
throw new HttpException(404, 'File not found');
|
||||
}
|
||||
|
||||
$path = rtrim($baseDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $name;
|
||||
if (!is_file($path)) {
|
||||
throw new HttpException(404, 'File not found');
|
||||
}
|
||||
|
||||
$mime = $this->detectMime($path);
|
||||
$mtime = filemtime($path) ?: time();
|
||||
$size = filesize($path) ?: 0;
|
||||
$etag = md5($name . '|' . $mtime . '|' . $size);
|
||||
$downloadName = $downloadName ? $downloadName . '.' . $ext : $name;
|
||||
|
||||
return [
|
||||
'name' => $name,
|
||||
'path' => $path,
|
||||
'mime' => $mime,
|
||||
'mtime' => $mtime,
|
||||
'size' => $size,
|
||||
'etag' => $etag,
|
||||
'download_name' => $downloadName,
|
||||
'last_modified' => gmdate('D, d M Y H:i:s', $mtime) . ' GMT',
|
||||
];
|
||||
}
|
||||
|
||||
private function detectMime(string $path): string
|
||||
{
|
||||
$mime = 'application/octet-stream';
|
||||
if (function_exists('finfo_open')) {
|
||||
$fi = finfo_open(FILEINFO_MIME_TYPE);
|
||||
if ($fi) {
|
||||
$detected = finfo_file($fi, $path);
|
||||
if ($detected) {
|
||||
$mime = $detected;
|
||||
}
|
||||
finfo_close($fi);
|
||||
}
|
||||
} elseif (function_exists('mime_content_type')) {
|
||||
$mime = mime_content_type($path) ?: $mime;
|
||||
}
|
||||
|
||||
return $mime;
|
||||
}
|
||||
|
||||
private function notModifiedHeaders(array $meta): array
|
||||
{
|
||||
return [
|
||||
'ETag' => $meta['etag'],
|
||||
'Last-Modified' => $meta['last_modified'],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user