我有一个在 TYPO3 中具有下载操作的控制器。一段时间以来,我已经像这样实现它并且它正在工作:
function downloadAction() {
// ...
// send headers ...
// ...
if ($fh = fopen($this->file, 'r')) {
while (!feof($fh)) {
echo fread($fh, $chunkSize); // send file in little chunks to output buffer
flush();
}
fclose($fh);
}
exit; // Stopp middlewares and so on.
}
我想知道我是否应该/可以在 TYPO3 11 中返回一个 ResponseInterface 类型的对象。所以很明显
exit
停止了中间件管道和其他东西,我真的不知道是否有任何副作用。
我尝试了以下方法来返回 ResponseInterface:
function downloadAction(): ResponseInterface {
// ...
return $this->responseFactory->createResponse();
->withAddedHeader(...)
// ...
->withBody($this->streamFactory->createStreamFromFile($this->file))
->withStatus(200, 'OK');
}
问题是使用 ResponseInterface 的解决方案仅适用于小文件。问题似乎出在
Bootstrap::handleFrontendRequest()
。
protected function handleFrontendRequest(ServerRequestInterface $request): string
{
// ...
if (headers_sent() === false) {
// send headers
}
$body = $response->getBody(); // get the stream
$body->rewind();
$content = $body->getContents(); // Problem: Read the hole stream into RAM instead of
// sending it in chunks to the output buffer
// ...
return $content;
}
TYPO3 尝试将整个流/文件读入 RAM。这会使应用程序崩溃。
那么现在我应该如何使用 TYPO3 触发文件下载呢?
使用方法
\TYPO3\CMS\Core\Resource\ResourceStorage::streamFile
创建一个响应,该响应将发出文件内容 而无需先将其读入变量并抛出 ImmediateResponseException
来规避 extbase 引导响应处理。顺便说一句:这仅适用于支持正确流式传输的 FAL 驱动程序。 EXT
aus_driver_amazon_s3
没有。示例
<?php
use TYPO3\CMS\Core\Http\ImmediateResponseException;
use TYPO3\CMS\Core\Resource\ResourceStorage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class ExtbaseController extends ActionController
{
public function emitFile(): never // never return type requires PHP 8.1
{
$resourceStorage = GeneralUtility::makeInstance(ResourceStorage::class);
$file = $resourceStorage->getFile('1:/myBigFile.zip');
$response = $resourceStorage->streamFile($file, true);
throw new ImmediateResponseException($response);
}
}
编辑:由于您要跳过 extbase 关闭过程,因此您要么不得更新任何域模型,要么手动刷新持久性管理器。