---
title: "Working with files, folders and file references"
manual: "TYPO3 Explained"
version: "main"
permalink: "https://docs.typo3.org/permalink/t3coreapi:fal-using-fal-examples-file-folder@main"
source: "ApiOverview/Fal/UsingFal/ExamplesFileFolder.rst"
modified: "2026-09-16T13:05:25+00:00"
---

# Working with files, folders and file references

This chapter provides some examples about interacting with
[file, folder](https://docs.typo3.org/permalink/t3coreapi:fal-architecture-components-files-folders@main) and
[file reference](https://docs.typo3.org/permalink/t3coreapi:fal-architecture-components-file-references@main) objects.

-   [Getting a file](https://docs.typo3.org/permalink/t3coreapi:getting-a-file@main)
-   [Copying a file](https://docs.typo3.org/permalink/t3coreapi:copying-a-file@main)
-   [Deleting a file](https://docs.typo3.org/permalink/t3coreapi:deleting-a-file@main)
-   [Adding a file](https://docs.typo3.org/permalink/t3coreapi:adding-a-file@main)
-   [Creating a file reference](https://docs.typo3.org/permalink/t3coreapi:creating-a-file-reference@main)
-   [Getting referenced files](https://docs.typo3.org/permalink/t3coreapi:getting-referenced-files@main)
-   [Get files in a folder](https://docs.typo3.org/permalink/t3coreapi:get-files-in-a-folder@main)
-   [Dumping a file via eID script](https://docs.typo3.org/permalink/t3coreapi:dumping-a-file-via-eid-script@main)

## Getting a file

### By uid

A file can be retrieved using its uid:

**EXT:my_extension/Classes/MyClass.php**

```php
<?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

**EXT:my_extension/Classes/MyClass.php**

```php
<?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 `getFileObjectFromCombinedIdentifier()` is

```none
[[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\CMS\Core\Resource\ResourceStorage`. 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_folder/some_image.png`, if the file
`/absolute/path/to/fileadmin/some_folder/some_image.png` 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

**EXT:my_extension/Classes/MyClass.php**

```php
<?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

**EXT:my_extension/Classes/MyClass.php**

```php
<?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

**EXT:my_extension/Classes/MyClass.php**

```php
<?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

**EXT:my_extension/Classes/MyClass.php**

```php
<?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:

**EXT:my_extension/Classes/MyClass.php**

```php
<?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](https://docs.typo3.org/permalink/t3coreapi:fal-concepts-storages-drivers@main).

So, for this example, the resulting file path would typically be
`<document-root>/fileadmin/final_file_name.ext`

To store the file in a sub-folder use `$storage->getFolder()`:

**EXT:my_extension/Classes/MyClass.php**

```php
<?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-root>/fileadmin/some/nested/folder/final_file_name.ext`

### Security and consistency checks

The following methods of `\TYPO3\CMS\Core\Resource\ResourceStorage` perform
validation checks:

-   `addFile()`
-   `renameFile()`
-   `replaceFile()`
-   `addUploadedFile()`

Validation behavior:

-   Only explicitly allowed file extensions are accepted. Valid extensions must be configured in:
    [$GLOBALS\['TYPO3_CONF_VARS'\]\['SYS'\]\['textfile_ext'\]](https://docs.typo3.org/permalink/t3coreapi:confval-globals-typo3-conf-vars-sys-textfile-ext@main),
    [$GLOBALS\['TYPO3_CONF_VARS'\]\['SYS'\]\['mediafile_ext'\]](https://docs.typo3.org/permalink/t3coreapi:confval-globals-typo3-conf-vars-sys-mediafile-ext@main),
    [$GLOBALS\['TYPO3_CONF_VARS'\]\['SYS'\]\['miscfile_ext'\]](https://docs.typo3.org/permalink/t3coreapi:confval-globals-typo3-conf-vars-sys-miscfile-ext@main).
-   The file’s MIME type must match the expected file extension. For example,
    a real PNG image with a `.exe` file extension is rejected.

Feature flags controlling this behavior:

-   `security.system.enforceAllowedFileExtensions`
-   `security.system.enforceFileExtensionMimeTypeConsistency`

For controlled or low-level operations, consistency checks can be bypassed temporarily:

**EXT:my_extension/Classes/Command/ImportCommand.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Command;

class ImportCommand
{
  use \TYPO3\CMS\Core\Resource\ResourceInstructionTrait;

  protected function execute(): void
  {
    // ...

    // Skip the consistency check once for the specified storage,
    // source and target
    $this->skipResourceConsistencyCheckForCommands(
      $storage,
      $temporaryFileName,
      $targetFileName,
    );

    /** @var \TYPO3\CMS\Core\Resource\File $file */
    $file = $storage->addFile(
      $temporaryFileName,
      $targetFolder,
      $targetFileName,
    );
  }
}

```

## Creating a file reference

### In backend context

In the backend or [command line](https://docs.typo3.org/permalink/t3coreapi:symfony-console-commands@main) context, it is
possible to create file references using the [DataHandler](https://docs.typo3.org/permalink/t3coreapi:datahandler-basics@main)
(`\TYPO3\CMS\Core\DataHandling\DataHandler`).

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](https://docs.typo3.org/permalink/t3coreapi:fal-architecture-database-sys-file-reference@main)
entry and the relation to the other item (in this case a `tt_content`
record):

**EXT:my_extension/Classes/MyClass.php**

```php
<?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](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_content`, you need to define
the "pid" explicitly when creating the relation:

**EXT:my_extension/Classes/SomeClass.php**

```php
$data['tt_address'][$address['uid']] = [
    'pid' => $address['pid'],
    'image' => 'NEW1234' // changed automatically
];
```

### In frontend context

In a frontend context, the `\TYPO3\CMS\Core\DataHandling\DataHandler`
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](https://docs.typo3.org/permalink/t3coreapi:fal-architecture-database-sys-file-reference@main) by
using the [database connection](https://docs.typo3.org/permalink/t3coreapi:database-connection@main) class or the
[query builder](https://docs.typo3.org/permalink/t3coreapi:database-query-builder@main) provided by TYPO3.

See [Extbase file upload](https://docs.typo3.org/permalink/t3coreapi:extbase-domain-fileupload@main) for details on how
to achieve this using [Extbase](https://docs.typo3.org/permalink/t3coreapi:extbase-extension-framework@main).

## 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:

**EXT:my_extension/Classes/MyClass.php**

```php
<?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\CMS\Core\Resource\FileReference` objects.

> [!NOTE]
> **See also**
>
> See [Current content object](https://docs.typo3.org/permalink/t3coreapi:typo3-request-attribute-current-content-object@main) about fetching
> the UID of the current `tt_content` 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](https://docs.typo3.org/permalink/t3coreapi:fal-using-fal-examples-storage-repository@main), get
a folder object for some path in that storage (path relative to storage root),
finally retrieve the files:

**EXT:my_extension/Classes/MyClass.php**

```php
<?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 `eID` 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 `eID` script.

An example URL looks like this:
`index.php?eID=dumpFile&t=f&f=1230&token=135b17c52f5e718b7cc94e44186eb432e0cc6d2f`.

Following URI parameters are available:

-   `t` (*Type*): Can be one of `f` (`sys_file`),
    `r` (`sys_file_reference`) or `p` (`sys_file_processedfile`)
-   `f` (*File*): UID of table `sys_file`
-   `r` (*Reference*): UID of table `sys_file_reference`
-   `p` (*Processed*): UID of table `sys_file_processedfile`
-   `s` (*Size*): Size (width and height) of the file
-   `cv` (*CropVariant*): In case of `sys_file_reference`, you can
    assign a cropping variant

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:height:minW:minH:maxW:maxH`.
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\CMS\Core\Controller\FileDumpController`, which you may also use
in your code.

> [!NOTE]
> **Changed in version 14.0**
>
> Until TYPO3 v13 generating the Hash-based Message Authentication Codes (HMACs)
> was done via `GeneralUtility::hmac()`; this has been deprecated with
> TYPO3 v13.1 and removed with TYPO3 v14.0. Use the
> `\TYPO3\CMS\Core\Crypto\HashService::hmac()` method instead.

See the following example on how to create a URI using the
`FileDumpController` for a `sys_file` record with a fixed image size:

**EXT:some_extension/Classes/SomeClass.php**

```php
<?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_file_reference` record:

**EXT:some_extension/Classes/SomeClass.php**

```php
<?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_file_processedfile`:

**EXT:some_extension/Classes/SomeClass.php**

```php
<?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_file` and
    `sys_file_processedfile` records, only to `sys_file_reference`
