66 lines
2.5 KiB
PHP
66 lines
2.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Evomedien\Vitec\Middleware;
|
|
|
|
use Evomedien\Vitec\Service\DownloadFileResolver;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use Psr\Http\Server\MiddlewareInterface;
|
|
use Psr\Http\Server\RequestHandlerInterface;
|
|
use TYPO3\CMS\Core\Http\Response;
|
|
use TYPO3\CMS\Core\Http\Stream;
|
|
|
|
/**
|
|
* Forced file download for download records, two routes:
|
|
*
|
|
* /download/<slug> - canonical, human-readable (search results, sharing)
|
|
* /download/file/<uid> - legacy, kept because the "Download" record links
|
|
* from the link browser build exactly this path
|
|
* (config.recordLinks.download)
|
|
*
|
|
* A direct fileadmin URL would open PDFs inline; this endpoint streams the
|
|
* file with Content-Disposition: attachment, so the browser saves it.
|
|
*
|
|
* The file lookup lives in Service\DownloadFileResolver (FAL -> Collateral
|
|
* naming convention -> filepath column), which also refuses records flagged
|
|
* private_download. Unknown uid/slug, hidden or private record or missing
|
|
* file fall through to the regular pipeline - the reply is then the normal
|
|
* 404 page, never a broken download.
|
|
*/
|
|
final class DownloadFileMiddleware implements MiddlewareInterface
|
|
{
|
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
|
{
|
|
try {
|
|
$path = $request->getUri()->getPath();
|
|
|
|
$file = null;
|
|
if (preg_match('#^/download/file/(\\d+)/?$#', $path, $matches) === 1) {
|
|
$file = DownloadFileResolver::resolve((int)$matches[1]);
|
|
} elseif (preg_match('#^/download/([a-z0-9\\-]+)/?$#', $path, $matches) === 1) {
|
|
$file = DownloadFileResolver::resolveBySlug($matches[1]);
|
|
}
|
|
|
|
if ($file !== null) {
|
|
$filename = str_replace(['"', "\r", "\n"], '', $file['name']);
|
|
|
|
return new Response(
|
|
new Stream($file['path'], 'rb'),
|
|
200,
|
|
[
|
|
'Content-Type' => $file['mimeType'] !== '' ? $file['mimeType'] : 'application/octet-stream',
|
|
'Content-Length' => (string)$file['size'],
|
|
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
|
|
]
|
|
);
|
|
}
|
|
} catch (\Throwable $e) {
|
|
// fall through to the regular pipeline
|
|
}
|
|
|
|
return $handler->handle($request);
|
|
}
|
|
}
|