Description Summary
Extension: beechit/fal-securedownload
TYPO3 version: 12 LTS
PHP version: 8.2
Storage driver: Local file system
Issue: Enabling the “resumable download” option corrupts binary file delivery (e.g., .xls)
Steps to Reproduce
Install/enable fal_securedownload on a TYPO3 v12 site.
Set EXTENSIONS > fal_securedownload > resumable_download = 1.
Protect a binary file (e.g., .xls) and request it via index.php?eID=dumpFile&f=...&token=....
Open the downloaded file in the corresponding application (Excel).
Expected Result
TYPO3 returns the file through a PSR-7 ResponseInterface, with correct Content-Type, Content-Disposition, and Content-Length.
The file opens without errors or “repaired file” warnings.
Actual Result
The response is generated via manual header() / print output in ModifyFileDumpEventListener::dumpFileContents().
Downloads contain corrupt bytes; Excel reports “file was repaired” and strips formatting.
Curl traces show inconsistencies in Content-Length and leading bytes compared to the original file.
Environment Details
TYPO3: 12.4.37
fal_securedownload: 5.0.7
PHP: 8.2.x FPM
Web server: Apache/2.4.59
Compression: zlib.output_compression off
Workaround
Set resumable_download = 0, which forces TYPO3 to use the core streamFile() response and resolves the corruption.
Suspected Root Cause
The resumable branch bypasses TYPO3’s PSR-7 streaming:
Manually emits headers (header(), Content-Length, Accept-Ranges).
Uses ob_clean(), while (ob_get_level()) { ob_end_clean(); }, fread() loop, and print.
Calls exit, preventing further middleware cleanup.
Any earlier output (BOM/whitespace/cookies) or header injection results in file corruption.
Proposed Fix / Ideas
Replace the manual streaming logic with a PSR-7 compliant implementation:
Use $event->setResponse($streamingResponse) with a StreamInterface that supports ranges.
Avoid direct header() calls; rely on ResponseInterface::withHeader.
Remove global exit usage and depend on the event response.
Alternatively, disable resumables by default until a PSR-7 approach is implemented.
Reactions are currently unavailable
You can’t perform that action at this time.
Summary
beechit/fal-securedownload.xls)Steps to Reproduce
fal_securedownloadon a TYPO3 v12 site.EXTENSIONS > fal_securedownload > resumable_download = 1..xls) and request it viaindex.php?eID=dumpFile&f=...&token=....Expected Result
ResponseInterface, with correctContent-Type,Content-Disposition, andContent-Length.Actual Result
header()/printoutput inModifyFileDumpEventListener::dumpFileContents().Content-Lengthand leading bytes compared to the original file.Environment Details
fal_securedownload: 5.0.7zlib.output_compressionoffWorkaround
resumable_download = 0, which forces TYPO3 to use the corestreamFile()response and resolves the corruption.Suspected Root Cause
header(),Content-Length,Accept-Ranges).ob_clean(),while (ob_get_level()) { ob_end_clean(); },fread()loop, andprint.exit, preventing further middleware cleanup.Proposed Fix / Ideas
$event->setResponse($streamingResponse)with aStreamInterfacethat supports ranges.header()calls; rely onResponseInterface::withHeader.exitusage and depend on the event response.