Leuchtfeuer/typo3-secure-downloads

Re-enable chunking option for file delivery

Closed this issue · 4 comments

I think secure_downloads makes a serious effort on extending the functionality of typo3 when it comes to protecting downloads. As it already hooks into the generation of Urls and the file delivery, a seconday use case was to provide alternative methods for file delivery. AFAIK, typo3 does not natively support a chunked file delivery. This causes problems if you have large files in a non-public storage: At once point the PHP process will hit its memory limit.

Previous versions of secure_downloads (up to 4.1.0) have supported a chunked file delivery that reduced the memory requirement significantly to enable the (protected) download of large files. However, for some reason it was removed in 4.1.1.

I therefore suggest to re-enable this option. If there are some mechanisms in typo3 core already that I don't know of, some guidelines for how to deal with large files would be helpful.

Hi,

I also run in this issue. The following hack makes it working again (tested with version 4.1.1):
Under /Classes/Resource/FileDelivery.php replace the deliver()-function with the following:

    /**
     * Output the requested file
     */
    public function deliver()
    {
        $file = GeneralUtility::getFileAbsFileName(ltrim($this->file, '/'));
        $fileName = basename($file);
        // This is a workaround for a PHP bug on Windows systems:
        // @see http://bugs.php.net/bug.php?id=46990
        // It helps for filenames with special characters that are present in latin1 encoding.
        // If you have real UTF-8 filenames, use a nix based OS.
        if (Environment::isWindows()) {
            $file = utf8_decode($file);
        }
        $this->dispatchAfterFileRetrievedEvent($file, $fileName);
        if (file_exists($file)) {
            $this->fileSize = filesize($file);
            $fileExtension = pathinfo($file, PATHINFO_EXTENSION);
            $forceDownload = $this->shouldForceDownload($fileExtension);
            $mimeType = MimeTypeUtility::getMimeType($file) ?? 'application/octet-stream';

            // Hook for output:
            // TODO: This hook is deprecated and will be removed with version 5. Use 'preReadFile' hook instead.
            // TODO: Remove the pObj property with version 5.
            $params = ['pObj' => &$this, 'fileExtension' => '.' . $fileExtension, 'mimeType' => &$mimeType];
            HookUtility::executeHook('output', 'output', $params, $this);

            $header = $this->getHeader($mimeType, $fileName, $forceDownload);
            $outputFunction = $this->extensionConfiguration->getOutputFunction();

            $this->dispatchBeforeFileDeliverEvent($outputFunction, $header, $fileName, $mimeType, $forceDownload);

            if ($this->isProcessed === false && $this->extensionConfiguration->isLog()) {
                $this->logDownload($this->fileSize, $mimeType);
            }

            foreach($header as $key => $value) {
                header($key . ': ' . $value);
            }

            if ($this->shouldStreamFile($outputFunction)) {
                $this->streamFile($file);
            } else {
                readfile ($file);
            }
            // make sure we can detect an aborted connection, call flush
            ob_flush();
            flush();
        } else {
            print 'File does not exist!';
        }

Does this problem still exist? Then I would need more information to reproduce it.

Can the problem be solved if "delivery.outputFunction" is set to "fpassthru"? With the #102 error, I then had no problems with large videos.

It works on Version v5.0.0-rc1 in my case. So imho this can get closed.