To use the private:// scheme of Drupal 8 I had to :

  • Create a folder outside the docroot folder
  • Implement a $settings['file_private_path'] = '../private-files'; to designate this folder
  • Make sure authorization matches the website user to write into it

Then I load the filesystem helper (I could use injection dependency but that is not the point here) :

$this->filesystem = \Drupal::service('file_system');

Prepare the directory in case it does not exists :

$this->filesystem->prepareDirectory('private://any_folder', FileSystemInterface::CREATE_DIRECTORY);

And then I could save a (unmanaged) file:

$this->filesystem->saveData(json_encode(['My Beautiful File Body']), 'private://any_folder/any_file.json', FileSystemInterface::EXISTS_REPLACE);

And this works fine.

But to load the file, I would have expected to have an "opposite" (say, loadData() ) method in $this->filesystem.

And as the file is unmanaged (which is fine) I cannout use File Entity::load() to load it.

So I end up with :

$loadedFile = json_decode(file_get_contents('private://any_folder/any_file.json'), JSON_OBJECT_AS_ARRAY);

Which works fine, but raises questions :

  • Is this a legitimate way to do it (meaning, using a Drupal helper to save a file, then loading it from a straight PHP function) ?

  • Why there is no loadData() method in the FileSystem service as I would have expected ?

  • How does the Drupal scheme 'public:// or private://) is resolved from this PHP function ?

1 Answer 1


To answer your questions in respective order:

  • Sure. If there's no built-in API function to make it easier, there's nothing wrong with using file_get_contents since the function can use Drupal's file stream protocols. The core test, FileSaveDataTest::testFileSaveData(), is doing this to confirm that saveData() works.
  • One can only guess about the requirements as the class was composed. saveData() is a wrapper around a file_put_contents() op so that logging can take place when Drupal writes to a temp file. Perhaps there was no need to wrap file_get_contents in the same way?
  • Drupal has a StreamWrapperManager service class that registered different custom myscheme:// streams with PHP. This manager makes use of core PHP function stream_wrapper_register() to register any injected class that has the tags: { name: stream_wrapper, scheme: myscheme }. For example, look at CoreServiceProvider::register() which registers the private:// scheme when it detects file_private_path settings has been set.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.