ziptypo3php-7.4typo3-11.xfilereference

TYPO3V11 - fileReference: how to get files to create a ZIP


I’m relatively new to TYPO3 and currently managing a website built on this CMS. Since I have limited experience, I would greatly appreciate any assistance or guidance you can provide.

Thank you in advance!

I have array, use TYPO3-11.5.39, PHP-7.4.32.

<f:for each="{detail.images}" as="file">
<f:link.file file="{file.originalResource}" download="true" filename="{file.originalResource.properties.name}">Download file</f:link.file>                  
</f:for>

enter image description here enter image description here

I need to convert this array to another array to create an archive. Here is my controller. The function is tested, the archive is created with constant values. But I can't get files from TYPO3.

<?php

declare(strict_types=1);

namespace Vendor\extName\Controller;

use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Resource\FileReference;
use ZipArchive;



class DownloadController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
    /**
     * Download action to create and download a zip file of images
     *
     * @return void
     */


    public function downloadZipAction(): void
    {

       
        $files = [];

        foreach ($this->detail->images as $fileReference) {
            if ($fileReference instanceof \TYPO3\CMS\Extbase\Domain\Model\FileReference) {
                $file = $fileReference->getOriginalResource();

                if ($file instanceof \TYPO3\CMS\Core\Resource\FileReference) {
                    $identifier = $file->getIdentifier();
                    if ($identifier) {
                        $files[] = ['url' => $identifier];
                    }
                }
            }
        }




        $zipFileName = tempnam(sys_get_temp_dir(), 'images_') . '.zip';

        $zip = new ZipArchive();

        if ($zip->open($zipFileName, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
            die('Could not create ZIP file.' );
        }

        foreach ($files as $file) {
            $fileContent = @file_get_contents($file); /
            if ($fileContent === false) {
                echo "Failed to fetch file:";
                continue; 
            }
            $fileName = basename($file);
            if (!$zip->addFromString($fileName, $fileContent)) {
                echo "Failed to add file: $fileName";
            }
        }

        $zip->close();

        if (!file_exists($zipFileName) || filesize($zipFileName) == 0) {
            unlink($zipFileName); 
            die('Failed to create a non-empty ZIP file.  ' );
        }

        header('Content-Type: application/zip');
        header('Content-Disposition: attachment; filename="images.zip"');
        header('Content-Length: ' . filesize($zipFileName));

        readfile($zipFileName);

        unlink($zipFileName);
        exit;
    }

}

My Fluid Template

                <f:link.action action="downloadZip" controller="Download" arguments="{detail: detail}" target="_blank">
                    Download Images as ZIP
                </f:link.action>

The controller works, but I get an empty archive.


Solution

  • I think the issue was that you created an array with a "url" substructure, but when you iterated it, you did not utilize that. Also the file path was not using an absolute directory. Please see the updated code, I've placed "@NEW" annotation to see the difference to your implementation. Hope it helps!

    <?php declare(strict_types=1);
    
    namespace Vendor\extName\Controller;
    
    use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
    use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
    // @NEW: Import this for access to base directory
    use TYPO3\CMS\Core\Core\Environment;
    use TYPO3\CMS\Core\Utility\GeneralUtility;
    use TYPO3\CMS\Core\Resource\ResourceFactory;
    use TYPO3\CMS\Core\Resource\FileReference;
    use ZipArchive;
    
    class DownloadController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
    {
        /**
         * Download action to create and download a zip file of images
         *
         * @return void
         */
        public function downloadZipAction(): void
        {
            $files = [];
    
            foreach ($this->detail->images as $fileReference) {
                if ($fileReference instanceof \TYPO3\CMS\Extbase\Domain\Model\FileReference) {
                    $file = $fileReference->getOriginalResource();
    
                    if ($file instanceof \TYPO3\CMS\Core\Resource\FileReference) {
                        $identifier = $file->getIdentifier();
                        if ($identifier) {
                            // @NEW: No longer use 'url' subkey, and create a full path instread.
                                $files[] = Environment::getPublicPath() . $file->getOriginalFile()->getPublicUrl();
                        }
                    }
                }
            }
    
            $zipFileName = tempnam(sys_get_temp_dir(), 'images_') . '.zip';
            $zip = new ZipArchive();
    
            if ($zip->open($zipFileName, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
                die('Could not create ZIP file.' );
            }
    
            foreach ($files as $file) {
                $fileContent = @file_get_contents($file);
                if ($fileContent === false) {
                    echo "Failed to fetch file:";
                    continue; 
                }
                $fileName = basename($file);
                if (!$zip->addFromString($fileName, $fileContent)) {
                    echo "Failed to add file: $fileName";
                }
            }
    
            $zip->close();
    
            // @NEW: Split these checks, because 'unlink' on a non-existing otherwise
            if (!file_exists($zipFileName)) {
                die('Failed to create ZIP file.');
            }
    
            if (filesize($zipFileName) == 0) {
                unlink($zipFileName); 
                die('Failed to create a non-empty ZIP file.');
            }
    
            header('Content-Type: application/zip');
            header('Content-Disposition: attachment; filename="images.zip"');
            header('Content-Length: ' . filesize($zipFileName));
    
            readfile($zipFileName);
            unlink($zipFileName);
    
            exit;
        }
    }