I would like to create a file and write some data to it using a PHP CLI script. The script will bootstrap Drupal and then use either the file_system or file.repository services to perform the task.
For sanity check, I tested the methods using Drush:
drush eval 'use Drupal\Core\File\FileSystemInterface; $fileRepository = \Drupal::service("file.repository"); $fileRepository->writeData("hello", "public://foo.txt", FileSystemInterface::EXISTS_REPLACE);'
I then created a script (saved at $DOCROOT/scripts/create-file.php):
#!/usr/bin/env php
<?php
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\File\FileSystemInterface;
// Specify relative path to the drupal root.
$autoloader = require_once __DIR__ . '/../web/autoload.php';
$request = Request::createFromGlobals();
// Bootstrap drupal to different levels
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
$kernel->boot();
/** @var \Drupal\file\FileRepositoryInterface $fileRepository */
$fileRepository = \Drupal::service('file.repository');
$fileRepository->writeData("Hello, World!", "public://foo.txt", FileSystemInterface::EXISTS_REPLACE);
I made the script executable (chmod +x scripts/create-file.php
) and ran it (./scripts/create-file.php
).
But I received a FileWriteException error: Drupal\Core\File\Exception\FileWriteException: Temporary file 'temporary://<somefile>' could not be created
. It creates a zero-byte temp file and stops there as if there are permission issues.
I confirmed the temp directory locations (in both Drupal and PHP installation): drush eval 'print \Drupal::service("file_system")->getTempDirectory();'
and php -r 'echo sys_get_temp_dir() . "\n";'
Both return /tmp
as the temporary directory.
I tested this on both a Linux server and a Docker container (DDEV instance). The behavior is the same in both. If I remove the Drupal bootstrap stuff and execute the script with drush scr
, it works (similar to the sanity check above).
Is there something preventing a shell user from executing a script that then tries to write a file?
Update:
The issue seems to exist only when using the Drupal service. For instance, the following method works:
$fp = fopen("/var/www/html/web/sites/default/files/foo.txt","wb");
fwrite($fp,$output);
fclose($fp);
Using Symfony also works:
use Symfony\Component\Filesystem\Filesystem;
$filesystem = new Filesystem();
$filesystem->dumpFile('/var/www/html/web/sites/default/files/foo.txt', $output);
But the following does not work:
$filesystem = \Drupal::service('file_system');
$filesystem->saveData($output, "/var/www/html/web/sites/default/files/foo.txt", FileSystemInterface::EXISTS_REPLACE);