Working with files, folders and file references
This chapter provides some examples about interacting with file, folder and file reference objects.
Getting a file
By uid
A file can be retrieved using its uid:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\ResourceFactory;
final class MyClass
{
public function __construct(
private readonly ResourceFactory $resourceFactory,
) {}
public function doSomething(): void
{
// Get the file object with uid=4
try {
/** @var File $file */
$file = $this->resourceFactory->getFileObject(4);
} catch (FileDoesNotExistException $e) {
// ... do some exception handling
}
// ... more logic
}
}
By its combined identifier
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\ProcessedFile;
use TYPO3\CMS\Core\Resource\ResourceFactory;
final class MyClass
{
public function __construct(
private readonly ResourceFactory $resourceFactory,
) {}
public function doSomething(): void
{
// Get the file object by combined identifier "1:/foo.txt"
/** @var File|ProcessedFile|null $file */
$file = $this->resourceFactory->getFileObjectFromCombinedIdentifier('1:/foo.txt');
// ... more logic
}
}
The syntax of argument 1 for get
is
[[storage uid]:]<file identifier>
The storage uid is optional. If it is not specified, the default storage "0"
will be assumed initially. The default storage is virtual with $uid === 0
in its class \TYPO3\
. In this case the
local filesystem is checked for the given file. The file identifier is the local
path and filename relative to the TYPO3 fileadmin/
folder.
Example: /some_
, if the file
/absolute/
exists on the
file system.
The file can be accessed from the default storage, if it exists under the given
local path in fileadmin/
. In case the file is not found, a search for
another storage best fitting to this local path will be started. Afterwards, the
file identifier is adapted accordingly inside of TYPO3 to match the new
storage's base path.
By filename from its folder
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\InaccessibleFolder;
use TYPO3\CMS\Core\Resource\ProcessedFile;
use TYPO3\CMS\Core\Resource\StorageRepository;
final class MyClass
{
public function __construct(
private readonly StorageRepository $storageRepository,
) {}
public function doSomething(): void
{
$defaultStorage = $this->storageRepository->getDefaultStorage();
try {
/** @var Folder|InaccessibleFolder $folder */
$folder = $defaultStorage->getFolder('/some/path/in/storage/');
/** @var File|ProcessedFile|null $file */
$file = $folder->getStorage()->getFileInFolder('example.ext', $folder);
} catch (InsufficientFolderAccessPermissionsException $e) {
// ... do some exception handling
}
// ... more logic
}
}
By its filename from the folder object
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\InaccessibleFolder;
use TYPO3\CMS\Core\Resource\StorageRepository;
final class MyClass
{
public function __construct(
private readonly StorageRepository $storageRepository,
) {}
public function doSomething(): void
{
$defaultStorage = $this->storageRepository->getDefaultStorage();
try {
/** @var Folder|InaccessibleFolder $folder */
$folder = $defaultStorage->getFolder('/some/path/in/storage/');
/** @var File|null $file */
$file = $folder->getFile('filename.ext');
} catch (InsufficientFolderAccessPermissionsException $e) {
// ... do some exception handling
}
// ... more logic
}
}
Copying a file
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\InaccessibleFolder;
use TYPO3\CMS\Core\Resource\StorageRepository;
final class MyClass
{
public function __construct(
private readonly StorageRepository $storageRepository,
) {}
public function doSomething(): void
{
$storageUid = 17;
$someFileIdentifier = 'templates/images/banner.jpg';
$someFolderIdentifier = 'website/images/';
$storage = $this->storageRepository->getStorageObject($storageUid);
/** @var File $file */
$file = $storage->getFile($someFileIdentifier);
try {
/** @var Folder|InaccessibleFolder $folder */
$folder = $storage->getFolder($someFolderIdentifier);
/** @var File $copiedFile The new, copied file */
$copiedFile = $file->copyTo($folder);
} catch (InsufficientFolderAccessPermissionsException|\RuntimeException $e) {
// ... do some exception handling
}
// ... more logic
}
}
Deleting a file
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\StorageRepository;
final class MyClass
{
public function __construct(
private readonly StorageRepository $storageRepository,
) {}
public function doSomething(): void
{
$storageUid = 17;
$someFileIdentifier = 'templates/images/banner.jpg';
$storage = $this->storageRepository->getStorageObject($storageUid);
/** @var File $file */
$file = $storage->getFile($someFileIdentifier);
if ($file->delete()) {
// ... file was deleted successfully
} else {
// ... an error occurred
}
// ... more logic
}
}
Adding a file
This example adds a new file in the root folder of the default storage:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\StorageRepository;
final class MyClass
{
public function __construct(
private readonly StorageRepository $storageRepository,
) {}
public function doSomething(): void
{
$storage = $this->storageRepository->getDefaultStorage();
/** @var File $newFile */
$newFile = $storage->addFile(
'/tmp/temporary_file_name.ext',
$storage->getRootLevelFolder(),
'final_file_name.ext',
);
// ... more logic
}
}
The default storage uses fileadmin/
unless this was configured
differently, as explained in Storages and drivers.
So, for this example, the resulting file path would typically be
<document-
To store the file in a sub-folder use $storage->get
:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\StorageRepository;
final class MyClass
{
public function __construct(
private readonly StorageRepository $storageRepository,
) {}
public function doSomething(): void
{
$storage = $this->storageRepository->getDefaultStorage();
/** @var File $newFile */
$newFile = $storage->addFile(
'/tmp/temporary_file_name.ext',
$storage->getFolder('some/nested/folder'),
'final_file_name.ext',
);
// ... more logic
}
}
In this example, the file path would likely be
<document-
Creating a file reference
In backend context
In the backend or command line context, it is
possible to create file references using the DataHandler
(\TYPO3\
).
Assuming you have the "uid" of both the File
and whatever other item
you want to create a relation to, the following code will create
the sys_file_reference
entry and the relation to the other item (in this case a tt_
record):
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\StringUtility;
final class MyClass
{
public function __construct(
private readonly ResourceFactory $resourceFactory,
) {}
public function doSomething(): void
{
// Get file object with uid=42
$fileObject = $this->resourceFactory->getFileObject(42);
// Get content element with uid=21
$contentElement = BackendUtility::getRecord('tt_content', 21);
// Assemble DataHandler data
$newId = StringUtility::getUniqueId('NEW'); // random string prefixed with NEW
$data = [];
$data['sys_file_reference'][$newId] = [
'uid_local' => $fileObject->getUid(),
'tablenames' => 'tt_content',
'uid_foreign' => $contentElement['uid'],
'fieldname' => 'assets',
'pid' => $contentElement['pid'],
];
$data['tt_content'][$contentElement['uid']] = [
'assets' => $newId, // For multiple new references $newId is a comma-separated list
];
/** @var DataHandler $dataHandler */
// Do not inject or reuse the DataHander as it holds state!
// Do not use `new` as GeneralUtility::makeInstance handles dependencies
$dataHandler = GeneralUtility::makeInstance(DataHandler::class);
// Process the DataHandler data
$dataHandler->start($data, []);
$dataHandler->process_datamap();
// Error or success reporting
if ($dataHandler->errorLog === []) {
// ... handle success
} else {
// ... handle errors
}
}
}
The above example comes from the "examples" extension (reference: https://github.com/TYPO3-Documentation/t3docs-examples/blob/main/Classes/Controller/ModuleController.php).
Here, the 'fieldname'
'assets'
is used instead of
image
. Content elements of ctype 'textmedia' use the field 'assets'.
For another table than tt_
, you need to define
the "pid" explicitly when creating the relation:
$data['tt_address'][$address['uid']] = [
'pid' => $address['pid'],
'image' => 'NEW1234' // changed automatically
];
In frontend context
In a frontend context, the \TYPO3\
class cannot be used and there is no specific API to create a file reference.
You are on your own.
The simplest solution is to create a database entry into table sys_file_reference by using the database connection class or the query builder provided by TYPO3.
See Extbase file upload for details on how to achieve this using Extbase.
Getting referenced files
This snippet shows how to retrieve FAL items that have been attached
to some other element, in this case the media
field of the pages
table:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Core\Resource\FileReference;
use TYPO3\CMS\Core\Resource\FileRepository;
final class MyClass
{
public function __construct(
private readonly FileRepository $fileRepository,
) {}
public function doSomething(): void
{
/** @var FileReference[] $fileObjects */
$fileObjects = $this->fileRepository->findByRelation('pages', 'media', 42);
// ... more logic
}
}
where $uid
is the ID of some page. The return value is an array
of \TYPO3\
objects.
See also
See Current content object about fetching
the UID of the current tt_
object.
Get files in a folder
These would be the shortest steps to get the list of files in a given folder: get the storage, get a folder object for some path in that storage (path relative to storage root), finally retrieve the files:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Classes;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\InaccessibleFolder;
use TYPO3\CMS\Core\Resource\StorageRepository;
final class MyClass
{
public function __construct(
private readonly StorageRepository $storageRepository,
) {}
public function doSomething(): void
{
$defaultStorage = $this->storageRepository->getDefaultStorage();
try {
/** @var Folder|InaccessibleFolder $folder */
$folder = $defaultStorage->getFolder('/some/path/in/storage/');
/** @var File[] $files */
$files = $defaultStorage->getFilesInFolder($folder);
} catch (InsufficientFolderAccessPermissionsException $e) {
// ... do some exception handling
}
// ... more logic
}
}
Dumping a file via eID script
TYPO3 registers an e
script that allows dumping / downloading / referencing
files via their FAL IDs. Non-public storages use this script to make their files
available to view or download. File retrieval is done via PHP and delivered
through the e
script.
An example URL looks like this:
index.
.
Following URI parameters are available:
t
(Type): Can be one off
(sys_
),file r
(sys_
) orfile_ reference p
(sys_
)file_ processedfile f
(File): UID of tablesys_
file r
(Reference): UID of tablesys_
file_ reference p
(Processed): UID of tablesys_
file_ processedfile s
(Size): Size (width and height) of the filecv
(CropVariant): In case ofsys_
, you can assign a cropping variantfile_ reference
You have to choose one of these parameters: f
, r
or p
.
It is not possible to combine them in one request.
The parameter s
has following syntax: width:
.
You can leave this parameter empty to load the file in its original size.
The parameters width
and height
can feature the trailing
c
or m
indicator, as known from TypoScript.
The PHP class responsible for handling the file dumping is the
\TYPO3\
, which you may also use
in your code.
Changed in version 14.0
Until TYPO3 v13 generating the Hash-based Message Authentication Codes (HMACs)
was done via General
; this has been deprecated with
TYPO3 v13.1 and removed with TYPO3 v14.0. Use the
\TYPO3\
method instead.
See the following example on how to create a URI using the
File
for a sys_
record with a fixed image size:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Service;
use MyVendor\MyExtension\Domain\Model\SomeModel;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Crypto\HashService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
class SomeClass
{
public function __construct(private readonly HashService $hashService) {}
public function getPublicUrl(SomeModel $resourceObject): string
{
$queryParameterArray = ['eID' => 'dumpFile', 't' => 'f'];
$queryParameterArray['f'] = $resourceObject->getUid();
$queryParameterArray['s'] = '320c:280c';
$queryParameterArray['token'] = $this->hashService->hmac(
implode('|', $queryParameterArray),
'resourceStorageDumpFile',
);
$publicUrl = GeneralUtility::locationHeaderUrl(PathUtility::getAbsoluteWebPath(Environment::getPublicPath() . '/index.php'));
$publicUrl .= '?' . http_build_query($queryParameterArray, '', '&', PHP_QUERY_RFC3986);
return $publicUrl;
}
}
In this example, the crop variant default
and an image size of 320x280
will be applied to a sys_
record:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Service;
use MyVendor\MyExtension\Domain\Model\SomeModel;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Crypto\HashService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
class SomeClass
{
public function __construct(private readonly HashService $hashService) {}
public function getPublicUrl(SomeModel $resourceObject): string
{
$queryParameterArray = ['eID' => 'dumpFile', 't' => 'r'];
$queryParameterArray['f'] = $resourceObject->getUid();
$queryParameterArray['s'] = '320c:280c:320:280:320:280';
$queryParameterArray['cv'] = 'default';
$queryParameterArray['token'] = $this->hashService->hmac(
implode('|', $queryParameterArray),
'resourceStorageDumpFile',
);
$publicUrl = GeneralUtility::locationHeaderUrl(PathUtility::getAbsoluteWebPath(Environment::getPublicPath() . '/index.php'));
$publicUrl .= '?' . http_build_query($queryParameterArray, '', '&', PHP_QUERY_RFC3986);
return $publicUrl;
}
}
This example shows how to create a URI to load an image of
sys_
:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Service;
use MyVendor\MyExtension\Domain\Model\SomeModel;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Crypto\HashService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
class SomeClass
{
public function __construct(private readonly HashService $hashService) {}
public function getPublicUrl(SomeModel $resourceObject): string
{
$queryParameterArray = ['eID' => 'dumpFile', 't' => 'p'];
$queryParameterArray['p'] = $resourceObject->getUid();
$queryParameterArray['token'] = $this->hashService->hmac(
implode('|', $queryParameterArray),
'resourceStorageDumpFile',
);
$publicUrl = GeneralUtility::locationHeaderUrl(PathUtility::getAbsoluteWebPath(Environment::getPublicPath() . '/index.php'));
$publicUrl .= '?' . http_build_query($queryParameterArray, '', '&', PHP_QUERY_RFC3986);
return $publicUrl;
}
}
The following restrictions apply:
- You cannot assign any size parameter to processed files, as they are already resized.
- You cannot apply crop variants to
sys_
andfile sys_
records, only tofile_ processedfile sys_
file_ reference