如何使用typo3 extbase控制器操作下载(大)文件

问题描述 投票:0回答:2

我有一个在 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 触发文件下载呢?

download typo3 large-files extbase
2个回答
1
投票

使用方法

\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 关闭过程,因此您要么不得更新任何域模型,要么手动刷新持久性管理器。


0
投票
我认为,ResourceStorage 可能无法以这种方式工作,因为构造函数至少需要参数。

© www.soinside.com 2019 - 2024. All rights reserved.