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>
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.
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;
}
}