by finne on 12-12-2017

Handling files in Drupal 8

Files in Drupal 8 are usually thought of as entities. However the entity only stores metadata about the file (in the database). The file data itself is stored directly on a drive somewhere. There are three basic components when dealing with files in Drupal 8:

  1. The file (data) itself, as saved in a location on disk somewhere.
  2. The file entity, a Drupal 8 Content Entity that is saved in the database.
  3. The file usage service, a Drupal 8 Service that tracks a file's usage, stored in the database.

If you are creating a new file, you first save the incoming file (data) to a disk location. Drupal has three default locations:

  • temporary://
    • defaults to the operating system temp dir (/tmp).
    • /tmp is periodically wiped by the OS.
    • can be set via /admin/config/media/file-system
  • public://
    • defaults to sites/default/files
    • can be set in settings.php
    • is the default scheme (can be changed in /admin/config/media/file-system)
  • private://
    • not set by default
    • can be set in settings.php

Next create a file entity that references the new file on the filesystem. The file entity can have a status set to temporary or permanent. NB: temporary files are not necessary located in temporary://. Temporary file entities are periodically (see /admin/config/media/file-system, defaults to 6 hours) removed from the system if they are not flagged 'in use' by the file.usage service.

Finally –if applicable– mark the file as in use by your module using the file.usage Service.

\Drupal::service('file.usage')->add();

This sets the file status to permanent. If you use the file.usage Service delete() function to remove a usage flag, and bring the usage count to zero, the file is marked as temporary, and can be removed by the garbage collection process.

file functions

The various functions Drupal 8 offers to use for manipulating files have different applications. Some only manage the file, others also the file entity. 

  • core/includes/file.inc
    • file_unmanaged_save_data()
      • saves data in temporary:// location
      • calls file_unmanaged_move()
    • file_unmanaged_move()
      • defaults to public:// location
    • file_unmanaged_copy()
      • defaults to public:// location
  • core/modules/file/file.module
    • file_save_data()
      • defaults to default scheme location and sets file status permanent
    • file_managed_file_save_upload()
      • sets destination from form data
      • calls file_save_upload()
    • file_save_upload()
      • defaults to temporary:// location and sets file status temporary
  • \Drupal\Core\File\FileSystem
    • moveUploadedFile()
      • wraps php function without calling Drupal API's

Image Styles

If the file you are manipulating happens to be an image, you would expect the Drupal Image module (ImageStyle class) to automatically create thumbnails and other derivatives. It does this on the fly when an image style request is send to Drupal.

For public:// files the dynamic route provider \Drupal\image\Routing\ImageStyleRoutes provides routes for public files. The controller Drupal\image\Controller\ImageStyleDownloadController then generates the image derivative if it does not exist.

For private:// files the image.style_private route points to the same controller as the public:// above.

Gotcha: for temporary:// files the ImageStyle system does nothing. All image derivatives will be missing and not automatically created. Manually created image derivatives (using \Drupal\image\Entity\ImageStyle::createDerivative()) still work within the temporary:// location.

about the author

Finne Fortuin is a Drupal 8 expert who dabbles in image manipulation.

Finne