Issue #2244513 by kim.pepper, phenaproxima, 20th, andrei.dincu, beejeebus, Berdir, alexpott, jibran, andypost, larowlan, Chadwick Wood, acbramley, Wim Leers, sun, xjm, YesCT, chx, tim.plunkett: Move the unmanaged file APIs to the file_system service (file.inc)

8.7.x
Alex Pott 2019-02-23 22:35:15 +00:00
parent d8b8a0aa26
commit 76bf269417
No known key found for this signature in database
GPG Key ID: 31905460D4A69276
98 changed files with 1636 additions and 498 deletions

View File

@ -1565,25 +1565,27 @@ services:
arguments: [ '@state' ] arguments: [ '@state' ]
asset.css.collection_optimizer: asset.css.collection_optimizer:
class: Drupal\Core\Asset\CssCollectionOptimizer class: Drupal\Core\Asset\CssCollectionOptimizer
arguments: [ '@asset.css.collection_grouper', '@asset.css.optimizer', '@asset.css.dumper', '@state' ] arguments: [ '@asset.css.collection_grouper', '@asset.css.optimizer', '@asset.css.dumper', '@state', '@file_system']
asset.css.optimizer: asset.css.optimizer:
class: Drupal\Core\Asset\CssOptimizer class: Drupal\Core\Asset\CssOptimizer
asset.css.collection_grouper: asset.css.collection_grouper:
class: Drupal\Core\Asset\CssCollectionGrouper class: Drupal\Core\Asset\CssCollectionGrouper
asset.css.dumper: asset.css.dumper:
class: Drupal\Core\Asset\AssetDumper class: Drupal\Core\Asset\AssetDumper
arguments: ['@file_system']
asset.js.collection_renderer: asset.js.collection_renderer:
class: Drupal\Core\Asset\JsCollectionRenderer class: Drupal\Core\Asset\JsCollectionRenderer
arguments: [ '@state' ] arguments: [ '@state' ]
asset.js.collection_optimizer: asset.js.collection_optimizer:
class: Drupal\Core\Asset\JsCollectionOptimizer class: Drupal\Core\Asset\JsCollectionOptimizer
arguments: [ '@asset.js.collection_grouper', '@asset.js.optimizer', '@asset.js.dumper', '@state' ] arguments: [ '@asset.js.collection_grouper', '@asset.js.optimizer', '@asset.js.dumper', '@state', '@file_system']
asset.js.optimizer: asset.js.optimizer:
class: Drupal\Core\Asset\JsOptimizer class: Drupal\Core\Asset\JsOptimizer
asset.js.collection_grouper: asset.js.collection_grouper:
class: Drupal\Core\Asset\JsCollectionGrouper class: Drupal\Core\Asset\JsCollectionGrouper
asset.js.dumper: asset.js.dumper:
class: Drupal\Core\Asset\AssetDumper class: Drupal\Core\Asset\AssetDumper
arguments: ['@file_system']
library.discovery: library.discovery:
class: Drupal\Core\Asset\LibraryDiscovery class: Drupal\Core\Asset\LibraryDiscovery
arguments: ['@library.discovery.collector'] arguments: ['@library.discovery.collector']

View File

@ -6,13 +6,16 @@
*/ */
use Drupal\Component\FileSystem\FileSystem as ComponentFileSystem; use Drupal\Component\FileSystem\FileSystem as ComponentFileSystem;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\PhpStorage\FileStorage; use Drupal\Component\PhpStorage\FileStorage;
use Drupal\Component\Utility\Bytes; use Drupal\Component\Utility\Bytes;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\Exception\FileWriteException;
use Drupal\Core\File\FileSystem; use Drupal\Core\File\FileSystem;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Site\Settings; use Drupal\Core\Site\Settings;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\StreamWrapper\PrivateStream; use Drupal\Core\StreamWrapper\PrivateStream;
use Drupal\Core\StreamWrapper\PublicStream;
/** /**
* Default mode for new directories. See drupal_chmod(). * Default mode for new directories. See drupal_chmod().
@ -41,29 +44,44 @@ const FILE_CHMOD_FILE = FileSystem::CHMOD_FILE;
*/ */
/** /**
* Flag used by file_prepare_directory() -- create directory if not present. * Flag used to create a directory if not present.
*
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::CREATE_DIRECTORY.
*/ */
const FILE_CREATE_DIRECTORY = 1; const FILE_CREATE_DIRECTORY = FileSystemInterface::CREATE_DIRECTORY;
/** /**
* Flag used by file_prepare_directory() -- file permissions may be changed. * Flag used to indicate file permissions may be changed.
*
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::MODIFY_PERMISSIONS.
*/ */
const FILE_MODIFY_PERMISSIONS = 2; const FILE_MODIFY_PERMISSIONS = FileSystemInterface::MODIFY_PERMISSIONS;
/** /**
* Flag for dealing with existing files: Appends number until name is unique. * Flag for dealing with existing files: Appends number until name is unique.
*
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::EXISTS_RENAME.
*/ */
const FILE_EXISTS_RENAME = 0; const FILE_EXISTS_RENAME = FileSystemInterface::EXISTS_RENAME;
/** /**
* Flag for dealing with existing files: Replace the existing file. * Flag for dealing with existing files: Replace the existing file.
*
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::EXISTS_REPLACE.
*/ */
const FILE_EXISTS_REPLACE = 1; const FILE_EXISTS_REPLACE = FileSystemInterface::EXISTS_REPLACE;
/** /**
* Flag for dealing with existing files: Do nothing and return FALSE. * Flag for dealing with existing files: Do nothing and return FALSE.
*
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::EXISTS_ERROR.
*/ */
const FILE_EXISTS_ERROR = 2; const FILE_EXISTS_ERROR = FileSystemInterface::EXISTS_ERROR;
/** /**
* Indicates that the file is permanent and should not be deleted. * Indicates that the file is permanent and should not be deleted.
@ -288,29 +306,13 @@ function file_url_transform_relative($file_url) {
* @return * @return
* TRUE if the directory exists (or was created) and is writable. FALSE * TRUE if the directory exists (or was created) and is writable. FALSE
* otherwise. * otherwise.
*
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::prepareDirectory().
*/ */
function file_prepare_directory(&$directory, $options = FILE_MODIFY_PERMISSIONS) { function file_prepare_directory(&$directory, $options = FileSystemInterface::MODIFY_PERMISSIONS) {
if (!file_stream_wrapper_valid_scheme(\Drupal::service('file_system')->uriScheme($directory))) { @trigger_error('file_prepare_directory() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::prepareDirectory(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
// Only trim if we're not dealing with a stream. return \Drupal::service('file_system')->prepareDirectory($directory, $options);
$directory = rtrim($directory, '/\\');
}
// Check if directory exists.
if (!is_dir($directory)) {
// Let mkdir() recursively create directories and use the default directory
// permissions.
if ($options & FILE_CREATE_DIRECTORY) {
return @drupal_mkdir($directory, NULL, TRUE);
}
return FALSE;
}
// The directory exists, so check to see if it is writable.
$writable = is_writable($directory);
if (!$writable && ($options & FILE_MODIFY_PERMISSIONS)) {
return drupal_chmod($directory);
}
return $writable;
} }
/** /**
@ -452,25 +454,20 @@ function file_valid_uri($uri) {
* @return * @return
* The path to the new file, or FALSE in the event of an error. * The path to the new file, or FALSE in the event of an error.
* *
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::copy().
*
* @see file_copy() * @see file_copy()
* @see https://www.drupal.org/node/3006851
*/ */
function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) { function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
if (!file_unmanaged_prepare($source, $destination, $replace)) { @trigger_error('file_unmanaged_copy() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::copy(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
try {
return \Drupal::service('file_system')->copy($source, $destination, $replace);
}
catch (FileException $e) {
return FALSE; return FALSE;
} }
// Attempt to resolve the URIs. This is necessary in certain configurations
// (see above).
$file_system = \Drupal::service('file_system');
$real_source = $file_system->realpath($source) ?: $source;
$real_destination = $file_system->realpath($destination) ?: $destination;
// Perform the copy operation.
if (!@copy($real_source, $real_destination)) {
\Drupal::logger('file')->error('The specified file %file could not be copied to %destination.', ['%file' => $source, '%destination' => $destination]);
return FALSE;
}
// Set the permissions on the new file.
drupal_chmod($destination);
return $destination;
} }
/** /**
@ -500,12 +497,18 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
* @return * @return
* TRUE, or FALSE in the event of an error. * TRUE, or FALSE in the event of an error.
* *
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::getDestinationFilename() instead.
*
* @see file_unmanaged_copy() * @see file_unmanaged_copy()
* @see file_unmanaged_move() * @see file_unmanaged_move()
* @see https://www.drupal.org/node/3006851
*/ */
function file_unmanaged_prepare($source, &$destination = NULL, $replace = FILE_EXISTS_RENAME) { function file_unmanaged_prepare($source, &$destination = NULL, $replace = FILE_EXISTS_RENAME) {
@trigger_error('file_unmanaged_prepare() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::getDestinationFilename() instead. See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
$original_source = $source; $original_source = $source;
$logger = \Drupal::logger('file'); $logger = \Drupal::logger('file');
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system'); $file_system = \Drupal::service('file_system');
// Assert that the source file actually exists. // Assert that the source file actually exists.
@ -587,26 +590,15 @@ function file_build_uri($path) {
* @return * @return
* The destination filepath, or FALSE if the file already exists * The destination filepath, or FALSE if the file already exists
* and FILE_EXISTS_ERROR is specified. * and FILE_EXISTS_ERROR is specified.
*
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::getDestinationFilename().
*
* @see https://www.drupal.org/node/3006851
*/ */
function file_destination($destination, $replace) { function file_destination($destination, $replace) {
if (file_exists($destination)) { @trigger_error('file_destination() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::getDestinationFilename(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
switch ($replace) { return \Drupal::service('file_system')->getDestinationFilename($destination, $replace);
case FILE_EXISTS_REPLACE:
// Do nothing here, we want to overwrite the existing file.
break;
case FILE_EXISTS_RENAME:
$basename = drupal_basename($destination);
$directory = drupal_dirname($destination);
$destination = file_create_filename($basename, $directory);
break;
case FILE_EXISTS_ERROR:
// Error reporting handled by calling function.
return FALSE;
}
}
return $destination;
} }
/** /**
@ -640,36 +632,20 @@ function file_destination($destination, $replace) {
* @return * @return
* The path to the new file, or FALSE in the event of an error. * The path to the new file, or FALSE in the event of an error.
* *
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::move().
*
* @see file_move() * @see file_move()
* @see https://www.drupal.org/node/3006851
*/ */
function file_unmanaged_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) { function file_unmanaged_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
if (!file_unmanaged_prepare($source, $destination, $replace)) { @trigger_error('file_unmanaged_move() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::move(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
try {
return \Drupal::service('file_system')->move($source, $destination, $replace);
}
catch (FileException $e) {
return FALSE; return FALSE;
} }
// Ensure compatibility with Windows.
// @see drupal_unlink()
if ((substr(PHP_OS, 0, 3) == 'WIN') && (!file_stream_wrapper_valid_scheme(file_uri_scheme($source)))) {
chmod($source, 0600);
}
// Attempt to resolve the URIs. This is necessary in certain configurations
// (see above) and can also permit fast moves across local schemes.
$file_system = \Drupal::service('file_system');
$real_source = $file_system->realpath($source) ?: $source;
$real_destination = $file_system->realpath($destination) ?: $destination;
// Perform the move operation.
if (!@rename($real_source, $real_destination)) {
// Fall back to slow copy and unlink procedure. This is necessary for
// renames across schemes that are not local, or where rename() has not been
// implemented. It's not necessary to use drupal_unlink() as the Windows
// issue has already been resolved above.
if (!@copy($real_source, $real_destination) || !@unlink($real_source)) {
\Drupal::logger('file')->error('The specified file %file could not be moved to %destination.', ['%file' => $source, '%destination' => $destination]);
return FALSE;
}
}
// Set the permissions on the new file.
drupal_chmod($destination);
return $destination;
} }
/** /**
@ -768,45 +744,15 @@ function file_unmunge_filename($filename) {
* @return * @return
* File path consisting of $directory and a unique filename based off * File path consisting of $directory and a unique filename based off
* of $basename. * of $basename.
*
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::createFilename().
*
* @see https://www.drupal.org/node/3006851
*/ */
function file_create_filename($basename, $directory) { function file_create_filename($basename, $directory) {
// Strip control characters (ASCII value < 32). Though these are allowed in @trigger_error('file_create_filename() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::createFilename(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
// some filesystems, not many applications handle them well. return \Drupal::service('file_system')->createFilename($basename, $directory);
$basename = preg_replace('/[\x00-\x1F]/u', '_', $basename);
if (substr(PHP_OS, 0, 3) == 'WIN') {
// These characters are not allowed in Windows filenames
$basename = str_replace([':', '*', '?', '"', '<', '>', '|'], '_', $basename);
}
// A URI or path may already have a trailing slash or look like "public://".
if (substr($directory, -1) == '/') {
$separator = '';
}
else {
$separator = '/';
}
$destination = $directory . $separator . $basename;
if (file_exists($destination)) {
// Destination file already exists, generate an alternative.
$pos = strrpos($basename, '.');
if ($pos !== FALSE) {
$name = substr($basename, 0, $pos);
$ext = substr($basename, $pos);
}
else {
$name = $basename;
$ext = '';
}
$counter = 0;
do {
$destination = $directory . $separator . $name . '_' . $counter++ . $ext;
} while (file_exists($destination));
}
return $destination;
} }
/** /**
@ -870,28 +816,21 @@ function file_delete_multiple(array $fids) {
* TRUE for success or path does not exist, or FALSE in the event of an * TRUE for success or path does not exist, or FALSE in the event of an
* error. * error.
* *
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::delete().
*
* @see file_delete() * @see file_delete()
* @see file_unmanaged_delete_recursive() * @see file_unmanaged_delete_recursive()
* @see https://www.drupal.org/node/3006851
*/ */
function file_unmanaged_delete($path) { function file_unmanaged_delete($path) {
if (is_file($path)) { @trigger_error('file_unmanaged_delete() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::delete(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
return drupal_unlink($path); try {
return \Drupal::service('file_system')->delete($path);
} }
$logger = \Drupal::logger('file'); catch (FileException $e) {
if (is_dir($path)) {
$logger->error('%path is a directory and cannot be removed using file_unmanaged_delete().', ['%path' => $path]);
return FALSE; return FALSE;
} }
// Return TRUE for non-existent file, but log that nothing was actually
// deleted, as the current state is the intended result.
if (!file_exists($path)) {
$logger->notice('The file %path was not deleted because it does not exist.', ['%path' => $path]);
return TRUE;
}
// We cannot handle anything other than files and directories. Log an error
// for everything else (sockets, symbolic links, etc).
$logger->error('The file %path is not of a recognized type so it was not deleted.', ['%path' => $path]);
return FALSE;
} }
/** /**
@ -917,26 +856,21 @@ function file_unmanaged_delete($path) {
* TRUE for success or if path does not exist, FALSE in the event of an * TRUE for success or if path does not exist, FALSE in the event of an
* error. * error.
* *
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::deleteRecursive().
*
* @see file_unmanaged_delete() * @see file_unmanaged_delete()
* @see https://www.drupal.org/node/3006851
*/ */
function file_unmanaged_delete_recursive($path, $callback = NULL) { function file_unmanaged_delete_recursive($path, $callback = NULL) {
if (isset($callback)) { @trigger_error('file_unmanaged_delete_recursive() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::deleteRecursive(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
call_user_func($callback, $path); $callback = is_callable($callback) ? $callback : NULL;
try {
return \Drupal::service('file_system')->deleteRecursive($path, $callback);
} }
if (is_dir($path)) { catch (FileException $e) {
$dir = dir($path); return FALSE;
while (($entry = $dir->read()) !== FALSE) {
if ($entry == '.' || $entry == '..') {
continue;
}
$entry_path = $path . '/' . $entry;
file_unmanaged_delete_recursive($entry_path, $callback);
}
$dir->close();
return drupal_rmdir($path);
} }
return file_unmanaged_delete($path);
} }
/** /**
@ -976,18 +910,24 @@ function drupal_move_uploaded_file($filename, $uri) {
* @return * @return
* A string with the path of the resulting file, or FALSE on error. * A string with the path of the resulting file, or FALSE on error.
* *
* @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\File\FileSystemInterface::saveData().
*
* @see file_save_data() * @see file_save_data()
* @see https://www.drupal.org/node/3006851
*/ */
function file_unmanaged_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAME) { function file_unmanaged_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
// Write the data to a temporary file. @trigger_error('file_unmanaged_save_data() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::saveData(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
$temp_name = drupal_tempnam('temporary://', 'file'); try {
if (file_put_contents($temp_name, $data) === FALSE) { return \Drupal::service('file_system')->saveData($data, $destination, $replace);
}
catch (FileWriteException $e) {
\Drupal::messenger()->addError(t('The file could not be created.')); \Drupal::messenger()->addError(t('The file could not be created.'));
return FALSE; return FALSE;
} }
catch (FileException $e) {
// Move the file to its final destination. return FALSE;
return file_unmanaged_move($temp_name, $destination, $replace); }
} }
/** /**

View File

@ -15,6 +15,7 @@ use Drupal\Core\Config\StorageComparer;
use Drupal\Core\DrupalKernel; use Drupal\Core\DrupalKernel;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\Database\DatabaseExceptionWrapper; use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormState; use Drupal\Core\Form\FormState;
use Drupal\Core\Installer\Exception\AlreadyInstalledException; use Drupal\Core\Installer\Exception\AlreadyInstalledException;
use Drupal\Core\Installer\Exception\InstallerException; use Drupal\Core\Installer\Exception\InstallerException;
@ -1106,7 +1107,7 @@ function install_base_system(&$install_state) {
// configurable. The temporary directory needs to match what is set in each // configurable. The temporary directory needs to match what is set in each
// test types ::prepareEnvironment() step. // test types ::prepareEnvironment() step.
$temporary_directory = dirname(PublicStream::basePath()) . '/temp'; $temporary_directory = dirname(PublicStream::basePath()) . '/temp';
file_prepare_directory($temporary_directory, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($temporary_directory, FileSystemInterface::MODIFY_PERMISSIONS | FileSystemInterface::CREATE_DIRECTORY);
\Drupal::configFactory()->getEditable('system.file') \Drupal::configFactory()->getEditable('system.file')
->set('path.temporary', $temporary_directory) ->set('path.temporary', $temporary_directory)
->save(); ->save();
@ -1915,9 +1916,12 @@ function install_check_translations($langcode, $server_pattern) {
$online = FALSE; $online = FALSE;
// First attempt to create or make writable the files directory. // First attempt to create or make writable the files directory.
file_prepare_directory($files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$file_system->prepareDirectory($files_directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
// Then, attempt to create or make writable the translations directory. // Then, attempt to create or make writable the translations directory.
file_prepare_directory($translations_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); $file_system->prepareDirectory($translations_directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
// Get values so the requirements errors can be specific. // Get values so the requirements errors can be specific.
if (drupal_verify_install_file($translations_directory, FILE_EXIST, 'dir')) { if (drupal_verify_install_file($translations_directory, FILE_EXIST, 'dir')) {

View File

@ -7,6 +7,7 @@
use Drupal\Core\Extension\Dependency; use Drupal\Core\Extension\Dependency;
use Drupal\Component\Utility\Unicode; use Drupal\Component\Utility\Unicode;
use Drupal\Core\File\FileSystemInterface;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\OpCodeCache; use Drupal\Component\Utility\OpCodeCache;
@ -511,7 +512,7 @@ function drupal_install_config_directories() {
// public files directory, which has already been verified to be writable // public files directory, which has already been verified to be writable
// itself. But if it somehow fails anyway, the installation cannot proceed. // itself. But if it somehow fails anyway, the installation cannot proceed.
// Bail out using a similar error message as in system_requirements(). // Bail out using a similar error message as in system_requirements().
if (!file_prepare_directory($config_directories[CONFIG_SYNC_DIRECTORY], FILE_CREATE_DIRECTORY) if (!\Drupal::service('file_system')->prepareDirectory($config_directories[CONFIG_SYNC_DIRECTORY], FileSystemInterface::CREATE_DIRECTORY)
&& !file_exists($config_directories[CONFIG_SYNC_DIRECTORY])) { && !file_exists($config_directories[CONFIG_SYNC_DIRECTORY])) {
throw new Exception(t('The directory %directory could not be created. To proceed with the installation, either create the directory or ensure that the installer has the permissions to create it automatically. For more information, see the <a href=":handbook_url">online handbook</a>.', [ throw new Exception(t('The directory %directory could not be created. To proceed with the installation, either create the directory or ensure that the installer has the permissions to create it automatically. For more information, see the <a href=":handbook_url">online handbook</a>.', [
'%directory' => config_get_config_directory(CONFIG_SYNC_DIRECTORY), '%directory' => config_get_config_directory(CONFIG_SYNC_DIRECTORY),
@ -538,12 +539,13 @@ function drupal_install_config_directories() {
* TRUE if the config directory exists and is writable. * TRUE if the config directory exists and is writable.
* *
* @deprecated in Drupal 8.1.x, will be removed before Drupal 9.0.x. Use * @deprecated in Drupal 8.1.x, will be removed before Drupal 9.0.x. Use
* config_get_config_directory() and file_prepare_directory() instead. * config_get_config_directory() and
* \Drupal\Core\File\FileSystemInterface::prepareDirectory() instead.
* *
* @see https://www.drupal.org/node/2501187 * @see https://www.drupal.org/node/2501187
*/ */
function install_ensure_config_directory($type) { function install_ensure_config_directory($type) {
@trigger_error('install_ensure_config_directory() is deprecated in Drupal 8.1.0 and will be removed before Drupal 9.0.0. Use config_get_config_directory() and file_prepare_directory() instead. See https://www.drupal.org/node/2501187.', E_USER_DEPRECATED); @trigger_error('install_ensure_config_directory() is deprecated in Drupal 8.1.0 and will be removed before Drupal 9.0.0. Use config_get_config_directory() and \Drupal\Core\File\FileSystemInterface::prepareDirectory() instead. See https://www.drupal.org/node/2501187.', E_USER_DEPRECATED);
// The config directory must be defined in settings.php. // The config directory must be defined in settings.php.
global $config_directories; global $config_directories;
if (!isset($config_directories[$type])) { if (!isset($config_directories[$type])) {
@ -553,7 +555,7 @@ function install_ensure_config_directory($type) {
// directories that the installer creates. // directories that the installer creates.
else { else {
$config_directory = config_get_config_directory($type); $config_directory = config_get_config_directory($type);
return file_prepare_directory($config_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); return \Drupal::service('file_system')->prepareDirectory($config_directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
} }
} }

View File

@ -3,12 +3,31 @@
namespace Drupal\Core\Asset; namespace Drupal\Core\Asset;
use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\Crypt;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
/** /**
* Dumps a CSS or JavaScript asset. * Dumps a CSS or JavaScript asset.
*/ */
class AssetDumper implements AssetDumperInterface { class AssetDumper implements AssetDumperInterface {
/**
* The file system service.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/**
* AssetDumper constructor.
*
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file handler.
*/
public function __construct(FileSystemInterface $file_system = NULL) {
$this->fileSystem = $file_system;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
* *
@ -24,8 +43,13 @@ class AssetDumper implements AssetDumperInterface {
$path = 'public://' . $file_extension; $path = 'public://' . $file_extension;
$uri = $path . '/' . $filename; $uri = $path . '/' . $filename;
// Create the CSS or JS file. // Create the CSS or JS file.
file_prepare_directory($path, FILE_CREATE_DIRECTORY); $this->getFileSystem()->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY);
if (!file_exists($uri) && !file_unmanaged_save_data($data, $uri, FILE_EXISTS_REPLACE)) { try {
if (!file_exists($uri) && !$this->getFileSystem()->saveData($data, $uri, FileSystemInterface::EXISTS_REPLACE)) {
return FALSE;
}
}
catch (FileException $e) {
return FALSE; return FALSE;
} }
// If CSS/JS gzip compression is enabled and the zlib extension is available // If CSS/JS gzip compression is enabled and the zlib extension is available
@ -37,11 +61,30 @@ class AssetDumper implements AssetDumperInterface {
// aren't working can set css.gzip to FALSE in order to skip // aren't working can set css.gzip to FALSE in order to skip
// generating a file that won't be used. // generating a file that won't be used.
if (extension_loaded('zlib') && \Drupal::config('system.performance')->get($file_extension . '.gzip')) { if (extension_loaded('zlib') && \Drupal::config('system.performance')->get($file_extension . '.gzip')) {
if (!file_exists($uri . '.gz') && !file_unmanaged_save_data(gzencode($data, 9, FORCE_GZIP), $uri . '.gz', FILE_EXISTS_REPLACE)) { try {
if (!file_exists($uri . '.gz') && !$this->getFileSystem()->saveData(gzencode($data, 9, FORCE_GZIP), $uri . '.gz', FILE_EXISTS_REPLACE)) {
return FALSE;
}
}
catch (FileException $e) {
return FALSE; return FALSE;
} }
} }
return $uri; return $uri;
} }
/**
* Helper method for returning the file system service.
*
* @return \Drupal\Core\File\FileSystemInterface
* The file system service.
*/
private function getFileSystem() {
if (!$this->fileSystem) {
@trigger_error('\Drupal\Core\File\FileSystemInterface is a dependency of this class in Drupal 8.7.0 and will be required before Drupal 9.0.0. See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
$this->fileSystem = \Drupal::service('file_system');
}
return $this->fileSystem;
}
} }

View File

@ -2,6 +2,7 @@
namespace Drupal\Core\Asset; namespace Drupal\Core\Asset;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\State\StateInterface; use Drupal\Core\State\StateInterface;
/** /**
@ -37,6 +38,13 @@ class CssCollectionOptimizer implements AssetCollectionOptimizerInterface {
*/ */
protected $state; protected $state;
/**
* The file system service.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/** /**
* Constructs a CssCollectionOptimizer. * Constructs a CssCollectionOptimizer.
* *
@ -48,12 +56,19 @@ class CssCollectionOptimizer implements AssetCollectionOptimizerInterface {
* The dumper for optimized CSS assets. * The dumper for optimized CSS assets.
* @param \Drupal\Core\State\StateInterface $state * @param \Drupal\Core\State\StateInterface $state
* The state key/value store. * The state key/value store.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system service.
*/ */
public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptimizerInterface $optimizer, AssetDumperInterface $dumper, StateInterface $state) { public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptimizerInterface $optimizer, AssetDumperInterface $dumper, StateInterface $state, FileSystemInterface $file_system = NULL) {
$this->grouper = $grouper; $this->grouper = $grouper;
$this->optimizer = $optimizer; $this->optimizer = $optimizer;
$this->dumper = $dumper; $this->dumper = $dumper;
$this->state = $state; $this->state = $state;
if (!$file_system) {
@trigger_error('The file_system service must be passed to CssCollectionOptimizer::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
$file_system = \Drupal::service('file_system');
}
$this->fileSystem = $file_system;
} }
/** /**
@ -178,7 +193,7 @@ class CssCollectionOptimizer implements AssetCollectionOptimizerInterface {
$delete_stale = function ($uri) { $delete_stale = function ($uri) {
// Default stale file threshold is 30 days. // Default stale file threshold is 30 days.
if (REQUEST_TIME - filemtime($uri) > \Drupal::config('system.performance')->get('stale_file_threshold')) { if (REQUEST_TIME - filemtime($uri) > \Drupal::config('system.performance')->get('stale_file_threshold')) {
file_unmanaged_delete($uri); $this->fileSystem->delete($uri);
} }
}; };
file_scan_directory('public://css', '/.*/', ['callback' => $delete_stale]); file_scan_directory('public://css', '/.*/', ['callback' => $delete_stale]);

View File

@ -2,6 +2,7 @@
namespace Drupal\Core\Asset; namespace Drupal\Core\Asset;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\State\StateInterface; use Drupal\Core\State\StateInterface;
/** /**
@ -37,6 +38,13 @@ class JsCollectionOptimizer implements AssetCollectionOptimizerInterface {
*/ */
protected $state; protected $state;
/**
* The file system service.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/** /**
* Constructs a JsCollectionOptimizer. * Constructs a JsCollectionOptimizer.
* *
@ -48,12 +56,19 @@ class JsCollectionOptimizer implements AssetCollectionOptimizerInterface {
* The dumper for optimized JS assets. * The dumper for optimized JS assets.
* @param \Drupal\Core\State\StateInterface $state * @param \Drupal\Core\State\StateInterface $state
* The state key/value store. * The state key/value store.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system service.
*/ */
public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptimizerInterface $optimizer, AssetDumperInterface $dumper, StateInterface $state) { public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptimizerInterface $optimizer, AssetDumperInterface $dumper, StateInterface $state, FileSystemInterface $file_system = NULL) {
$this->grouper = $grouper; $this->grouper = $grouper;
$this->optimizer = $optimizer; $this->optimizer = $optimizer;
$this->dumper = $dumper; $this->dumper = $dumper;
$this->state = $state; $this->state = $state;
if (!$file_system) {
@trigger_error('The file_system service must be passed to JsCollectionOptimizer::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
$file_system = \Drupal::service('file_system');
}
$this->fileSystem = $file_system;
} }
/** /**
@ -180,7 +195,7 @@ class JsCollectionOptimizer implements AssetCollectionOptimizerInterface {
$delete_stale = function ($uri) { $delete_stale = function ($uri) {
// Default stale file threshold is 30 days. // Default stale file threshold is 30 days.
if (REQUEST_TIME - filemtime($uri) > \Drupal::config('system.performance')->get('stale_file_threshold')) { if (REQUEST_TIME - filemtime($uri) > \Drupal::config('system.performance')->get('stale_file_threshold')) {
file_unmanaged_delete($uri); $this->fileSystem->delete($uri);
} }
}; };
file_scan_directory('public://js', '/.*/', ['callback' => $delete_stale]); file_scan_directory('public://js', '/.*/', ['callback' => $delete_stale]);

View File

@ -4,6 +4,7 @@ namespace Drupal\Core\Config;
use Drupal\Component\FileCache\FileCacheFactory; use Drupal\Component\FileCache\FileCacheFactory;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException; use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Serialization\Yaml; use Drupal\Core\Serialization\Yaml;
/** /**
@ -44,7 +45,6 @@ class FileStorage implements StorageInterface {
public function __construct($directory, $collection = StorageInterface::DEFAULT_COLLECTION) { public function __construct($directory, $collection = StorageInterface::DEFAULT_COLLECTION) {
$this->directory = $directory; $this->directory = $directory;
$this->collection = $collection; $this->collection = $collection;
// Use a NULL File Cache backend by default. This will ensure only the // Use a NULL File Cache backend by default. This will ensure only the
// internal static caching of FileCache is used and thus avoids blowing up // internal static caching of FileCache is used and thus avoids blowing up
// the APCu cache. // the APCu cache.
@ -76,7 +76,7 @@ class FileStorage implements StorageInterface {
*/ */
protected function ensureStorage() { protected function ensureStorage() {
$dir = $this->getCollectionDirectory(); $dir = $this->getCollectionDirectory();
$success = file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); $success = \Drupal::service('file_system')->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
// Only create .htaccess file in root directory. // Only create .htaccess file in root directory.
if ($dir == $this->directory) { if ($dir == $this->directory) {
$success = $success && file_save_htaccess($this->directory, TRUE, TRUE); $success = $success && file_save_htaccess($this->directory, TRUE, TRUE);

View File

@ -6,6 +6,7 @@
*/ */
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Core\Utility\UpdateException; use Drupal\Core\Utility\UpdateException;
@ -226,7 +227,7 @@ function hook_modules_installed($modules) {
function hook_install() { function hook_install() {
// Create the styles directory and ensure it's writable. // Create the styles directory and ensure it's writable.
$directory = file_default_scheme() . '://styles'; $directory = file_default_scheme() . '://styles';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
} }
/** /**
@ -282,7 +283,7 @@ function hook_modules_uninstalled($modules) {
*/ */
function hook_uninstall() { function hook_uninstall() {
// Remove the styles directory and generated images. // Remove the styles directory and generated images.
file_unmanaged_delete_recursive(file_default_scheme() . '://styles'); \Drupal::service('file_system')->deleteRecursive(file_default_scheme() . '://styles');
} }
/** /**

View File

@ -0,0 +1,12 @@
<?php
namespace Drupal\Core\File\Exception;
/**
* Exception thrown when a file's destination directory is not ready.
*
* A directory can be considered not ready when it either does not exist, or
* is not writable.
*/
class DirectoryNotReadyException extends FileException {
}

View File

@ -0,0 +1,9 @@
<?php
namespace Drupal\Core\File\Exception;
/**
* Base class for exceptions related to file handling operations.
*/
class FileException extends \RuntimeException {
}

View File

@ -0,0 +1,9 @@
<?php
namespace Drupal\Core\File\Exception;
/**
* Exception thrown when a file unexpectedly exists.
*/
class FileExistsException extends FileException {
}

View File

@ -0,0 +1,9 @@
<?php
namespace Drupal\Core\File\Exception;
/**
* Exception thrown when a file is expected to exist but does not.
*/
class FileNotExistsException extends FileException {
}

View File

@ -0,0 +1,9 @@
<?php
namespace Drupal\Core\File\Exception;
/**
* Exception thrown when file cannot be written to disk.
*/
class FileWriteException extends FileException {
}

View File

@ -0,0 +1,9 @@
<?php
namespace Drupal\Core\File\Exception;
/**
* Exception thrown when a target is not a regular file (e.g. a directory).
*/
class NotRegularFileException extends FileException {
}

View File

@ -2,6 +2,12 @@
namespace Drupal\Core\File; namespace Drupal\Core\File;
use Drupal\Core\File\Exception\DirectoryNotReadyException;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\Exception\FileExistsException;
use Drupal\Core\File\Exception\FileNotExistsException;
use Drupal\Core\File\Exception\FileWriteException;
use Drupal\Core\File\Exception\NotRegularFileException;
use Drupal\Core\Site\Settings; use Drupal\Core\Site\Settings;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface; use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -301,4 +307,331 @@ class FileSystem implements FileSystemInterface {
return class_exists($this->streamWrapperManager->getClass($scheme)); return class_exists($this->streamWrapperManager->getClass($scheme));
} }
/**
* {@inheritdoc}
*/
public function copy($source, $destination = NULL, $replace = self::EXISTS_RENAME) {
$this->prepareDestination($source, $destination, $replace);
// Perform the copy operation.
if (!@copy($source, $destination)) {
// If the copy failed and realpaths exist, retry the operation using them
// instead.
$real_source = $this->realpath($source) ?: $source;
$real_destination = $this->realpath($destination) ?: $destination;
if ($real_source === FALSE || $real_destination === FALSE || !@copy($real_source, $real_destination)) {
$this->logger->error("The specified file '%source' could not be copied to '%destination'.", [
'%source' => $source,
'%destination' => $destination,
]);
throw new FileWriteException("The specified file '$source' could not be copied to '$destination'.");
}
}
// Set the permissions on the new file.
$this->chmod($destination);
return $destination;
}
/**
* {@inheritdoc}
*/
public function delete($path) {
if (is_file($path)) {
if (!$this->unlink($path)) {
$this->logger->error("Failed to unlink file '%path'.", ['%path' => $path]);
throw new FileException("Failed to unlink file '$path'.");
}
return TRUE;
}
if (is_dir($path)) {
$this->logger->error("Cannot delete '%path' because it is a directory. Use deleteRecursive() instead.", ['%path' => $path]);
throw new NotRegularFileException("Cannot delete '$path' because it is a directory. Use deleteRecursive() instead.");
}
// Return TRUE for non-existent file, but log that nothing was actually
// deleted, as the current state is the intended result.
if (!file_exists($path)) {
$this->logger->notice('The file %path was not deleted because it does not exist.', ['%path' => $path]);
return TRUE;
}
// We cannot handle anything other than files and directories.
// Throw an exception for everything else (sockets, symbolic links, etc).
$this->logger->error("The file '%path' is not of a recognized type so it was not deleted.", ['%path' => $path]);
throw new NotRegularFileException("The file '$path' is not of a recognized type so it was not deleted.");
}
/**
* {@inheritdoc}
*/
public function deleteRecursive($path, callable $callback = NULL) {
if ($callback) {
call_user_func($callback, $path);
}
if (is_dir($path)) {
$dir = dir($path);
while (($entry = $dir->read()) !== FALSE) {
if ($entry == '.' || $entry == '..') {
continue;
}
$entry_path = $path . '/' . $entry;
$this->deleteRecursive($entry_path, $callback);
}
$dir->close();
return $this->rmdir($path);
}
return $this->delete($path);
}
/**
* {@inheritdoc}
*/
public function move($source, $destination = NULL, $replace = self::EXISTS_RENAME) {
$this->prepareDestination($source, $destination, $replace);
// Ensure compatibility with Windows.
// @see \Drupal\Core\File\FileSystemInterface::unlink().
$scheme = $this->uriScheme($source);
if (!$this->validScheme($scheme) && (substr(PHP_OS, 0, 3) == 'WIN')) {
chmod($source, 0600);
}
// Attempt to resolve the URIs. This is necessary in certain
// configurations (see above) and can also permit fast moves across local
// schemes.
$real_source = $this->realpath($source) ?: $source;
$real_destination = $this->realpath($destination) ?: $destination;
// Perform the move operation.
if (!@rename($real_source, $real_destination)) {
// Fall back to slow copy and unlink procedure. This is necessary for
// renames across schemes that are not local, or where rename() has not
// been implemented. It's not necessary to use drupal_unlink() as the
// Windows issue has already been resolved above.
if (!@copy($real_source, $real_destination)) {
$this->logger->error("The specified file '%source' could not be moved to '%destination'.", [
'%source' => $source,
'%destination' => $destination,
]);
throw new FileWriteException("The specified file '$source' could not be moved to '$destination'.");
}
if (!@unlink($real_source)) {
$this->logger->error("The source file '%source' could not be unlinked after copying to '%destination'.", [
'%source' => $source,
'%destination' => $destination,
]);
throw new FileException("The source file '$source' could not be unlinked after copying to '$destination'.");
}
}
// Set the permissions on the new file.
$this->chmod($destination);
return $destination;
}
/**
* Prepares the destination for a file copy or move operation.
*
* - Checks if $source and $destination are valid and readable/writable.
* - Checks that $source is not equal to $destination; if they are an error
* is reported.
* - If file already exists in $destination either the call will error out,
* replace the file or rename the file based on the $replace parameter.
*
* @param string $source
* A string specifying the filepath or URI of the source file.
* @param string|null $destination
* A URI containing the destination that $source should be moved/copied to.
* The URI may be a bare filepath (without a scheme) and in that case the
* default scheme (file://) will be used. If this value is omitted, Drupal's
* default files scheme will be used, usually "public://".
* @param int $replace
* Replace behavior when the destination file already exists:
* - FILE_EXISTS_REPLACE - Replace the existing file.
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename
* is unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
*
* @see \Drupal\Core\File\FileSystemInterface::copy()
* @see \Drupal\Core\File\FileSystemInterface::move()
*/
protected function prepareDestination($source, &$destination, $replace) {
$original_source = $source;
// Assert that the source file actually exists.
if (!file_exists($source)) {
if (($realpath = $this->realpath($original_source)) !== FALSE) {
$this->logger->error("File '%original_source' ('%realpath') could not be copied because it does not exist.", [
'%original_source' => $original_source,
'%realpath' => $realpath,
]);
throw new FileNotExistsException("File '$original_source' ('$realpath') could not be copied because it does not exist.");
}
else {
$this->logger->error("File '%original_source' could not be copied because it does not exist.", [
'%original_source' => $original_source,
]);
throw new FileNotExistsException("File '$original_source' could not be copied because it does not exist.");
}
}
// Build a destination URI if necessary.
if (!isset($destination)) {
$destination = file_build_uri($this->basename($source));
}
// Prepare the destination directory.
if ($this->prepareDirectory($destination)) {
// The destination is already a directory, so append the source basename.
$destination = file_stream_wrapper_uri_normalize($destination . '/' . $this->basename($source));
}
else {
// Perhaps $destination is a dir/file?
$dirname = $this->dirname($destination);
if (!$this->prepareDirectory($dirname)) {
$this->logger->error("The specified file '%original_source' could not be copied because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions.", [
'%original_source' => $original_source,
]);
throw new DirectoryNotReadyException("The specified file '$original_source' could not be copied because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions.");
}
}
// Determine whether we can perform this operation based on overwrite rules.
$destination = $this->getDestinationFilename($destination, $replace);
if ($destination === FALSE) {
$this->logger->error("File '%original_source' could not be copied because a file by that name already exists in the destination directory ('%destination').", [
'%original_source' => $original_source,
'%destination' => $destination,
]);
throw new FileExistsException("File '$original_source' could not be copied because a file by that name already exists in the destination directory ('$destination').");
}
// Assert that the source and destination filenames are not the same.
$real_source = $this->realpath($source);
$real_destination = $this->realpath($destination);
if ($source == $destination || ($real_source !== FALSE) && ($real_source == $real_destination)) {
$this->logger->error("File '%source' could not be copied because it would overwrite itself.", [
'%source' => $source,
]);
throw new FileException("File '$source' could not be copied because it would overwrite itself.");
}
// Make sure the .htaccess files are present.
// @todo Replace with a service in https://www.drupal.org/project/drupal/issues/2620304.
file_ensure_htaccess();
}
/**
* {@inheritdoc}
*/
public function saveData($data, $destination = NULL, $replace = self::EXISTS_RENAME) {
// Write the data to a temporary file.
$temp_name = $this->tempnam('temporary://', 'file');
if (file_put_contents($temp_name, $data) === FALSE) {
$this->logger->error("Temporary file '%temp_name' could not be created.", ['%temp_name' => $temp_name]);
throw new FileWriteException("Temporary file '$temp_name' could not be created.");
}
// Move the file to its final destination.
return $this->move($temp_name, $destination, $replace);
}
/**
* {@inheritdoc}
*/
public function prepareDirectory(&$directory, $options = self::MODIFY_PERMISSIONS) {
if (!$this->validScheme($this->uriScheme($directory))) {
// Only trim if we're not dealing with a stream.
$directory = rtrim($directory, '/\\');
}
// Check if directory exists.
if (!is_dir($directory)) {
// Let mkdir() recursively create directories and use the default
// directory permissions.
if ($options & static::CREATE_DIRECTORY) {
return @$this->mkdir($directory, NULL, TRUE);
}
return FALSE;
}
// The directory exists, so check to see if it is writable.
$writable = is_writable($directory);
if (!$writable && ($options & static::MODIFY_PERMISSIONS)) {
return $this->chmod($directory);
}
return $writable;
}
/**
* {@inheritdoc}
*/
public function getDestinationFilename($destination, $replace) {
if (file_exists($destination)) {
switch ($replace) {
case FileSystemInterface::EXISTS_REPLACE:
// Do nothing here, we want to overwrite the existing file.
break;
case FileSystemInterface::EXISTS_RENAME:
$basename = $this->basename($destination);
$directory = $this->dirname($destination);
$destination = $this->createFilename($basename, $directory);
break;
case FileSystemInterface::EXISTS_ERROR:
// Error reporting handled by calling function.
return FALSE;
}
}
return $destination;
}
/**
* {@inheritdoc}
*/
public function createFilename($basename, $directory) {
// Strip control characters (ASCII value < 32). Though these are allowed in
// some filesystems, not many applications handle them well.
$basename = preg_replace('/[\x00-\x1F]/u', '_', $basename);
if (substr(PHP_OS, 0, 3) == 'WIN') {
// These characters are not allowed in Windows filenames.
$basename = str_replace([':', '*', '?', '"', '<', '>', '|'], '_', $basename);
}
// A URI or path may already have a trailing slash or look like "public://".
if (substr($directory, -1) == '/') {
$separator = '';
}
else {
$separator = '/';
}
$destination = $directory . $separator . $basename;
if (file_exists($destination)) {
// Destination file already exists, generate an alternative.
$pos = strrpos($basename, '.');
if ($pos !== FALSE) {
$name = substr($basename, 0, $pos);
$ext = substr($basename, $pos);
}
else {
$name = $basename;
$ext = '';
}
$counter = 0;
do {
$destination = $directory . $separator . $name . '_' . $counter++ . $ext;
} while (file_exists($destination));
}
return $destination;
}
} }

View File

@ -7,6 +7,31 @@ namespace Drupal\Core\File;
*/ */
interface FileSystemInterface { interface FileSystemInterface {
/**
* Flag for dealing with existing files: Appends number until name is unique.
*/
const EXISTS_RENAME = 0;
/**
* Flag for dealing with existing files: Replace the existing file.
*/
const EXISTS_REPLACE = 1;
/**
* Flag for dealing with existing files: Do nothing and return FALSE.
*/
const EXISTS_ERROR = 2;
/**
* Flag used by ::prepareDirectory() -- create directory if not present.
*/
const CREATE_DIRECTORY = 1;
/**
* Flag used by ::prepareDirectory() -- file permissions may be changed.
*/
const MODIFY_PERMISSIONS = 2;
/** /**
* Moves an uploaded file to a new location. * Moves an uploaded file to a new location.
* *
@ -237,4 +262,202 @@ interface FileSystemInterface {
*/ */
public function validScheme($scheme); public function validScheme($scheme);
/**
* Copies a file to a new location without invoking the file API.
*
* This is a powerful function that in many ways performs like an advanced
* version of copy().
* - Checks if $source and $destination are valid and readable/writable.
* - If file already exists in $destination either the call will error out,
* replace the file or rename the file based on the $replace parameter.
* - If the $source and $destination are equal, the behavior depends on the
* $replace parameter. FILE_EXISTS_REPLACE will error out.
* FILE_EXISTS_RENAME will rename the file until the $destination is unique.
* - Provides a fallback using realpaths if the move fails using stream
* wrappers. This can occur because PHP's copy() function does not properly
* support streams if open_basedir is enabled. See
* https://bugs.php.net/bug.php?id=60456
*
* @param string $source
* A string specifying the filepath or URI of the source file.
* @param string $destination
* A URI containing the destination that $source should be copied to. The
* URI may be a bare filepath (without a scheme). If this value is omitted,
* Drupal's default files scheme will be used, usually "public://".
* @param int $replace
* Replace behavior when the destination file already exists:
* - FileManagerInterface::FILE_EXISTS_REPLACE - Replace the existing file.
* - FileManagerInterface::FILE_EXISTS_RENAME - Append _{incrementing
* number} until the filename is unique.
* - FileManagerInterface::FILE_EXISTS_ERROR - Throw an exception.
*
* @return string
* The path to the new file.
*
* @throws \Drupal\Core\File\Exception\FileException
* Implementation may throw FileException or its subtype on failure.
*/
public function copy($source, $destination = NULL, $replace = self::EXISTS_RENAME);
/**
* Deletes a file without database changes or hook invocations.
*
* This function should be used when the file to be deleted does not have an
* entry recorded in the files table.
*
* @param string $path
* A string containing a file path or (streamwrapper) URI.
*
* @throws \Drupal\Core\File\Exception\FileException
* Implementation may throw FileException or its subtype on failure.
*/
public function delete($path);
/**
* Deletes all files and directories in the specified filepath recursively.
*
* If the specified path is a directory then the function is called
* recursively to process the contents. Once the contents have been removed
* the directory is also removed.
*
* If the specified path is a file then it will be processed with delete()
* method.
*
* Note that this only deletes visible files with write permission.
*
* @param string $path
* A string containing either an URI or a file or directory path.
* @param callable|null $callback
* Callback function to run on each file prior to deleting it and on each
* directory prior to traversing it. For example, can be used to modify
* permissions.
*
* @throws \Drupal\Core\File\Exception\FileException
* Implementation may throw FileException or its subtype on failure.
*/
public function deleteRecursive($path, callable $callback = NULL);
/**
* Moves a file to a new location without database changes or hook invocation.
*
* This is a powerful function that in many ways performs like an advanced
* version of rename().
* - Checks if $source and $destination are valid and readable/writable.
* - Checks that $source is not equal to $destination; if they are an error
* is reported.
* - If file already exists in $destination either the call will error out,
* replace the file or rename the file based on the $replace parameter.
* - Works around a PHP bug where rename() does not properly support streams
* if safe_mode or open_basedir are enabled.
*
* @param string $source
* A string specifying the filepath or URI of the source file.
* @param string $destination
* A URI containing the destination that $source should be moved to. The
* URI may be a bare filepath (without a scheme) and in that case the
* default scheme (file://) will be used. If this value is omitted, Drupal's
* default files scheme will be used, usually "public://".
* @param int $replace
* Replace behavior when the destination file already exists:
* - FILE_EXISTS_REPLACE - Replace the existing file.
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename
* is unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
*
* @return string
* The path to the new file.
*
* @throws \Drupal\Core\File\Exception\FileException
* Implementation may throw FileException or its subtype on failure.
*
* @see https://bugs.php.net/bug.php?id=60456
*/
public function move($source, $destination = NULL, $replace = self::EXISTS_RENAME);
/**
* Saves a file to the specified destination without invoking file API.
*
* This function is identical to file_save_data() except the file will not be
* saved to the {file_managed} table and none of the file_* hooks will be
* called.
*
* @param string $data
* A string containing the contents of the file.
* @param string $destination
* A string containing the destination location. This must be a stream
* wrapper URI. If no value is provided, a randomized name will be generated
* and the file will be saved using Drupal's default files scheme, usually
* "public://".
* @param int $replace
* Replace behavior when the destination file already exists:
* - FILE_EXISTS_REPLACE - Replace the existing file.
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename
* is unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
*
* @return string
* A string with the path of the resulting file, or FALSE on error.
*
* @throws \Drupal\Core\File\Exception\FileException
* Implementation may throw FileException or its subtype on failure.
*
* @see file_save_data()
*/
public function saveData($data, $destination = NULL, $replace = self::EXISTS_RENAME);
/**
* Checks that the directory exists and is writable.
*
* Directories need to have execute permissions to be considered a directory
* by FTP servers, etc.
*
* @param string $directory
* A string reference containing the name of a directory path or URI. A
* trailing slash will be trimmed from a path.
* @param int $options
* A bitmask to indicate if the directory should be created if it does
* not exist (FileSystemInterface::CREATE_DIRECTORY) or made writable if it
* is read-only (FileSystemInterface::MODIFY_PERMISSIONS).
*
* @return bool
* TRUE if the directory exists (or was created) and is writable. FALSE
* otherwise.
*/
public function prepareDirectory(&$directory, $options = self::MODIFY_PERMISSIONS);
/**
* Creates a full file path from a directory and filename.
*
* If a file with the specified name already exists, an alternative will be
* used.
*
* @param string $basename
* The filename.
* @param string $directory
* The directory or parent URI.
*
* @return string
* File path consisting of $directory and a unique filename based off
* of $basename.
*/
public function createFilename($basename, $directory);
/**
* Determines the destination path for a file.
*
* @param string $destination
* The desired final URI or filepath.
* @param int $replace
* Replace behavior when the destination file already exists.
* - FileSystemInterface::EXISTS_REPLACE - Replace the existing file.
* - FileSystemInterface::EXISTS_RENAME - Append _{incrementing number}
* until the filename is unique.
* - FileSystemInterface::EXISTS_ERROR - Do nothing and return FALSE.
*
* @return string|bool
* The destination filepath, or FALSE if the file already exists
* and FileSystemInterface::EXISTS_ERROR is specified.
*/
public function getDestinationFilename($destination, $replace);
} }

View File

@ -8,6 +8,7 @@ use Drupal\Core\Config\Development\ConfigSchemaChecker;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\DrupalKernel; use Drupal\Core\DrupalKernel;
use Drupal\Core\Extension\MissingDependencyException; use Drupal\Core\Extension\MissingDependencyException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Serialization\Yaml; use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Session\UserSession; use Drupal\Core\Session\UserSession;
use Drupal\Core\Site\Settings; use Drupal\Core\Site\Settings;
@ -318,7 +319,7 @@ trait FunctionalTestSetupTrait {
$config = $container->get('config.factory'); $config = $container->get('config.factory');
// Manually create the private directory. // Manually create the private directory.
file_prepare_directory($this->privateFilesDirectory, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($this->privateFilesDirectory, FileSystemInterface::CREATE_DIRECTORY);
// Manually configure the test mail collector implementation to prevent // Manually configure the test mail collector implementation to prevent
// tests from sending out emails and collect them in state instead. // tests from sending out emails and collect them in state instead.
@ -575,7 +576,7 @@ trait FunctionalTestSetupTrait {
// Create test directory ahead of installation so fatal errors and debug // Create test directory ahead of installation so fatal errors and debug
// information can be logged during installation process. // information can be logged during installation process.
file_prepare_directory($this->siteDirectory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); \Drupal::service('file_system')->prepareDirectory($this->siteDirectory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
// Prepare filesystem directory paths. // Prepare filesystem directory paths.
$this->publicFilesDirectory = $this->siteDirectory . '/files'; $this->publicFilesDirectory = $this->siteDirectory . '/files';

View File

@ -288,7 +288,7 @@ EOF;
$path = 'public://valid-opml.xml'; $path = 'public://valid-opml.xml';
// Add the UTF-8 byte order mark. // Add the UTF-8 byte order mark.
return file_unmanaged_save_data(chr(239) . chr(187) . chr(191) . $opml, $path); return \Drupal::service('file_system')->saveData(chr(239) . chr(187) . chr(191) . $opml, $path);
} }
/** /**
@ -305,7 +305,7 @@ EOF;
EOF; EOF;
$path = 'public://invalid-opml.xml'; $path = 'public://invalid-opml.xml';
return file_unmanaged_save_data($opml, $path); return \Drupal::service('file_system')->saveData($opml, $path);
} }
/** /**
@ -327,7 +327,7 @@ EOF;
EOF; EOF;
$path = 'public://empty-opml.xml'; $path = 'public://empty-opml.xml';
return file_unmanaged_save_data($opml, $path); return \Drupal::service('file_system')->saveData($opml, $path);
} }
/** /**

View File

@ -281,7 +281,7 @@ EOF;
$path = 'public://valid-opml.xml'; $path = 'public://valid-opml.xml';
// Add the UTF-8 byte order mark. // Add the UTF-8 byte order mark.
return file_unmanaged_save_data(chr(239) . chr(187) . chr(191) . $opml, $path); return \Drupal::service('file_system')->saveData(chr(239) . chr(187) . chr(191) . $opml, $path);
} }
/** /**
@ -298,7 +298,7 @@ EOF;
EOF; EOF;
$path = 'public://invalid-opml.xml'; $path = 'public://invalid-opml.xml';
return file_unmanaged_save_data($opml, $path); return \Drupal::service('file_system')->saveData($opml, $path);
} }
/** /**
@ -320,7 +320,7 @@ EOF;
EOF; EOF;
$path = 'public://empty-opml.xml'; $path = 'public://empty-opml.xml';
return file_unmanaged_save_data($opml, $path); return \Drupal::service('file_system')->saveData($opml, $path);
} }
/** /**

View File

@ -5,12 +5,14 @@
* Allows users to change the color scheme of themes. * Allows users to change the color scheme of themes.
*/ */
use Drupal\Component\Utility\Color;
use Drupal\Core\Asset\CssOptimizer;
use Drupal\Component\Utility\Bytes; use Drupal\Component\Utility\Bytes;
use Drupal\Component\Utility\Color;
use Drupal\Component\Utility\Environment; use Drupal\Component\Utility\Environment;
use Drupal\Core\Asset\CssOptimizer;
use Drupal\Core\Block\BlockPluginInterface; use Drupal\Core\Block\BlockPluginInterface;
use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Render\Element\Textfield; use Drupal\Core\Render\Element\Textfield;
@ -440,8 +442,10 @@ function color_scheme_form_submit($form, FormStateInterface $form_state) {
$id = $theme . '-' . substr(hash('sha256', serialize($palette) . microtime()), 0, 8); $id = $theme . '-' . substr(hash('sha256', serialize($palette) . microtime()), 0, 8);
$paths['color'] = 'public://color'; $paths['color'] = 'public://color';
$paths['target'] = $paths['color'] . '/' . $id; $paths['target'] = $paths['color'] . '/' . $id;
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
foreach ($paths as $path) { foreach ($paths as $path) {
file_prepare_directory($path, FILE_CREATE_DIRECTORY); $file_system->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY);
} }
$paths['target'] = $paths['target'] . '/'; $paths['target'] = $paths['target'] . '/';
$paths['id'] = $id; $paths['id'] = $id;
@ -458,7 +462,12 @@ function color_scheme_form_submit($form, FormStateInterface $form_state) {
foreach ($info['copy'] as $file) { foreach ($info['copy'] as $file) {
$base = drupal_basename($file); $base = drupal_basename($file);
$source = $paths['source'] . $file; $source = $paths['source'] . $file;
$filepath = file_unmanaged_copy($source, $paths['target'] . $base); try {
$filepath = $file_system->copy($source, $paths['target'] . $base);
}
catch (FileException $e) {
$filepath = FALSE;
}
$paths['map'][$file] = $base; $paths['map'][$file] = $base;
$paths['files'][] = $filepath; $paths['files'][] = $filepath;
} }
@ -582,7 +591,7 @@ function _color_rewrite_stylesheet($theme, &$info, &$paths, $palette, $style) {
* Saves the rewritten stylesheet to disk. * Saves the rewritten stylesheet to disk.
*/ */
function _color_save_stylesheet($file, $style, &$paths) { function _color_save_stylesheet($file, $style, &$paths) {
$filepath = file_unmanaged_save_data($style, $file, FILE_EXISTS_REPLACE); $filepath = \Drupal::service('file_system')->saveData($style, $file, FileSystemInterface::EXISTS_REPLACE);
$paths['files'][] = $filepath; $paths['files'][] = $filepath;
// Set standard file permissions for webserver-generated files. // Set standard file permissions for webserver-generated files.

View File

@ -7,6 +7,8 @@ use Drupal\Core\Config\ConfigManagerInterface;
use Drupal\Core\Config\StorageInterface; use Drupal\Core\Config\StorageInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Diff\DiffFormatter; use Drupal\Core\Diff\DiffFormatter;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Serialization\Yaml; use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\system\FileDownloadController; use Drupal\system\FileDownloadController;
@ -53,6 +55,13 @@ class ConfigController implements ContainerInjectionInterface {
*/ */
protected $diffFormatter; protected $diffFormatter;
/**
* The file system.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -62,7 +71,8 @@ class ConfigController implements ContainerInjectionInterface {
$container->get('config.storage.sync'), $container->get('config.storage.sync'),
$container->get('config.manager'), $container->get('config.manager'),
new FileDownloadController(), new FileDownloadController(),
$container->get('diff.formatter') $container->get('diff.formatter'),
$container->get('file_system')
); );
} }
@ -72,23 +82,35 @@ class ConfigController implements ContainerInjectionInterface {
* @param \Drupal\Core\Config\StorageInterface $target_storage * @param \Drupal\Core\Config\StorageInterface $target_storage
* The target storage. * The target storage.
* @param \Drupal\Core\Config\StorageInterface $source_storage * @param \Drupal\Core\Config\StorageInterface $source_storage
* The source storage * The source storage.
* @param \Drupal\Core\Config\ConfigManagerInterface $config_manager
* The config manager.
* @param \Drupal\system\FileDownloadController $file_download_controller * @param \Drupal\system\FileDownloadController $file_download_controller
* The file download controller. * The file download controller.
* @param \Drupal\Core\Diff\DiffFormatter $diff_formatter
* The diff formatter.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system.
*/ */
public function __construct(StorageInterface $target_storage, StorageInterface $source_storage, ConfigManagerInterface $config_manager, FileDownloadController $file_download_controller, DiffFormatter $diff_formatter) { public function __construct(StorageInterface $target_storage, StorageInterface $source_storage, ConfigManagerInterface $config_manager, FileDownloadController $file_download_controller, DiffFormatter $diff_formatter, FileSystemInterface $file_system) {
$this->targetStorage = $target_storage; $this->targetStorage = $target_storage;
$this->sourceStorage = $source_storage; $this->sourceStorage = $source_storage;
$this->configManager = $config_manager; $this->configManager = $config_manager;
$this->fileDownloadController = $file_download_controller; $this->fileDownloadController = $file_download_controller;
$this->diffFormatter = $diff_formatter; $this->diffFormatter = $diff_formatter;
$this->fileSystem = $file_system;
} }
/** /**
* Downloads a tarball of the site configuration. * Downloads a tarball of the site configuration.
*/ */
public function downloadExport() { public function downloadExport() {
file_unmanaged_delete(file_directory_temp() . '/config.tar.gz'); try {
$this->fileSystem->delete(file_directory_temp() . '/config.tar.gz');
}
catch (FileException $e) {
// Ignore failed deletes.
}
$archiver = new ArchiveTar(file_directory_temp() . '/config.tar.gz', 'gz'); $archiver = new ArchiveTar(file_directory_temp() . '/config.tar.gz', 'gz');
// Get raw configuration data without overrides. // Get raw configuration data without overrides.

View File

@ -4,6 +4,7 @@ namespace Drupal\Tests\config\Functional;
use Drupal\Core\Config\PreExistingConfigException; use Drupal\Core\Config\PreExistingConfigException;
use Drupal\Core\Config\StorageInterface; use Drupal\Core\Config\StorageInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\language\Entity\ConfigurableLanguage; use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
@ -201,7 +202,12 @@ class ConfigInstallWebTest extends BrowserTestBase {
$this->drupalPostForm('admin/modules', ['modules[config][enable]' => TRUE], t('Install')); $this->drupalPostForm('admin/modules', ['modules[config][enable]' => TRUE], t('Install'));
$directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY); $directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
file_unmanaged_delete_recursive($directory); try {
\Drupal::service('file_system')->deleteRecursive($directory);
}
catch (FileException $e) {
// Ignore failed deletes.
}
$this->drupalGet('/admin/reports/status'); $this->drupalGet('/admin/reports/status');
$this->assertRaw(t('The directory %directory does not exist.', ['%directory' => $directory])); $this->assertRaw(t('The directory %directory does not exist.', ['%directory' => $directory]));
} }

View File

@ -94,11 +94,13 @@ class FieldImportCreateTest extends FieldKernelTestBase {
// Add the new files to the sync directory. // Add the new files to the sync directory.
$src_dir = __DIR__ . '/../../modules/field_test_config/sync'; $src_dir = __DIR__ . '/../../modules/field_test_config/sync';
$target_dir = config_get_config_directory(CONFIG_SYNC_DIRECTORY); $target_dir = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_storage_config_name.yml", "$target_dir/$field_storage_config_name.yml")); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name.yml", "$target_dir/$field_config_name.yml")); $file_system = \Drupal::service('file_system');
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_storage_config_name_2.yml", "$target_dir/$field_storage_config_name_2.yml")); $this->assertTrue($file_system->copy("$src_dir/$field_storage_config_name.yml", "$target_dir/$field_storage_config_name.yml"));
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name_2a.yml", "$target_dir/$field_config_name_2a.yml")); $this->assertTrue($file_system->copy("$src_dir/$field_config_name.yml", "$target_dir/$field_config_name.yml"));
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name_2b.yml", "$target_dir/$field_config_name_2b.yml")); $this->assertTrue($file_system->copy("$src_dir/$field_storage_config_name_2.yml", "$target_dir/$field_storage_config_name_2.yml"));
$this->assertTrue($file_system->copy("$src_dir/$field_config_name_2a.yml", "$target_dir/$field_config_name_2a.yml"));
$this->assertTrue($file_system->copy("$src_dir/$field_config_name_2b.yml", "$target_dir/$field_config_name_2b.yml"));
// Import the content of the sync directory. // Import the content of the sync directory.
$this->configImporter()->import(); $this->configImporter()->import();

View File

@ -7,6 +7,8 @@
use Drupal\Core\Datetime\Entity\DateFormat; use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Render\BubbleableMetadata; use Drupal\Core\Render\BubbleableMetadata;
@ -153,8 +155,10 @@ function file_load($fid, $reset = FALSE) {
* @see hook_file_copy() * @see hook_file_copy()
*/ */
function file_copy(FileInterface $source, $destination = NULL, $replace = FILE_EXISTS_RENAME) { function file_copy(FileInterface $source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
if (!file_valid_uri($destination)) { if (!file_valid_uri($destination)) {
if (($realpath = \Drupal::service('file_system')->realpath($source->getFileUri())) !== FALSE) { if (($realpath = $file_system->realpath($source->getFileUri())) !== FALSE) {
\Drupal::logger('file')->notice('File %file (%realpath) could not be copied because the destination %destination is invalid. This is often caused by improper use of file_copy() or a missing stream wrapper.', ['%file' => $source->getFileUri(), '%realpath' => $realpath, '%destination' => $destination]); \Drupal::logger('file')->notice('File %file (%realpath) could not be copied because the destination %destination is invalid. This is often caused by improper use of file_copy() or a missing stream wrapper.', ['%file' => $source->getFileUri(), '%realpath' => $realpath, '%destination' => $destination]);
} }
else { else {
@ -164,7 +168,8 @@ function file_copy(FileInterface $source, $destination = NULL, $replace = FILE_E
return FALSE; return FALSE;
} }
if ($uri = file_unmanaged_copy($source->getFileUri(), $destination, $replace)) { try {
$uri = $file_system->copy($source->getFileUri(), $destination, $replace);
$file = $source->createDuplicate(); $file = $source->createDuplicate();
$file->setFileUri($uri); $file->setFileUri($uri);
$file->setFilename(drupal_basename($uri)); $file->setFilename(drupal_basename($uri));
@ -193,7 +198,9 @@ function file_copy(FileInterface $source, $destination = NULL, $replace = FILE_E
return $file; return $file;
} }
return FALSE; catch (FileException $e) {
return FALSE;
}
} }
/** /**
@ -224,12 +231,14 @@ function file_copy(FileInterface $source, $destination = NULL, $replace = FILE_E
* @return \Drupal\file\FileInterface|false * @return \Drupal\file\FileInterface|false
* Resulting file entity for success, or FALSE in the event of an error. * Resulting file entity for success, or FALSE in the event of an error.
* *
* @see file_unmanaged_move() * @see \Drupal\Core\File\FileSystemInterface::move()
* @see hook_file_move() * @see hook_file_move()
*/ */
function file_move(FileInterface $source, $destination = NULL, $replace = FILE_EXISTS_RENAME) { function file_move(FileInterface $source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
if (!file_valid_uri($destination)) { if (!file_valid_uri($destination)) {
if (($realpath = \Drupal::service('file_system')->realpath($source->getFileUri())) !== FALSE) { if (($realpath = $file_system->realpath($source->getFileUri())) !== FALSE) {
\Drupal::logger('file')->notice('File %file (%realpath) could not be moved because the destination %destination is invalid. This may be caused by improper use of file_move() or a missing stream wrapper.', ['%file' => $source->getFileUri(), '%realpath' => $realpath, '%destination' => $destination]); \Drupal::logger('file')->notice('File %file (%realpath) could not be moved because the destination %destination is invalid. This may be caused by improper use of file_move() or a missing stream wrapper.', ['%file' => $source->getFileUri(), '%realpath' => $realpath, '%destination' => $destination]);
} }
else { else {
@ -239,7 +248,8 @@ function file_move(FileInterface $source, $destination = NULL, $replace = FILE_E
return FALSE; return FALSE;
} }
if ($uri = file_unmanaged_move($source->getFileUri(), $destination, $replace)) { try {
$uri = $file_system->move($source->getFileUri(), $destination, $replace);
$delete_source = FALSE; $delete_source = FALSE;
$file = clone $source; $file = clone $source;
@ -272,7 +282,9 @@ function file_move(FileInterface $source, $destination = NULL, $replace = FILE_E
return $file; return $file;
} }
return FALSE; catch (FileException $e) {
return FALSE;
}
} }
/** /**
@ -555,7 +567,8 @@ function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAM
return FALSE; return FALSE;
} }
if ($uri = file_unmanaged_save_data($data, $destination, $replace)) { try {
$uri = \Drupal::service('file_system')->saveData($data, $destination, $replace);
// Create a file entity. // Create a file entity.
$file = File::create([ $file = File::create([
'uri' => $uri, 'uri' => $uri,
@ -583,7 +596,10 @@ function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAM
$file->save(); $file->save();
return $file; return $file;
} }
return FALSE; catch (FileException $e) {
return FALSE;
}
} }
/** /**
@ -920,7 +936,7 @@ function file_save_upload($form_field_name, $validators = [], $destination = FAL
* *
* @see file_save_upload() * @see file_save_upload()
*/ */
function _file_save_upload_single(\SplFileInfo $file_info, $form_field_name, $validators = [], $destination = FALSE, $replace = FILE_EXISTS_RENAME) { function _file_save_upload_single(\SplFileInfo $file_info, $form_field_name, $validators = [], $destination = FALSE, $replace = FileSystemInterface::EXISTS_REPLACE) {
$user = \Drupal::currentUser(); $user = \Drupal::currentUser();
// Check for file upload errors and return FALSE for this file if a lower // Check for file upload errors and return FALSE for this file if a lower
// level system error occurred. For a complete list of errors: // level system error occurred. For a complete list of errors:
@ -1020,9 +1036,11 @@ function _file_save_upload_single(\SplFileInfo $file_info, $form_field_name, $va
if (substr($destination, -1) != '/') { if (substr($destination, -1) != '/') {
$destination .= '/'; $destination .= '/';
} }
$file->destination = file_destination($destination . $file->getFilename(), $replace); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
// If file_destination() returns FALSE then $replace === FILE_EXISTS_ERROR and $file_system = \Drupal::service('file_system');
// there's an existing file so we need to bail. $file->destination = $file_system->getDestinationFilename($destination . $file->getFilename(), $replace);
// If the destination is FALSE then there is an existing file and $replace is
// set to return an error, so we need to exit.
if ($file->destination === FALSE) { if ($file->destination === FALSE) {
\Drupal::messenger()->addError(t('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', ['%source' => $form_field_name, '%directory' => $destination])); \Drupal::messenger()->addError(t('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', ['%source' => $form_field_name, '%directory' => $destination]));
return FALSE; return FALSE;
@ -1053,7 +1071,7 @@ function _file_save_upload_single(\SplFileInfo $file_info, $form_field_name, $va
} }
$file->setFileUri($file->destination); $file->setFileUri($file->destination);
if (!\Drupal::service('file_system')->moveUploadedFile($file_info->getRealPath(), $file->getFileUri())) { if (!$file_system->moveUploadedFile($file_info->getRealPath(), $file->getFileUri())) {
\Drupal::messenger()->addError(t('File upload error. Could not move uploaded file.')); \Drupal::messenger()->addError(t('File upload error. Could not move uploaded file.'));
\Drupal::logger('file')->notice('Upload error. Could not move uploaded file %file to destination %destination.', ['%file' => $file->getFilename(), '%destination' => $file->getFileUri()]); \Drupal::logger('file')->notice('Upload error. Could not move uploaded file %file to destination %destination.', ['%file' => $file->getFilename(), '%destination' => $file->getFileUri()]);
return FALSE; return FALSE;
@ -1065,7 +1083,7 @@ function _file_save_upload_single(\SplFileInfo $file_info, $form_field_name, $va
// If we are replacing an existing file re-use its database record. // If we are replacing an existing file re-use its database record.
// @todo Do not create a new entity in order to update it. See // @todo Do not create a new entity in order to update it. See
// https://www.drupal.org/node/2241865. // https://www.drupal.org/node/2241865.
if ($replace == FILE_EXISTS_REPLACE) { if ($replace == FileSystemInterface::EXISTS_REPLACE) {
$existing_files = entity_load_multiple_by_properties('file', ['uri' => $file->getFileUri()]); $existing_files = entity_load_multiple_by_properties('file', ['uri' => $file->getFileUri()]);
if (count($existing_files)) { if (count($existing_files)) {
$existing = reset($existing_files); $existing = reset($existing_files);
@ -1358,7 +1376,7 @@ function file_managed_file_save_upload($element, FormStateInterface $form_state)
$file_upload = $all_files[$upload_name]; $file_upload = $all_files[$upload_name];
$destination = isset($element['#upload_location']) ? $element['#upload_location'] : NULL; $destination = isset($element['#upload_location']) ? $element['#upload_location'] : NULL;
if (isset($destination) && !file_prepare_directory($destination, FILE_CREATE_DIRECTORY)) { if (isset($destination) && !\Drupal::service('file_system')->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY)) {
\Drupal::logger('file')->notice('The upload directory %directory for the file field %name could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.', ['%directory' => $destination, '%name' => $element['#field_name']]); \Drupal::logger('file')->notice('The upload directory %directory for the file field %name could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.', ['%directory' => $destination, '%name' => $element['#field_name']]);
$form_state->setError($element, t('The file could not be uploaded.')); $form_state->setError($element, t('The file could not be uploaded.'));
return FALSE; return FALSE;

View File

@ -7,6 +7,7 @@ use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\File\Exception\FileException;
use Drupal\file\FileInterface; use Drupal\file\FileInterface;
use Drupal\user\EntityOwnerTrait; use Drupal\user\EntityOwnerTrait;
@ -206,7 +207,12 @@ class File extends ContentEntityBase implements FileInterface {
// Delete the actual file. Failures due to invalid files and files that // Delete the actual file. Failures due to invalid files and files that
// were already deleted are logged to watchdog but ignored, the // were already deleted are logged to watchdog but ignored, the
// corresponding file entity will be deleted. // corresponding file entity will be deleted.
file_unmanaged_delete($entity->getFileUri()); try {
\Drupal::service('file_system')->delete($entity->getFileUri());
}
catch (FileException $e) {
// Ignore and continue.
}
} }
} }

View File

@ -8,6 +8,7 @@ use Drupal\Component\Utility\Random;
use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem; use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StreamWrapper\StreamWrapperInterface; use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\TypedData\DataDefinition;
@ -325,12 +326,12 @@ class FileItem extends EntityReferenceItem {
// Prepare destination. // Prepare destination.
$dirname = static::doGetUploadLocation($settings); $dirname = static::doGetUploadLocation($settings);
file_prepare_directory($dirname, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($dirname, FileSystemInterface::CREATE_DIRECTORY);
// Generate a file entity. // Generate a file entity.
$destination = $dirname . '/' . $random->name(10, TRUE) . '.txt'; $destination = $dirname . '/' . $random->name(10, TRUE) . '.txt';
$data = $random->paragraphs(3); $data = $random->paragraphs(3);
$file = file_save_data($data, $destination, FILE_EXISTS_ERROR); $file = file_save_data($data, $destination, FileSystemInterface::EXISTS_ERROR);
$values = [ $values = [
'target_id' => $file->id(), 'target_id' => $file->id(),
'display' => (int) $settings['display_default'], 'display' => (int) $settings['display_default'],

View File

@ -7,6 +7,7 @@ use Drupal\Component\Utility\Crypt;
use Drupal\Core\Config\Config; use Drupal\Core\Config\Config;
use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface; use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Lock\LockBackendInterface; use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\AccountInterface;
@ -73,7 +74,7 @@ class FileUploadResource extends ResourceBase {
/** /**
* The file system service. * The file system service.
* *
* @var \Drupal\Core\File\FileSystemInterface * @var \Drupal\Core\File\FileSystem
*/ */
protected $fileSystem; protected $fileSystem;
@ -226,7 +227,7 @@ class FileUploadResource extends ResourceBase {
$destination = $this->getUploadLocation($field_definition->getSettings()); $destination = $this->getUploadLocation($field_definition->getSettings());
// Check the destination file path is writable. // Check the destination file path is writable.
if (!file_prepare_directory($destination, FILE_CREATE_DIRECTORY)) { if (!$this->fileSystem->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY)) {
throw new HttpException(500, 'Destination file path is not writable'); throw new HttpException(500, 'Destination file path is not writable');
} }
@ -239,8 +240,7 @@ class FileUploadResource extends ResourceBase {
$temp_file_path = $this->streamUploadData(); $temp_file_path = $this->streamUploadData();
// This will take care of altering $file_uri if a file already exists. $file_uri = $this->fileSystem->getDestinationFilename($file_uri, FileSystemInterface::EXISTS_RENAME);
file_unmanaged_prepare($temp_file_path, $file_uri);
// Lock based on the prepared file URI. // Lock based on the prepared file URI.
$lock_id = $this->generateLockIdFromFileUri($file_uri); $lock_id = $this->generateLockIdFromFileUri($file_uri);
@ -265,8 +265,11 @@ class FileUploadResource extends ResourceBase {
// Move the file to the correct location after validation. Use // Move the file to the correct location after validation. Use
// FILE_EXISTS_ERROR as the file location has already been determined above // FILE_EXISTS_ERROR as the file location has already been determined above
// in file_unmanaged_prepare(). // in FileSystem::getDestinationFilename().
if (!file_unmanaged_move($temp_file_path, $file_uri, FILE_EXISTS_ERROR)) { try {
$this->fileSystem->move($temp_file_path, $file_uri, FileSystemInterface::EXISTS_ERROR);
}
catch (FileException $e) {
throw new HttpException(500, 'Temporary file could not be moved to file location'); throw new HttpException(500, 'Temporary file could not be moved to file location');
} }

View File

@ -2,6 +2,7 @@
namespace Drupal\file_test\Form; namespace Drupal\file_test\Form;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormInterface; use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
@ -29,11 +30,11 @@ class FileTestForm implements FormInterface {
'#type' => 'select', '#type' => 'select',
'#title' => t('Replace existing image'), '#title' => t('Replace existing image'),
'#options' => [ '#options' => [
FILE_EXISTS_RENAME => t('Appends number until name is unique'), FileSystemInterface::EXISTS_RENAME => t('Appends number until name is unique'),
FILE_EXISTS_REPLACE => t('Replace the existing file'), FileSystemInterface::EXISTS_REPLACE => t('Replace the existing file'),
FILE_EXISTS_ERROR => t('Fail with an error'), FileSystemInterface::EXISTS_ERROR => t('Fail with an error'),
], ],
'#default_value' => FILE_EXISTS_RENAME, '#default_value' => FileSystemInterface::EXISTS_RENAME,
]; ];
$form['file_subdir'] = [ $form['file_subdir'] = [
'#type' => 'textfield', '#type' => 'textfield',
@ -79,7 +80,7 @@ class FileTestForm implements FormInterface {
// form value for the $replace parameter. // form value for the $replace parameter.
if (!$form_state->isValueEmpty('file_subdir')) { if (!$form_state->isValueEmpty('file_subdir')) {
$destination = 'temporary://' . $form_state->getValue('file_subdir'); $destination = 'temporary://' . $form_state->getValue('file_subdir');
file_prepare_directory($destination, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY);
} }
else { else {
$destination = FALSE; $destination = FALSE;

View File

@ -2,6 +2,7 @@
namespace Drupal\file_test\Form; namespace Drupal\file_test\Form;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Messenger\MessengerInterface;
@ -70,11 +71,11 @@ class FileTestSaveUploadFromForm extends FormBase {
'#type' => 'select', '#type' => 'select',
'#title' => $this->t('Replace existing image'), '#title' => $this->t('Replace existing image'),
'#options' => [ '#options' => [
FILE_EXISTS_RENAME => $this->t('Appends number until name is unique'), FileSystemInterface::EXISTS_RENAME => $this->t('Appends number until name is unique'),
FILE_EXISTS_REPLACE => $this->t('Replace the existing file'), FileSystemInterface::EXISTS_REPLACE => $this->t('Replace the existing file'),
FILE_EXISTS_ERROR => $this->t('Fail with an error'), FileSystemInterface::EXISTS_ERROR => $this->t('Fail with an error'),
], ],
'#default_value' => FILE_EXISTS_RENAME, '#default_value' => FileSystemInterface::EXISTS_RENAME,
]; ];
$form['file_subdir'] = [ $form['file_subdir'] = [
'#type' => 'textfield', '#type' => 'textfield',
@ -121,7 +122,7 @@ class FileTestSaveUploadFromForm extends FormBase {
// form value for the $replace parameter. // form value for the $replace parameter.
if (!$form_state->isValueEmpty('file_subdir')) { if (!$form_state->isValueEmpty('file_subdir')) {
$destination = 'temporary://' . $form_state->getValue('file_subdir'); $destination = 'temporary://' . $form_state->getValue('file_subdir');
file_prepare_directory($destination, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY);
} }
else { else {
$destination = FALSE; $destination = FALSE;

View File

@ -2,6 +2,8 @@
namespace Drupal\Tests\file\Functional; namespace Drupal\Tests\file\Functional;
use Drupal\Core\File\FileSystemInterface;
/** /**
* Tests for download/file transfer functions. * Tests for download/file transfer functions.
* *
@ -143,9 +145,9 @@ class DownloadTest extends FileManagedTestBase {
// Convert $filename to a valid filename, i.e. strip characters not // Convert $filename to a valid filename, i.e. strip characters not
// supported by the filesystem, and create the file in the specified // supported by the filesystem, and create the file in the specified
// directory. // directory.
$filepath = file_create_filename($filename, $directory); $filepath = \Drupal::service('file_system')->createFilename($filename, $directory);
$directory_uri = $scheme . '://' . dirname($filepath); $directory_uri = $scheme . '://' . dirname($filepath);
file_prepare_directory($directory_uri, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($directory_uri, FileSystemInterface::CREATE_DIRECTORY);
$file = $this->createFile($filepath, NULL, $scheme); $file = $this->createFile($filepath, NULL, $scheme);
$url = file_create_url($file->getFileUri()); $url = file_create_url($file->getFileUri());

View File

@ -168,7 +168,7 @@ class FileManagedFileElementTest extends FileFieldTestBase {
$file = $this->container->get('entity_type.manager')->getStorage('file')->load($fid); $file = $this->container->get('entity_type.manager')->getStorage('file')->load($fid);
$file->setPermanent(); $file->setPermanent();
$file->save(); $file->save();
$this->assertTrue(file_unmanaged_delete($file->getFileUri())); $this->assertTrue(\Drupal::service('file_system')->delete($file->getFileUri()));
$file->save(); $file->save();
$this->assertTrue($file->isPermanent()); $this->assertTrue($file->isPermanent());
$file->delete(); $file->delete();

View File

@ -2,6 +2,7 @@
namespace Drupal\Tests\file\Functional; namespace Drupal\Tests\file\Functional;
use Drupal\Core\File\FileSystemInterface;
use Drupal\file\Entity\File; use Drupal\file\Entity\File;
use Drupal\Tests\TestFileCreationTrait; use Drupal\Tests\TestFileCreationTrait;
@ -302,7 +303,7 @@ class SaveUploadFormTest extends FileManagedTestBase {
/** @var \Drupal\Core\File\FileSystemInterface $file_system */ /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system'); $file_system = \Drupal::service('file_system');
$edit = [ $edit = [
'file_test_replace' => FILE_EXISTS_RENAME, 'file_test_replace' => FileSystemInterface::EXISTS_RENAME,
'files[file_test_upload][]' => $file_system->realpath($this->image->getFileUri()), 'files[file_test_upload][]' => $file_system->realpath($this->image->getFileUri()),
]; ];
$this->drupalPostForm('file-test/save_upload_from_form_test', $edit, t('Submit')); $this->drupalPostForm('file-test/save_upload_from_form_test', $edit, t('Submit'));

View File

@ -2,6 +2,7 @@
namespace Drupal\Tests\file\Functional; namespace Drupal\Tests\file\Functional;
use Drupal\Core\File\FileSystemInterface;
use Drupal\file\Entity\File; use Drupal\file\Entity\File;
use Drupal\Tests\TestFileCreationTrait; use Drupal\Tests\TestFileCreationTrait;
@ -285,7 +286,7 @@ class SaveUploadTest extends FileManagedTestBase {
*/ */
public function testExistingRename() { public function testExistingRename() {
$edit = [ $edit = [
'file_test_replace' => FILE_EXISTS_RENAME, 'file_test_replace' => FileSystemInterface::EXISTS_RENAME,
'files[file_test_upload]' => \Drupal::service('file_system')->realpath($this->image->getFileUri()), 'files[file_test_upload]' => \Drupal::service('file_system')->realpath($this->image->getFileUri()),
]; ];
$this->drupalPostForm('file-test/upload', $edit, t('Submit')); $this->drupalPostForm('file-test/upload', $edit, t('Submit'));

View File

@ -2,6 +2,8 @@
namespace Drupal\Tests\file\Kernel; namespace Drupal\Tests\file\Kernel;
use Drupal\Core\File\FileSystemInterface;
/** /**
* Tests the file url. * Tests the file url.
* *
@ -15,9 +17,9 @@ class FileUrlTest extends FileManagedUnitTestBase {
public function testFilesUrlWithDifferentHostName() { public function testFilesUrlWithDifferentHostName() {
$test_base_url = 'http://www.example.com/cdn'; $test_base_url = 'http://www.example.com/cdn';
$this->setSetting('file_public_base_url', $test_base_url); $this->setSetting('file_public_base_url', $test_base_url);
$filepath = file_create_filename('test.txt', ''); $filepath = \Drupal::service('file_system')->createFilename('test.txt', '');
$directory_uri = 'public://' . dirname($filepath); $directory_uri = 'public://' . dirname($filepath);
file_prepare_directory($directory_uri, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($directory_uri, FileSystemInterface::CREATE_DIRECTORY);
$file = $this->createFile($filepath, NULL, 'public'); $file = $this->createFile($filepath, NULL, 'public');
$url = file_create_url($file->getFileUri()); $url = file_create_url($file->getFileUri());
$expected_url = $test_base_url . '/' . basename($filepath); $expected_url = $test_base_url . '/' . basename($filepath);

View File

@ -99,7 +99,7 @@ class FilterHtmlImageSecureTest extends BrowserTestBase {
$special_filename = 'tést fïle nàme.png'; $special_filename = 'tést fïle nàme.png';
$special_image = rawurlencode($special_filename); $special_image = rawurlencode($special_filename);
$special_uri = str_replace($test_images[0]->filename, $special_filename, $test_images[0]->uri); $special_uri = str_replace($test_images[0]->filename, $special_filename, $test_images[0]->uri);
file_unmanaged_copy($test_images[0]->uri, $special_uri); \Drupal::service('file_system')->copy($test_images[0]->uri, $special_uri);
// Create a list of test image sources. // Create a list of test image sources.
// The keys become the value of the IMG 'src' attribute, the values are the // The keys become the value of the IMG 'src' attribute, the values are the

View File

@ -5,13 +5,16 @@
* Install, update and uninstall functions for the image module. * Install, update and uninstall functions for the image module.
*/ */
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
/** /**
* Implements hook_install(). * Implements hook_install().
*/ */
function image_install() { function image_install() {
// Create the styles directory and ensure it's writable. // Create the styles directory and ensure it's writable.
$directory = file_default_scheme() . '://styles'; $directory = file_default_scheme() . '://styles';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
} }
/** /**
@ -19,7 +22,14 @@ function image_install() {
*/ */
function image_uninstall() { function image_uninstall() {
// Remove the styles directory and generated images. // Remove the styles directory and generated images.
file_unmanaged_delete_recursive(file_default_scheme() . '://styles'); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
try {
$file_system->deleteRecursive(file_default_scheme() . '://styles');
}
catch (FileException $e) {
// Ignore failed deletes.
}
} }
/** /**

View File

@ -6,6 +6,7 @@
*/ */
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\file\FileInterface; use Drupal\file\FileInterface;
use Drupal\field\FieldStorageConfigInterface; use Drupal\field\FieldStorageConfigInterface;
@ -434,7 +435,7 @@ function image_field_storage_config_update(FieldStorageConfigInterface $field_st
// If the upload destination changed, then move the file. // If the upload destination changed, then move the file.
if ($file_new && (file_uri_scheme($file_new->getFileUri()) != $field_storage->getSetting('uri_scheme'))) { if ($file_new && (file_uri_scheme($file_new->getFileUri()) != $field_storage->getSetting('uri_scheme'))) {
$directory = $field_storage->getSetting('uri_scheme') . '://default_images/'; $directory = $field_storage->getSetting('uri_scheme') . '://default_images/';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
file_move($file_new, $directory . $file_new->getFilename()); file_move($file_new, $directory . $file_new->getFilename());
} }
} }
@ -472,7 +473,7 @@ function image_field_config_update(FieldConfigInterface $field) {
// If the upload destination changed, then move the file. // If the upload destination changed, then move the file.
if ($file_new && (file_uri_scheme($file_new->getFileUri()) != $field_storage->getSetting('uri_scheme'))) { if ($file_new && (file_uri_scheme($file_new->getFileUri()) != $field_storage->getSetting('uri_scheme'))) {
$directory = $field_storage->getSetting('uri_scheme') . '://default_images/'; $directory = $field_storage->getSetting('uri_scheme') . '://default_images/';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
file_move($file_new, $directory . $file_new->getFilename()); file_move($file_new, $directory . $file_new->getFilename());
} }
} }

View File

@ -7,6 +7,7 @@ use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface; use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Image\ImageFactory; use Drupal\Core\Image\ImageFactory;
use Drupal\Core\Render\Element\StatusMessages; use Drupal\Core\Render\Element\StatusMessages;
use Drupal\Core\Render\RendererInterface; use Drupal\Core\Render\RendererInterface;
@ -49,6 +50,13 @@ class QuickEditImageController extends ControllerBase {
*/ */
protected $entityDisplayRepository; protected $entityDisplayRepository;
/**
* The file system.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/** /**
* Constructs a new QuickEditImageController. * Constructs a new QuickEditImageController.
* *
@ -60,8 +68,10 @@ class QuickEditImageController extends ControllerBase {
* The tempstore factory. * The tempstore factory.
* @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
* The entity display repository service. * The entity display repository service.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system.
*/ */
public function __construct(RendererInterface $renderer, ImageFactory $image_factory, PrivateTempStoreFactory $temp_store_factory, EntityDisplayRepositoryInterface $entity_display_repository = NULL) { public function __construct(RendererInterface $renderer, ImageFactory $image_factory, PrivateTempStoreFactory $temp_store_factory, EntityDisplayRepositoryInterface $entity_display_repository = NULL, FileSystemInterface $file_system = NULL) {
$this->renderer = $renderer; $this->renderer = $renderer;
$this->imageFactory = $image_factory; $this->imageFactory = $image_factory;
$this->tempStore = $temp_store_factory->get('quickedit'); $this->tempStore = $temp_store_factory->get('quickedit');
@ -70,6 +80,11 @@ class QuickEditImageController extends ControllerBase {
$entity_display_repository = \Drupal::service('entity_display.repository'); $entity_display_repository = \Drupal::service('entity_display.repository');
} }
$this->entityDisplayRepository = $entity_display_repository; $this->entityDisplayRepository = $entity_display_repository;
if (!$file_system) {
@trigger_error('The file_system service must be passed to QuickEditImageController::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
$file_system = \Drupal::service('file_system');
}
$this->fileSystem = $file_system;
} }
/** /**
@ -80,7 +95,8 @@ class QuickEditImageController extends ControllerBase {
$container->get('renderer'), $container->get('renderer'),
$container->get('image.factory'), $container->get('image.factory'),
$container->get('tempstore.private'), $container->get('tempstore.private'),
$container->get('entity_display.repository') $container->get('entity_display.repository'),
$container->get('file_system')
); );
} }
@ -111,7 +127,7 @@ class QuickEditImageController extends ControllerBase {
} }
// Create the destination directory if it does not already exist. // Create the destination directory if it does not already exist.
if (isset($destination) && !file_prepare_directory($destination, FILE_CREATE_DIRECTORY)) { if (isset($destination) && !$this->fileSystem->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY)) {
return new JsonResponse(['main_error' => $this->t('The destination directory could not be created.'), 'errors' => '']); return new JsonResponse(['main_error' => $this->t('The destination directory could not be created.'), 'errors' => '']);
} }

View File

@ -7,6 +7,8 @@ use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityWithPluginCollectionInterface; use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Routing\RequestHelper; use Drupal\Core\Routing\RequestHelper;
use Drupal\Core\Site\Settings; use Drupal\Core\Site\Settings;
use Drupal\Core\Url; use Drupal\Core\Url;
@ -251,10 +253,17 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface, Entity
*/ */
public function flush($path = NULL) { public function flush($path = NULL) {
// A specific image path has been provided. Flush only that derivative. // A specific image path has been provided. Flush only that derivative.
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
if (isset($path)) { if (isset($path)) {
$derivative_uri = $this->buildUri($path); $derivative_uri = $this->buildUri($path);
if (file_exists($derivative_uri)) { if (file_exists($derivative_uri)) {
file_unmanaged_delete($derivative_uri); try {
$file_system->delete($derivative_uri);
}
catch (FileException $e) {
// Ignore failed deletes.
}
} }
return $this; return $this;
} }
@ -263,7 +272,12 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface, Entity
$wrappers = $this->getStreamWrapperManager()->getWrappers(StreamWrapperInterface::WRITE_VISIBLE); $wrappers = $this->getStreamWrapperManager()->getWrappers(StreamWrapperInterface::WRITE_VISIBLE);
foreach ($wrappers as $wrapper => $wrapper_data) { foreach ($wrappers as $wrapper => $wrapper_data) {
if (file_exists($directory = $wrapper . '://styles/' . $this->id())) { if (file_exists($directory = $wrapper . '://styles/' . $this->id())) {
file_unmanaged_delete_recursive($directory); try {
$file_system->deleteRecursive($directory);
}
catch (FileException $e) {
// Ignore failed deletes.
}
} }
} }
@ -293,7 +307,7 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface, Entity
$directory = drupal_dirname($derivative_uri); $directory = drupal_dirname($derivative_uri);
// Build the destination folder tree if it doesn't already exist. // Build the destination folder tree if it doesn't already exist.
if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { if (!\Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
\Drupal::logger('image')->error('Failed to create style directory: %directory', ['%directory' => $directory]); \Drupal::logger('image')->error('Failed to create style directory: %directory', ['%directory' => $directory]);
return FALSE; return FALSE;
} }

View File

@ -6,6 +6,8 @@ use Drupal\Component\Utility\Random;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StreamWrapper\StreamWrapperInterface; use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\TypedData\DataDefinition;
@ -344,15 +346,22 @@ class ImageItem extends FileItem {
if (!isset($images[$extension][$min_resolution][$max_resolution]) || count($images[$extension][$min_resolution][$max_resolution]) <= 5) { if (!isset($images[$extension][$min_resolution][$max_resolution]) || count($images[$extension][$min_resolution][$max_resolution]) <= 5) {
$tmp_file = drupal_tempnam('temporary://', 'generateImage_'); $tmp_file = drupal_tempnam('temporary://', 'generateImage_');
$destination = $tmp_file . '.' . $extension; $destination = $tmp_file . '.' . $extension;
file_unmanaged_move($tmp_file, $destination); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
if ($path = $random->image(\Drupal::service('file_system')->realpath($destination), $min_resolution, $max_resolution)) { $file_system = \Drupal::service('file_system');
try {
$file_system->move($tmp_file, $destination);
}
catch (FileException $e) {
// Ignore failed move.
}
if ($path = $random->image($file_system->realpath($destination), $min_resolution, $max_resolution)) {
$image = File::create(); $image = File::create();
$image->setFileUri($path); $image->setFileUri($path);
$image->setOwnerId(\Drupal::currentUser()->id()); $image->setOwnerId(\Drupal::currentUser()->id());
$image->setMimeType(\Drupal::service('file.mime_type.guesser')->guess($path)); $image->setMimeType(\Drupal::service('file.mime_type.guesser')->guess($path));
$image->setFileName(drupal_basename($path)); $image->setFileName(drupal_basename($path));
$destination_dir = static::doGetUploadLocation($settings); $destination_dir = static::doGetUploadLocation($settings);
file_prepare_directory($destination_dir, FILE_CREATE_DIRECTORY); $file_system->prepareDirectory($destination_dir, FileSystemInterface::CREATE_DIRECTORY);
$destination = $destination_dir . '/' . basename($path); $destination = $destination_dir . '/' . basename($path);
$file = file_move($image, $destination); $file = file_move($image, $destination);
$images[$extension][$min_resolution][$max_resolution][$file->id()] = $file; $images[$extension][$min_resolution][$max_resolution][$file->id()] = $file;

View File

@ -2,6 +2,7 @@
namespace Drupal\Tests\image\Functional; namespace Drupal\Tests\image\Functional;
use Drupal\Core\File\FileSystemInterface;
use Drupal\file\Entity\File; use Drupal\file\Entity\File;
use Drupal\image\Entity\ImageStyle; use Drupal\image\Entity\ImageStyle;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
@ -46,7 +47,7 @@ class FileMoveTest extends BrowserTestBase {
// Clone the object so we don't have to worry about the function changing // Clone the object so we don't have to worry about the function changing
// our reference copy. // our reference copy.
$desired_filepath = 'public://' . $this->randomMachineName(); $desired_filepath = 'public://' . $this->randomMachineName();
$result = file_move(clone $file, $desired_filepath, FILE_EXISTS_ERROR); $result = file_move(clone $file, $desired_filepath, FileSystemInterface::EXISTS_ERROR);
// Check if image has been moved. // Check if image has been moved.
$this->assertTrue(file_exists($result->getFileUri()), 'Make sure image is moved successfully.'); $this->assertTrue(file_exists($result->getFileUri()), 'Make sure image is moved successfully.');

View File

@ -33,7 +33,7 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
if (!isset($file_path)) { if (!isset($file_path)) {
$files = $this->drupalGetTestFiles('image'); $files = $this->drupalGetTestFiles('image');
$file = reset($files); $file = reset($files);
$file_path = file_unmanaged_copy($file->uri); $file_path = \Drupal::service('file_system')->copy($file->uri);
} }
return $style->buildUrl($file_path) ? $file_path : FALSE; return $style->buildUrl($file_path) ? $file_path : FALSE;

View File

@ -2,6 +2,7 @@
namespace Drupal\Tests\image\Functional; namespace Drupal\Tests\image\Functional;
use Drupal\Core\File\FileSystemInterface;
use Drupal\image\Entity\ImageStyle; use Drupal\image\Entity\ImageStyle;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\TestFileCreationTrait; use Drupal\Tests\TestFileCreationTrait;
@ -35,13 +36,15 @@ class ImageDimensionsTest extends BrowserTestBase {
// Create a working copy of the file. // Create a working copy of the file.
$files = $this->drupalGetTestFiles('image'); $files = $this->drupalGetTestFiles('image');
$file = reset($files); $file = reset($files);
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$original_uri = $file_system->copy($file->uri, 'public://', FileSystemInterface::EXISTS_RENAME);
// Create a style. // Create a style.
/** @var $style \Drupal\image\ImageStyleInterface */ /** @var $style \Drupal\image\ImageStyleInterface */
$style = ImageStyle::create(['name' => 'test', 'label' => 'Test']); $style = ImageStyle::create(['name' => 'test', 'label' => 'Test']);
$style->save(); $style->save();
$generated_uri = 'public://styles/test/public/' . \Drupal::service('file_system')->basename($original_uri); $generated_uri = 'public://styles/test/public/' . $file_system->basename($original_uri);
$url = file_url_transform_relative($style->buildUrl($original_uri)); $url = file_url_transform_relative($style->buildUrl($original_uri));
$variables = [ $variables = [
@ -257,7 +260,7 @@ class ImageDimensionsTest extends BrowserTestBase {
'#height' => 20, '#height' => 20,
]; ];
// PNG original image. Should be resized to 100x100. // PNG original image. Should be resized to 100x100.
$generated_uri = 'public://styles/test_uri/public/' . \Drupal::service('file_system')->basename($original_uri); $generated_uri = 'public://styles/test_uri/public/' . $file_system->basename($original_uri);
$url = file_url_transform_relative($style->buildUrl($original_uri)); $url = file_url_transform_relative($style->buildUrl($original_uri));
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="100" height="100" alt="" class="image-style-test-uri" />'); $this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="100" height="100" alt="" class="image-style-test-uri" />');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.'); $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
@ -269,8 +272,8 @@ class ImageDimensionsTest extends BrowserTestBase {
$this->assertEqual($image_file->getHeight(), 100); $this->assertEqual($image_file->getHeight(), 100);
// GIF original image. Should be resized to 50x50. // GIF original image. Should be resized to 50x50.
$file = $files[1]; $file = $files[1];
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME); $original_uri = $file_system->copy($file->uri, 'public://', FileSystemInterface::EXISTS_RENAME);
$generated_uri = 'public://styles/test_uri/public/' . \Drupal::service('file_system')->basename($original_uri); $generated_uri = 'public://styles/test_uri/public/' . $file_system->basename($original_uri);
$url = file_url_transform_relative($style->buildUrl($original_uri)); $url = file_url_transform_relative($style->buildUrl($original_uri));
$variables['#uri'] = $original_uri; $variables['#uri'] = $original_uri;
$this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="50" height="50" alt="" class="image-style-test-uri" />'); $this->assertEqual($this->getImageTag($variables), '<img src="' . $url . '" width="50" height="50" alt="" class="image-style-test-uri" />');

View File

@ -42,7 +42,7 @@ class ImageFieldDefaultImagesTest extends ImageFieldTestBase {
for ($i = 1; $i <= 10; $i++) { for ($i = 1; $i <= 10; $i++) {
$filename = $this->randomMachineName() . "$i"; $filename = $this->randomMachineName() . "$i";
$desired_filepath = 'public://' . $filename; $desired_filepath = 'public://' . $filename;
file_unmanaged_copy($files[0]->uri, $desired_filepath, FILE_EXISTS_ERROR); \Drupal::service('file_system')->copy($files[0]->uri, $desired_filepath, FILE_EXISTS_ERROR);
$file = File::create(['uri' => $desired_filepath, 'filename' => $filename, 'name' => $filename]); $file = File::create(['uri' => $desired_filepath, 'filename' => $filename, 'name' => $filename]);
$file->save(); $file->save();
} }

View File

@ -29,7 +29,7 @@ class ImageStyleFlushTest extends ImageFieldTestBase {
} }
// Make sure we have an image in our wrapper testing file directory. // Make sure we have an image in our wrapper testing file directory.
$source_uri = file_unmanaged_copy($file->uri, $wrapper . '://'); $source_uri = \Drupal::service('file_system')->copy($file->uri, $wrapper . '://');
// Build the derivative image. // Build the derivative image.
$derivative_uri = $style->buildUri($source_uri); $derivative_uri = $style->buildUri($source_uri);
$derivative = $style->createDerivative($source_uri, $derivative_uri); $derivative = $style->createDerivative($source_uri, $derivative_uri);

View File

@ -2,6 +2,7 @@
namespace Drupal\Tests\image\Functional; namespace Drupal\Tests\image\Functional;
use Drupal\Core\File\FileSystemInterface;
use Drupal\image\Entity\ImageStyle; use Drupal\image\Entity\ImageStyle;
use Drupal\language\Entity\ConfigurableLanguage; use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
@ -134,7 +135,7 @@ class ImageStylesPathAndUrlTest extends BrowserTestBase {
// Create the directories for the styles. // Create the directories for the styles.
$directory = $scheme . '://styles/' . $this->style->id(); $directory = $scheme . '://styles/' . $this->style->id();
$status = file_prepare_directory($directory, FILE_CREATE_DIRECTORY); $status = \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
$this->assertNotIdentical(FALSE, $status, 'Created the directory for the generated images for the test style.'); $this->assertNotIdentical(FALSE, $status, 'Created the directory for the generated images for the test style.');
// Override the language to build the URL for the correct language. // Override the language to build the URL for the correct language.
@ -147,7 +148,9 @@ class ImageStylesPathAndUrlTest extends BrowserTestBase {
// Create a working copy of the file. // Create a working copy of the file.
$files = $this->drupalGetTestFiles('image'); $files = $this->drupalGetTestFiles('image');
$file = array_shift($files); $file = array_shift($files);
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$original_uri = $file_system->copy($file->uri, $scheme . '://', FileSystemInterface::EXISTS_RENAME);
// Let the image_module_test module know about this file, so it can claim // Let the image_module_test module know about this file, so it can claim
// ownership in hook_file_download(). // ownership in hook_file_download().
\Drupal::state()->set('image.test_file_download', $original_uri); \Drupal::state()->set('image.test_file_download', $original_uri);
@ -231,7 +234,7 @@ class ImageStylesPathAndUrlTest extends BrowserTestBase {
// Repeat this with a different file that we do not have access to and // Repeat this with a different file that we do not have access to and
// make sure that access is denied. // make sure that access is denied.
$file_noaccess = array_shift($files); $file_noaccess = array_shift($files);
$original_uri_noaccess = file_unmanaged_copy($file_noaccess->uri, $scheme . '://', FILE_EXISTS_RENAME); $original_uri_noaccess = $file_system->copy($file_noaccess->uri, $scheme . '://', FileSystemInterface::EXISTS_RENAME);
$generated_uri_noaccess = $scheme . '://styles/' . $this->style->id() . '/' . $scheme . '/' . drupal_basename($original_uri_noaccess); $generated_uri_noaccess = $scheme . '://styles/' . $this->style->id() . '/' . $scheme . '/' . drupal_basename($original_uri_noaccess);
$this->assertFalse(file_exists($generated_uri_noaccess), 'Generated file does not exist.'); $this->assertFalse(file_exists($generated_uri_noaccess), 'Generated file does not exist.');
$generate_url_noaccess = $this->style->buildUrl($original_uri_noaccess); $generate_url_noaccess = $this->style->buildUrl($original_uri_noaccess);
@ -271,7 +274,7 @@ class ImageStylesPathAndUrlTest extends BrowserTestBase {
// Create another working copy of the file. // Create another working copy of the file.
$files = $this->drupalGetTestFiles('image'); $files = $this->drupalGetTestFiles('image');
$file = array_shift($files); $file = array_shift($files);
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME); $original_uri = $file_system->copy($file->uri, $scheme . '://', FileSystemInterface::EXISTS_RENAME);
// Let the image_module_test module know about this file, so it can claim // Let the image_module_test module know about this file, so it can claim
// ownership in hook_file_download(). // ownership in hook_file_download().
\Drupal::state()->set('image.test_file_download', $original_uri); \Drupal::state()->set('image.test_file_download', $original_uri);

View File

@ -67,7 +67,7 @@ class ImageItemTest extends FieldKernelTestBase {
'file_extensions' => 'jpg', 'file_extensions' => 'jpg',
], ],
])->save(); ])->save();
file_unmanaged_copy($this->root . '/core/misc/druplicon.png', 'public://example.jpg'); \Drupal::service('file_system')->copy($this->root . '/core/misc/druplicon.png', 'public://example.jpg');
$this->image = File::create([ $this->image = File::create([
'uri' => 'public://example.jpg', 'uri' => 'public://example.jpg',
]); ]);
@ -100,7 +100,7 @@ class ImageItemTest extends FieldKernelTestBase {
$this->assertEqual($entity->image_test->entity->uuid(), $this->image->uuid()); $this->assertEqual($entity->image_test->entity->uuid(), $this->image->uuid());
// Make sure the computed entity reflects updates to the referenced file. // Make sure the computed entity reflects updates to the referenced file.
file_unmanaged_copy($this->root . '/core/misc/druplicon.png', 'public://example-2.jpg'); \Drupal::service('file_system')->copy($this->root . '/core/misc/druplicon.png', 'public://example-2.jpg');
$image2 = File::create([ $image2 = File::create([
'uri' => 'public://example-2.jpg', 'uri' => 'public://example-2.jpg',
]); ]);

View File

@ -3,6 +3,7 @@
namespace Drupal\Tests\image\Kernel; namespace Drupal\Tests\image\Kernel;
use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\entity_test\Entity\EntityTest; use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldConfig;
@ -62,7 +63,7 @@ class ImageThemeFunctionTest extends KernelTestBase {
'field_name' => 'image_test', 'field_name' => 'image_test',
'bundle' => 'entity_test', 'bundle' => 'entity_test',
])->save(); ])->save();
file_unmanaged_copy($this->root . '/core/misc/druplicon.png', 'public://example.jpg'); \Drupal::service('file_system')->copy($this->root . '/core/misc/druplicon.png', 'public://example.jpg');
$this->image = File::create([ $this->image = File::create([
'uri' => 'public://example.jpg', 'uri' => 'public://example.jpg',
]); ]);
@ -80,7 +81,7 @@ class ImageThemeFunctionTest extends KernelTestBase {
// Create an image. // Create an image.
$files = $this->drupalGetTestFiles('image'); $files = $this->drupalGetTestFiles('image');
$file = reset($files); $file = reset($files);
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME); $original_uri = \Drupal::service('file_system')->copy($file->uri, 'public://', FileSystemInterface::EXISTS_RENAME);
// Create a style. // Create a style.
$style = ImageStyle::create(['name' => 'test', 'label' => 'Test']); $style = ImageStyle::create(['name' => 'test', 'label' => 'Test']);
@ -142,7 +143,7 @@ class ImageThemeFunctionTest extends KernelTestBase {
// Create an image. // Create an image.
$files = $this->drupalGetTestFiles('image'); $files = $this->drupalGetTestFiles('image');
$file = reset($files); $file = reset($files);
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME); $original_uri = \Drupal::service('file_system')->copy($file->uri, 'public://', FileSystemInterface::EXISTS_RENAME);
// Create a style. // Create a style.
$style = ImageStyle::create(['name' => 'image_test', 'label' => 'Test']); $style = ImageStyle::create(['name' => 'image_test', 'label' => 'Test']);

View File

@ -5,6 +5,7 @@
* Mass import-export and batch import functionality for Gettext .po files. * Mass import-export and batch import functionality for Gettext .po files.
*/ */
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageInterface;
use Drupal\file\FileInterface; use Drupal\file\FileInterface;
use Drupal\locale\Gettext; use Drupal\locale\Gettext;
@ -506,8 +507,10 @@ function locale_translate_delete_translation_files(array $projects = [], array $
// Delete all translation files from the translations directory. // Delete all translation files from the translations directory.
if ($files = locale_translate_get_interface_translation_files($projects, $langcodes)) { if ($files = locale_translate_get_interface_translation_files($projects, $langcodes)) {
foreach ($files as $file) { foreach ($files as $file) {
$success = file_unmanaged_delete($file->uri); try {
if (!$success) { \Drupal::service('file_system')->delete($file->uri);
}
catch (FileException $e) {
$fail = TRUE; $fail = TRUE;
} }
} }

View File

@ -5,6 +5,8 @@
* Install, update, and uninstall functions for the Locale module. * Install, update, and uninstall functions for the Locale module.
*/ */
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
/** /**
@ -17,7 +19,7 @@ function locale_install() {
$directory = $site_path . '/files/translations'; $directory = $site_path . '/files/translations';
\Drupal::configFactory()->getEditable('locale.settings')->set('translation.path', $directory)->save(); \Drupal::configFactory()->getEditable('locale.settings')->set('translation.path', $directory)->save();
} }
file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
} }
/** /**
@ -32,7 +34,12 @@ function locale_uninstall() {
$locale_javascripts = \Drupal::state()->get('locale.translation.javascript') ?: []; $locale_javascripts = \Drupal::state()->get('locale.translation.javascript') ?: [];
foreach ($locale_javascripts as $langcode => $file_suffix) { foreach ($locale_javascripts as $langcode => $file_suffix) {
if (!empty($file_suffix)) { if (!empty($file_suffix)) {
file_unmanaged_delete($locale_js_directory . '/' . $langcode . '_' . $file_suffix . '.js'); try {
\Drupal::service('file_system')->delete($locale_js_directory . '/' . $langcode . '_' . $file_suffix . '.js');
}
catch (FileException $e) {
// Ignore and continue.
}
} }
} }
// Delete the JavaScript translations directory if empty. // Delete the JavaScript translations directory if empty.

View File

@ -15,6 +15,8 @@ use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Xss; use Drupal\Component\Utility\Xss;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Core\Asset\AttachedAssetsInterface; use Drupal\Core\Asset\AttachedAssetsInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
@ -1298,8 +1300,17 @@ function _locale_rebuild_js($langcode = NULL) {
// be saved. // be saved.
$locale_javascripts = \Drupal::state()->get('locale.translation.javascript') ?: []; $locale_javascripts = \Drupal::state()->get('locale.translation.javascript') ?: [];
$changed_hash = !isset($locale_javascripts[$language->getId()]) || ($locale_javascripts[$language->getId()] != $data_hash); $changed_hash = !isset($locale_javascripts[$language->getId()]) || ($locale_javascripts[$language->getId()] != $data_hash);
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
if (!empty($locale_javascripts[$language->getId()]) && (!$data || $changed_hash)) { if (!empty($locale_javascripts[$language->getId()]) && (!$data || $changed_hash)) {
file_unmanaged_delete($dir . '/' . $language->getId() . '_' . $locale_javascripts[$language->getId()] . '.js'); try {
$file_system->delete($dir . '/' . $language->getId() . '_' . $locale_javascripts[$language->getId()] . '.js');
}
catch (FileException $e) {
// Ignore.
}
$locale_javascripts[$language->getId()] = ''; $locale_javascripts[$language->getId()] = '';
$status = 'deleted'; $status = 'deleted';
} }
@ -1309,30 +1320,35 @@ function _locale_rebuild_js($langcode = NULL) {
$dest = $dir . '/' . $language->getId() . '_' . $data_hash . '.js'; $dest = $dir . '/' . $language->getId() . '_' . $data_hash . '.js';
if ($data && ($changed_hash || !file_exists($dest))) { if ($data && ($changed_hash || !file_exists($dest))) {
// Ensure that the directory exists and is writable, if possible. // Ensure that the directory exists and is writable, if possible.
file_prepare_directory($dir, FILE_CREATE_DIRECTORY); $file_system->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY);
// Save the file. // Save the file.
if (file_unmanaged_save_data($data, $dest)) { try {
$locale_javascripts[$language->getId()] = $data_hash; if ($file_system->saveData($data, $dest)) {
// If we deleted a previous version of the file and we replace it with a $locale_javascripts[$language->getId()] = $data_hash;
// new one we have an update. // If we deleted a previous version of the file and we replace it with a
if ($status == 'deleted') { // new one we have an update.
$status = 'updated'; if ($status == 'deleted') {
$status = 'updated';
}
// If the file did not exist previously and the data has changed we have
// a fresh creation.
elseif ($changed_hash) {
$status = 'created';
}
// If the data hash is unchanged the translation was lost and has to be
// rebuilt.
else {
$status = 'rebuilt';
}
} }
// If the file did not exist previously and the data has changed we have
// a fresh creation.
elseif ($changed_hash) {
$status = 'created';
}
// If the data hash is unchanged the translation was lost and has to be
// rebuilt.
else { else {
$status = 'rebuilt'; $locale_javascripts[$language->getId()] = '';
$status = 'error';
} }
} }
else { catch (FileException $e) {
$locale_javascripts[$language->getId()] = ''; // Do nothing.
$status = 'error';
} }
} }

View File

@ -33,8 +33,8 @@ class LocaleExportTest extends BrowserTestBase {
$this->drupalLogin($this->adminUser); $this->drupalLogin($this->adminUser);
// Copy test po files to the translations directory. // Copy test po files to the translations directory.
file_unmanaged_copy(__DIR__ . '/../../tests/test.de.po', 'translations://', FILE_EXISTS_REPLACE); \Drupal::service('file_system')->copy(__DIR__ . '/../../../tests/test.de.po', 'translations://', FILE_EXISTS_REPLACE);
file_unmanaged_copy(__DIR__ . '/../../tests/test.xx.po', 'translations://', FILE_EXISTS_REPLACE); \Drupal::service('file_system')->copy(__DIR__ . '/../../../tests/test.xx.po', 'translations://', FILE_EXISTS_REPLACE);
} }
/** /**

View File

@ -41,8 +41,10 @@ class LocaleImportFunctionalTest extends BrowserTestBase {
parent::setUp(); parent::setUp();
// Copy test po files to the translations directory. // Copy test po files to the translations directory.
file_unmanaged_copy(__DIR__ . '/../../tests/test.de.po', 'translations://', FILE_EXISTS_REPLACE); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
file_unmanaged_copy(__DIR__ . '/../../tests/test.xx.po', 'translations://', FILE_EXISTS_REPLACE); $file_system = \Drupal::service('file_system');
$file_system->copy(__DIR__ . '/../../../tests/test.de.po', 'translations://', FILE_EXISTS_REPLACE);
$file_system->copy(__DIR__ . '/../../../tests/test.xx.po', 'translations://', FILE_EXISTS_REPLACE);
$this->adminUser = $this->drupalCreateUser(['administer languages', 'translate interface', 'access administration pages']); $this->adminUser = $this->drupalCreateUser(['administer languages', 'translate interface', 'access administration pages']);
$this->adminUserAccessSiteReports = $this->drupalCreateUser(['administer languages', 'translate interface', 'access administration pages', 'access site reports']); $this->adminUserAccessSiteReports = $this->drupalCreateUser(['administer languages', 'translate interface', 'access administration pages', 'access site reports']);

View File

@ -263,7 +263,7 @@ class LocaleTranslationUiTest extends BrowserTestBase {
$this->assertTrue($result = file_exists($js_file), new FormattableMarkup('JavaScript file created: %file', ['%file' => $result ? $js_file : 'not found'])); $this->assertTrue($result = file_exists($js_file), new FormattableMarkup('JavaScript file created: %file', ['%file' => $result ? $js_file : 'not found']));
// Test JavaScript translation rebuilding. // Test JavaScript translation rebuilding.
file_unmanaged_delete($js_file); \Drupal::service('file_system')->delete($js_file);
$this->assertTrue($result = !file_exists($js_file), new FormattableMarkup('JavaScript file deleted: %file', ['%file' => $result ? $js_file : 'found'])); $this->assertTrue($result = !file_exists($js_file), new FormattableMarkup('JavaScript file deleted: %file', ['%file' => $result ? $js_file : 'found']));
_locale_rebuild_js($langcode); _locale_rebuild_js($langcode);
$this->assertTrue($result = file_exists($js_file), new FormattableMarkup('JavaScript file rebuilt: %file', ['%file' => $result ? $js_file : 'not found'])); $this->assertTrue($result = file_exists($js_file), new FormattableMarkup('JavaScript file rebuilt: %file', ['%file' => $result ? $js_file : 'not found']));

View File

@ -3,6 +3,7 @@
namespace Drupal\Tests\locale\Functional; namespace Drupal\Tests\locale\Functional;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\StreamWrapper\PublicStream; use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\file\Entity\File; use Drupal\file\Entity\File;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
@ -76,7 +77,7 @@ abstract class LocaleUpdateBase extends BrowserTestBase {
* directory. * directory.
*/ */
protected function setTranslationsDirectory($path) { protected function setTranslationsDirectory($path) {
file_prepare_directory($path, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY);
$this->config('locale.settings')->set('translation.path', $path)->save(); $this->config('locale.settings')->set('translation.path', $path)->save();
} }
@ -130,7 +131,7 @@ EOF;
} }
} }
file_prepare_directory($path, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY);
$file = File::create([ $file = File::create([
'uid' => 1, 'uid' => 1,
'filename' => $filename, 'filename' => $filename,

View File

@ -5,11 +5,13 @@
* Install, uninstall and update hooks for Media module. * Install, uninstall and update hooks for Media module.
*/ */
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\media\MediaTypeInterface; use Drupal\media\MediaTypeInterface;
use Drupal\media\Plugin\media\Source\OEmbedInterface; use Drupal\media\Plugin\media\Source\OEmbedInterface;
use Drupal\user\RoleInterface;
use Drupal\user\Entity\Role; use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
/** /**
* Implements hook_install(). * Implements hook_install().
@ -17,7 +19,9 @@ use Drupal\user\Entity\Role;
function media_install() { function media_install() {
$source = drupal_get_path('module', 'media') . '/images/icons'; $source = drupal_get_path('module', 'media') . '/images/icons';
$destination = \Drupal::config('media.settings')->get('icon_base_uri'); $destination = \Drupal::config('media.settings')->get('icon_base_uri');
file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$file_system->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
$files = file_scan_directory($source, '/.*\.(svg|png|jpg|jpeg|gif)$/'); $files = file_scan_directory($source, '/.*\.(svg|png|jpg|jpeg|gif)$/');
foreach ($files as $file) { foreach ($files as $file) {
@ -28,7 +32,13 @@ function media_install() {
// referenced somewhere else. Since showing an error that it was not // referenced somewhere else. Since showing an error that it was not
// possible to copy the files is also confusing, we silently do nothing. // possible to copy the files is also confusing, we silently do nothing.
if (!file_exists($destination . DIRECTORY_SEPARATOR . $file->filename)) { if (!file_exists($destination . DIRECTORY_SEPARATOR . $file->filename)) {
file_unmanaged_copy($file->uri, $destination, FILE_EXISTS_ERROR); try {
$file_system->copy($file->uri, $destination, FileSystemInterface::EXISTS_ERROR);
}
catch (FileException $e) {
// Ignore and continue.
}
} }
} }
@ -46,7 +56,7 @@ function media_requirements($phase) {
$requirements = []; $requirements = [];
if ($phase == 'install') { if ($phase == 'install') {
$destination = 'public://media-icons/generic'; $destination = 'public://media-icons/generic';
file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); \Drupal::service('file_system')->prepareDirectory($destination, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
$is_writable = is_writable($destination); $is_writable = is_writable($destination);
$is_directory = is_dir($destination); $is_directory = is_dir($destination);
if (!$is_writable || !$is_directory) { if (!$is_writable || !$is_directory) {

View File

@ -9,6 +9,8 @@ use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
@ -114,6 +116,13 @@ class OEmbed extends MediaSourceBase implements OEmbedInterface {
*/ */
protected $iFrameUrlHelper; protected $iFrameUrlHelper;
/**
* The file system.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/** /**
* Constructs a new OEmbed instance. * Constructs a new OEmbed instance.
* *
@ -143,8 +152,10 @@ class OEmbed extends MediaSourceBase implements OEmbedInterface {
* The oEmbed URL resolver service. * The oEmbed URL resolver service.
* @param \Drupal\media\IFrameUrlHelper $iframe_url_helper * @param \Drupal\media\IFrameUrlHelper $iframe_url_helper
* The iFrame URL helper service. * The iFrame URL helper service.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system.
*/ */
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, FieldTypePluginManagerInterface $field_type_manager, LoggerInterface $logger, MessengerInterface $messenger, ClientInterface $http_client, ResourceFetcherInterface $resource_fetcher, UrlResolverInterface $url_resolver, IFrameUrlHelper $iframe_url_helper) { public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, FieldTypePluginManagerInterface $field_type_manager, LoggerInterface $logger, MessengerInterface $messenger, ClientInterface $http_client, ResourceFetcherInterface $resource_fetcher, UrlResolverInterface $url_resolver, IFrameUrlHelper $iframe_url_helper, FileSystemInterface $file_system = NULL) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $field_type_manager, $config_factory); parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $field_type_manager, $config_factory);
$this->logger = $logger; $this->logger = $logger;
$this->messenger = $messenger; $this->messenger = $messenger;
@ -152,6 +163,11 @@ class OEmbed extends MediaSourceBase implements OEmbedInterface {
$this->resourceFetcher = $resource_fetcher; $this->resourceFetcher = $resource_fetcher;
$this->urlResolver = $url_resolver; $this->urlResolver = $url_resolver;
$this->iFrameUrlHelper = $iframe_url_helper; $this->iFrameUrlHelper = $iframe_url_helper;
if (!$file_system) {
@trigger_error('The file_system service must be passed to OEmbed::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
$file_system = \Drupal::service('file_system');
}
$this->fileSystem = $file_system;
} }
/** /**
@ -171,7 +187,8 @@ class OEmbed extends MediaSourceBase implements OEmbedInterface {
$container->get('http_client'), $container->get('http_client'),
$container->get('media.oembed.resource_fetcher'), $container->get('media.oembed.resource_fetcher'),
$container->get('media.oembed.url_resolver'), $container->get('media.oembed.url_resolver'),
$container->get('media.oembed.iframe_url_helper') $container->get('media.oembed.iframe_url_helper'),
$container->get('file_system')
); );
} }
@ -381,33 +398,28 @@ class OEmbed extends MediaSourceBase implements OEmbedInterface {
// The local thumbnail doesn't exist yet, so try to download it. First, // The local thumbnail doesn't exist yet, so try to download it. First,
// ensure that the destination directory is writable, and if it's not, // ensure that the destination directory is writable, and if it's not,
// log an error and bail out. // log an error and bail out.
if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { if (!$this->fileSystem->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
$this->logger->warning('Could not prepare thumbnail destination directory @dir for oEmbed media.', [ $this->logger->warning('Could not prepare thumbnail destination directory @dir for oEmbed media.', [
'@dir' => $directory, '@dir' => $directory,
]); ]);
return NULL; return NULL;
} }
$error_message = 'Could not download remote thumbnail from {url}.';
$error_context = [
'url' => $remote_thumbnail_url,
];
try { try {
$response = $this->httpClient->get($remote_thumbnail_url); $response = $this->httpClient->get($remote_thumbnail_url);
if ($response->getStatusCode() === 200) { if ($response->getStatusCode() === 200) {
$success = file_unmanaged_save_data((string) $response->getBody(), $local_thumbnail_uri, FILE_EXISTS_REPLACE); $this->fileSystem->saveData((string) $response->getBody(), $local_thumbnail_uri, FileSystemInterface::EXISTS_REPLACE);
return $local_thumbnail_uri;
if ($success) {
return $local_thumbnail_uri;
}
else {
$this->logger->warning($error_message, $error_context);
}
} }
} }
catch (RequestException $e) { catch (RequestException $e) {
$this->logger->warning($e->getMessage()); $this->logger->warning($e->getMessage());
} }
catch (FileException $e) {
$this->logger->warning('Could not download remote thumbnail from {url}.', [
'url' => $remote_thumbnail_url,
]);
}
return NULL; return NULL;
} }

View File

@ -80,7 +80,7 @@ class MediaSourceFileTest extends MediaSourceTestBase {
// Test the MIME type icon. // Test the MIME type icon.
$icon_base = \Drupal::config('media.settings')->get('icon_base_uri'); $icon_base = \Drupal::config('media.settings')->get('icon_base_uri');
file_unmanaged_copy($icon_base . '/generic.png', $icon_base . '/text--plain.png'); \Drupal::service('file_system')->copy($icon_base . '/generic.png', $icon_base . '/text--plain.png');
$this->drupalGet("media/add/{$media_type_id}"); $this->drupalGet("media/add/{$media_type_id}");
$page->attachFileToField("files[{$source_field_id}_0]", \Drupal::service('file_system')->realpath($test_filepath)); $page->attachFileToField("files[{$source_field_id}_0]", \Drupal::service('file_system')->realpath($test_filepath));
$result = $assert_session->waitForButton('Remove'); $result = $assert_session->waitForButton('Remove');

View File

@ -6,6 +6,8 @@ use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\TypedData\FieldItemDataDefinition; use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
use Drupal\Core\File\Exception\FileWriteException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\ElementInfoManagerInterface; use Drupal\Core\Render\ElementInfoManagerInterface;
use Drupal\Core\Render\RendererInterface; use Drupal\Core\Render\RendererInterface;
@ -41,6 +43,13 @@ class FileUploadForm extends AddFormBase {
*/ */
protected $renderer; protected $renderer;
/**
* The file system service.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/** /**
* Constructs a new FileUploadForm. * Constructs a new FileUploadForm.
* *
@ -52,11 +61,14 @@ class FileUploadForm extends AddFormBase {
* The element info manager. * The element info manager.
* @param \Drupal\Core\Render\RendererInterface $renderer * @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer service. * The renderer service.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system service.
*/ */
public function __construct(EntityTypeManagerInterface $entity_type_manager, MediaLibraryUiBuilder $library_ui_builder, ElementInfoManagerInterface $element_info, RendererInterface $renderer) { public function __construct(EntityTypeManagerInterface $entity_type_manager, MediaLibraryUiBuilder $library_ui_builder, ElementInfoManagerInterface $element_info, RendererInterface $renderer, FileSystemInterface $file_system) {
parent::__construct($entity_type_manager, $library_ui_builder); parent::__construct($entity_type_manager, $library_ui_builder);
$this->elementInfo = $element_info; $this->elementInfo = $element_info;
$this->renderer = $renderer; $this->renderer = $renderer;
$this->fileSystem = $file_system;
} }
/** /**
@ -67,7 +79,8 @@ class FileUploadForm extends AddFormBase {
$container->get('entity_type.manager'), $container->get('entity_type.manager'),
$container->get('media_library.ui_builder'), $container->get('media_library.ui_builder'),
$container->get('element_info'), $container->get('element_info'),
$container->get('renderer') $container->get('renderer'),
$container->get('file_system')
); );
} }
@ -209,8 +222,8 @@ class FileUploadForm extends AddFormBase {
// Create a file item to get the upload location. // Create a file item to get the upload location.
$item = $this->createFileItem($media_type); $item = $this->createFileItem($media_type);
$upload_location = $item->getUploadLocation(); $upload_location = $item->getUploadLocation();
if (!file_prepare_directory($upload_location, FILE_CREATE_DIRECTORY)) { if (!$this->fileSystem->prepareDirectory($upload_location, FileSystemInterface::CREATE_DIRECTORY)) {
throw new \Exception("The destination directory '$upload_location' is not writable"); throw new FileWriteException("The destination directory '$upload_location' is not writable");
} }
$file = file_move($file, $upload_location); $file = file_move($file, $upload_location);
if (!$file) { if (!$file) {

View File

@ -120,21 +120,21 @@ class Download extends FileProcessBase implements ContainerFactoryPluginInterfac
list($source, $destination) = $value; list($source, $destination) = $value;
// Modify the destination filename if necessary. // Modify the destination filename if necessary.
$final_destination = file_destination($destination, $this->configuration['file_exists']); $final_destination = $this->fileSystem->getDestinationFilename($destination, $this->configuration['file_exists']);
// Reuse if file exists. // Reuse if file exists.
if (!$final_destination) { if (!$final_destination) {
return $destination; return $destination;
} }
// Try opening the file first, to avoid calling file_prepare_directory() // Try opening the file first, to avoid calling prepareDirectory()
// unnecessarily. We're suppressing fopen() errors because we want to try // unnecessarily. We're suppressing fopen() errors because we want to try
// to prepare the directory before we give up and fail. // to prepare the directory before we give up and fail.
$destination_stream = @fopen($final_destination, 'w'); $destination_stream = @fopen($final_destination, 'w');
if (!$destination_stream) { if (!$destination_stream) {
// If fopen didn't work, make sure there's a writable directory in place. // If fopen didn't work, make sure there's a writable directory in place.
$dir = $this->fileSystem->dirname($final_destination); $dir = $this->fileSystem->dirname($final_destination);
if (!file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { if (!$this->fileSystem->prepareDirectory($dir, FileSystemInterface:: CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
throw new MigrateException("Could not create or write to directory '$dir'"); throw new MigrateException("Could not create or write to directory '$dir'");
} }
// Let's try that fopen again. // Let's try that fopen again.

View File

@ -2,6 +2,7 @@
namespace Drupal\migrate\Plugin\migrate\process; namespace Drupal\migrate\Plugin\migrate\process;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface; use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StreamWrapper\LocalStream; use Drupal\Core\StreamWrapper\LocalStream;
@ -141,10 +142,11 @@ class FileCopy extends FileProcessBase implements ContainerFactoryPluginInterfac
// Check if a writable directory exists, and if not try to create it. // Check if a writable directory exists, and if not try to create it.
$dir = $this->getDirectory($destination); $dir = $this->getDirectory($destination);
// If the directory exists and is writable, avoid file_prepare_directory() // If the directory exists and is writable, avoid
// call and write the file to destination. // \Drupal\Core\File\FileSystemInterface::prepareDirectory() call and write
// the file to destination.
if (!is_dir($dir) || !is_writable($dir)) { if (!is_dir($dir) || !is_writable($dir)) {
if (!file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { if (!$this->fileSystem->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
throw new MigrateException("Could not create or write to directory '$dir'"); throw new MigrateException("Could not create or write to directory '$dir'");
} }
} }
@ -169,15 +171,24 @@ class FileCopy extends FileProcessBase implements ContainerFactoryPluginInterfac
* @return string|bool * @return string|bool
* File destination on success, FALSE on failure. * File destination on success, FALSE on failure.
*/ */
protected function writeFile($source, $destination, $replace = FILE_EXISTS_REPLACE) { protected function writeFile($source, $destination, $replace = FileSystemInterface::EXISTS_REPLACE) {
// Check if there is a destination available for copying. If there isn't, // Check if there is a destination available for copying. If there isn't,
// it already exists at the destination and the replace flag tells us to not // it already exists at the destination and the replace flag tells us to not
// replace it. In that case, return the original destination. // replace it. In that case, return the original destination.
if (!($final_destination = file_destination($destination, $replace))) { if ($this->fileSystem->getDestinationFilename($destination, $replace) === FALSE) {
return $destination; return $destination;
} }
$function = 'file_unmanaged_' . ($this->configuration['move'] ? 'move' : 'copy'); try {
return $function($source, $destination, $replace); if ($this->configuration['move']) {
return $this->fileSystem->move($source, $destination, $replace);
}
else {
return $this->fileSystem->copy($source, $destination, $replace);
}
}
catch (FileException $e) {
return FALSE;
}
} }
/** /**
@ -185,7 +196,8 @@ class FileCopy extends FileProcessBase implements ContainerFactoryPluginInterfac
* *
* For URIs like public://foo.txt, the full physical path of public:// * For URIs like public://foo.txt, the full physical path of public://
* will be returned, since a scheme by itself will trip up certain file * will be returned, since a scheme by itself will trip up certain file
* API functions (such as file_prepare_directory()). * API functions (such as
* \Drupal\Core\File\FileSystemInterface::prepareDirectory()).
* *
* @param string $uri * @param string $uri
* The URI or path. * The URI or path.

View File

@ -2,6 +2,7 @@
namespace Drupal\migrate\Plugin\migrate\process; namespace Drupal\migrate\Plugin\migrate\process;
use Drupal\Core\File\FileSystemInterface;
use Drupal\migrate\ProcessPluginBase; use Drupal\migrate\ProcessPluginBase;
/** /**
@ -31,28 +32,28 @@ abstract class FileProcessBase extends ProcessPluginBase {
if (array_key_exists('file_exists', $configuration)) { if (array_key_exists('file_exists', $configuration)) {
switch ($configuration['file_exists']) { switch ($configuration['file_exists']) {
case 'use existing': case 'use existing':
$configuration['file_exists'] = FILE_EXISTS_ERROR; $configuration['file_exists'] = FileSystemInterface::EXISTS_ERROR;
break; break;
case 'rename': case 'rename':
$configuration['file_exists'] = FILE_EXISTS_RENAME; $configuration['file_exists'] = FileSystemInterface::EXISTS_RENAME;
break; break;
default: default:
$configuration['file_exists'] = FILE_EXISTS_REPLACE; $configuration['file_exists'] = FileSystemInterface::EXISTS_REPLACE;
} }
} }
if (array_key_exists('reuse', $configuration)) { if (array_key_exists('reuse', $configuration)) {
@trigger_error("Using the key 'reuse' is deprecated, use 'file_exists' => 'use existing' instead. See https://www.drupal.org/node/2981389.", E_USER_DEPRECATED); @trigger_error("Using the key 'reuse' is deprecated, use 'file_exists' => 'use existing' instead. See https://www.drupal.org/node/2981389.", E_USER_DEPRECATED);
if (!empty($configuration['reuse'])) { if (!empty($configuration['reuse'])) {
$configuration['file_exists'] = FILE_EXISTS_ERROR; $configuration['file_exists'] = FileSystemInterface::EXISTS_ERROR;
} }
} }
if (array_key_exists('rename', $configuration)) { if (array_key_exists('rename', $configuration)) {
@trigger_error("Using the key 'rename' is deprecated, use 'file_exists' => 'rename' instead. See https://www.drupal.org/node/2981389.", E_USER_DEPRECATED); @trigger_error("Using the key 'rename' is deprecated, use 'file_exists' => 'rename' instead. See https://www.drupal.org/node/2981389.", E_USER_DEPRECATED);
if (!empty($configuration['rename'])) { if (!empty($configuration['rename'])) {
$configuration['file_exists'] = FILE_EXISTS_RENAME; $configuration['file_exists'] = FileSystemInterface::EXISTS_RENAME;
} }
} }
$configuration += ['file_exists' => FILE_EXISTS_REPLACE]; $configuration += ['file_exists' => FileSystemInterface::EXISTS_REPLACE];
parent::__construct($configuration, $plugin_id, $plugin_definition); parent::__construct($configuration, $plugin_id, $plugin_definition);
} }

View File

@ -7,21 +7,6 @@ use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\migrate\Plugin\migrate\process\FileCopy; use Drupal\migrate\Plugin\migrate\process\FileCopy;
use Drupal\migrate\Plugin\MigrateProcessInterface; use Drupal\migrate\Plugin\MigrateProcessInterface;
/**
* Flag for dealing with existing files: Appends number until name is unique.
*/
define('FILE_EXISTS_RENAME', 0);
/**
* Flag for dealing with existing files: Replace the existing file.
*/
define('FILE_EXISTS_REPLACE', 1);
/**
* Flag for dealing with existing files: Do nothing and return FALSE.
*/
define('FILE_EXISTS_ERROR', 2);
/** /**
* Tests the file copy process plugin. * Tests the file copy process plugin.
* *
@ -53,8 +38,8 @@ class FileCopyTest extends MigrateProcessTestCase {
*/ */
public function providerDeprecationNoticeRename() { public function providerDeprecationNoticeRename() {
return [ return [
[['rename' => TRUE], FILE_EXISTS_RENAME], [['rename' => TRUE], FileSystemInterface::EXISTS_RENAME],
[['rename' => FALSE], FILE_EXISTS_REPLACE], [['rename' => FALSE], FileSystemInterface::EXISTS_REPLACE],
]; ];
} }
@ -79,8 +64,8 @@ class FileCopyTest extends MigrateProcessTestCase {
*/ */
public function providerDeprecationNoticeReuse() { public function providerDeprecationNoticeReuse() {
return [ return [
[['reuse' => TRUE], FILE_EXISTS_ERROR], [['reuse' => TRUE], FileSystemInterface::EXISTS_ERROR],
[['reuse' => FALSE], FILE_EXISTS_REPLACE], [['reuse' => FALSE], FileSystemInterface::EXISTS_REPLACE],
]; ];
} }
@ -103,11 +88,11 @@ class FileCopyTest extends MigrateProcessTestCase {
*/ */
public function providerFileProcessBaseConstructor() { public function providerFileProcessBaseConstructor() {
return [ return [
[['file_exists' => 'replace'], FILE_EXISTS_REPLACE], [['file_exists' => 'replace'], FileSystemInterface::EXISTS_REPLACE],
[['file_exists' => 'rename'], FILE_EXISTS_RENAME], [['file_exists' => 'rename'], FileSystemInterface::EXISTS_RENAME],
[['file_exists' => 'use existing'], FILE_EXISTS_ERROR], [['file_exists' => 'use existing'], FileSystemInterface::EXISTS_ERROR],
[['file_exists' => 'foobar'], FILE_EXISTS_REPLACE], [['file_exists' => 'foobar'], FileSystemInterface::EXISTS_REPLACE],
[[], FILE_EXISTS_REPLACE], [[], FileSystemInterface::EXISTS_REPLACE],
]; ];
} }

View File

@ -61,7 +61,7 @@ class NodeImportCreateTest extends KernelTestBase {
// Manually add new node type. // Manually add new node type.
$src_dir = __DIR__ . '/../../../modules/node_test_config/sync'; $src_dir = __DIR__ . '/../../../modules/node_test_config/sync';
$target_dir = config_get_config_directory(CONFIG_SYNC_DIRECTORY); $target_dir = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
$this->assertTrue(file_unmanaged_copy("$src_dir/$node_type_config_name.yml", "$target_dir/$node_type_config_name.yml")); $this->assertTrue(\Drupal::service('file_system')->copy("$src_dir/$node_type_config_name.yml", "$target_dir/$node_type_config_name.yml"));
// Import the content of the sync directory. // Import the content of the sync directory.
$this->configImporter()->import(); $this->configImporter()->import();

View File

@ -136,7 +136,7 @@ class StandardProfileTest extends BrowserTestBase {
$this->term->save(); $this->term->save();
// Create image. // Create image.
file_unmanaged_copy($this->root . '/core/misc/druplicon.png', 'public://example.jpg'); \Drupal::service('file_system')->copy($this->root . '/core/misc/druplicon.png', 'public://example.jpg');
$this->image = File::create(['uri' => 'public://example.jpg']); $this->image = File::create(['uri' => 'public://example.jpg']);
$this->image->save(); $this->image->save();

View File

@ -6,6 +6,7 @@
*/ */
use Drupal\Component\Utility\Environment; use Drupal\Component\Utility\Environment;
use Drupal\Core\File\Exception\FileException;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
/** /**
@ -189,5 +190,11 @@ function simpletest_uninstall() {
simpletest_clean_environment(); simpletest_clean_environment();
} }
// Delete verbose test output and any other testing framework files. // Delete verbose test output and any other testing framework files.
file_unmanaged_delete_recursive('public://simpletest'); try {
\Drupal::service('file_system')->deleteRecursive('public://simpletest');
}
catch (FileException $e) {
// Ignore.
}
} }

View File

@ -7,6 +7,7 @@
use Drupal\Core\Asset\AttachedAssetsInterface; use Drupal\Core\Asset\AttachedAssetsInterface;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\Render\Element; use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\simpletest\TestBase; use Drupal\simpletest\TestBase;
@ -143,7 +144,12 @@ function simpletest_run_tests($test_list) {
->execute(); ->execute();
// Clear out the previous verbose files. // Clear out the previous verbose files.
file_unmanaged_delete_recursive('public://simpletest/verbose'); try {
\Drupal::service('file_system')->deleteRecursive('public://simpletest/verbose');
}
catch (FileException $e) {
// Ignore failed deletes.
}
// Get the info for the first test being run. // Get the info for the first test being run.
$first_test = reset($test_list); $first_test = reset($test_list);
@ -699,9 +705,14 @@ function simpletest_clean_temporary_directories() {
foreach ($files as $file) { foreach ($files as $file) {
if ($file[0] != '.') { if ($file[0] != '.') {
$path = DRUPAL_ROOT . '/sites/simpletest/' . $file; $path = DRUPAL_ROOT . '/sites/simpletest/' . $file;
file_unmanaged_delete_recursive($path, function ($any_path) { try {
@chmod($any_path, 0700); \Drupal::service('file_system')->deleteRecursive($path, function ($any_path) {
}); @chmod($any_path, 0700);
});
}
catch (FileException $e) {
// Ignore failed deletes.
}
$count++; $count++;
} }
} }

View File

@ -13,6 +13,7 @@ use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DrupalKernel; use Drupal\Core\DrupalKernel;
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface; use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
use Drupal\Core\Extension\ExtensionDiscovery; use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\KeyValueStore\KeyValueMemoryFactory; use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
use Drupal\Core\Language\Language; use Drupal\Core\Language\Language;
use Drupal\Core\Site\Settings; use Drupal\Core\Site\Settings;
@ -149,7 +150,7 @@ abstract class KernelTestBase extends TestBase {
$path = $this->siteDirectory . '/config_' . CONFIG_SYNC_DIRECTORY; $path = $this->siteDirectory . '/config_' . CONFIG_SYNC_DIRECTORY;
$GLOBALS['config_directories'][CONFIG_SYNC_DIRECTORY] = $path; $GLOBALS['config_directories'][CONFIG_SYNC_DIRECTORY] = $path;
// Ensure the directory can be created and is writeable. // Ensure the directory can be created and is writeable.
if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { if (!\Drupal::service('file_system')->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
throw new \RuntimeException("Failed to create '" . CONFIG_SYNC_DIRECTORY . "' config directory $path"); throw new \RuntimeException("Failed to create '" . CONFIG_SYNC_DIRECTORY . "' config directory $path");
} }
// Provide the already resolved path for tests. // Provide the already resolved path for tests.
@ -285,9 +286,7 @@ EOD;
// Tests based on this class are entitled to use Drupal's File and // Tests based on this class are entitled to use Drupal's File and
// StreamWrapper APIs. // StreamWrapper APIs.
// @todo Move StreamWrapper management into DrupalKernel. \Drupal::service('file_system')->prepareDirectory($this->publicFilesDirectory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
// @see https://www.drupal.org/node/2028109
file_prepare_directory($this->publicFilesDirectory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
$this->settingsSet('file_public_path', $this->publicFilesDirectory); $this->settingsSet('file_public_path', $this->publicFilesDirectory);
$this->streamWrappers = []; $this->streamWrappers = [];
$this->registerStreamWrapper('public', 'Drupal\Core\StreamWrapper\PublicStream'); $this->registerStreamWrapper('public', 'Drupal\Core\StreamWrapper\PublicStream');

View File

@ -7,6 +7,7 @@ use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\Crypt;
use Drupal\Component\Render\FormattableMarkup; use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Site\Settings; use Drupal\Core\Site\Settings;
use Drupal\Core\StreamWrapper\PublicStream; use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\Test\TestDatabase; use Drupal\Core\Test\TestDatabase;
@ -903,7 +904,7 @@ abstract class TestBase {
$this->verbose = TRUE; $this->verbose = TRUE;
$this->verboseDirectory = PublicStream::basePath() . '/simpletest/verbose'; $this->verboseDirectory = PublicStream::basePath() . '/simpletest/verbose';
$this->verboseDirectoryUrl = file_create_url($this->verboseDirectory); $this->verboseDirectoryUrl = file_create_url($this->verboseDirectory);
if (file_prepare_directory($this->verboseDirectory, FILE_CREATE_DIRECTORY) && !file_exists($this->verboseDirectory . '/.htaccess')) { if (\Drupal::service('file_system')->prepareDirectory($this->verboseDirectory, FileSystemInterface::CREATE_DIRECTORY) && !file_exists($this->verboseDirectory . '/.htaccess')) {
file_put_contents($this->verboseDirectory . '/.htaccess', "<IfModule mod_expires.c>\nExpiresActive Off\n</IfModule>\n"); file_put_contents($this->verboseDirectory . '/.htaccess', "<IfModule mod_expires.c>\nExpiresActive Off\n</IfModule>\n");
} }
$this->verboseClassName = str_replace("\\", "_", $class); $this->verboseClassName = str_replace("\\", "_", $class);
@ -1125,7 +1126,7 @@ abstract class TestBase {
// Create test directory ahead of installation so fatal errors and debug // Create test directory ahead of installation so fatal errors and debug
// information can be logged during installation process. // information can be logged during installation process.
file_prepare_directory($this->siteDirectory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); \Drupal::service('file_system')->prepareDirectory($this->siteDirectory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
// Prepare filesystem directory paths. // Prepare filesystem directory paths.
$this->publicFilesDirectory = $this->siteDirectory . '/files'; $this->publicFilesDirectory = $this->siteDirectory . '/files';
@ -1250,7 +1251,7 @@ abstract class TestBase {
\Drupal::setContainer($this->originalContainer); \Drupal::setContainer($this->originalContainer);
// Delete test site directory. // Delete test site directory.
file_unmanaged_delete_recursive($this->siteDirectory, [$this, 'filePreDeleteCallback']); \Drupal::service('file_system')->deleteRecursive($this->siteDirectory, [$this, 'filePreDeleteCallback']);
// Restore original database connection. // Restore original database connection.
Database::removeConnection('default'); Database::removeConnection('default');
@ -1362,11 +1363,13 @@ abstract class TestBase {
} }
/** /**
* Ensures test files are deletable within file_unmanaged_delete_recursive(). * Ensures test files are deletable.
* *
* Some tests chmod generated files to be read only. During * Some tests chmod generated files to be read only. During
* TestBase::restoreEnvironment() and other cleanup operations, these files * TestBase::restoreEnvironment() and other cleanup operations, these files
* need to get deleted too. * need to get deleted too.
*
* @see \Drupal\Core\File\FileSystemInterface::deleteRecursive()
*/ */
public static function filePreDeleteCallback($path) { public static function filePreDeleteCallback($path) {
// When the webserver runs with the same system user as the test runner, we // When the webserver runs with the same system user as the test runner, we

View File

@ -3,6 +3,8 @@
namespace Drupal\system\Form; namespace Drupal\system\Form;
use Drupal\Core\Extension\ThemeHandlerInterface; use Drupal\Core\Extension\ThemeHandlerInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element; use Drupal\Core\Render\Element;
use Drupal\Core\StreamWrapper\PublicStream; use Drupal\Core\StreamWrapper\PublicStream;
@ -56,6 +58,13 @@ class ThemeSettingsForm extends ConfigFormBase {
*/ */
protected $themeManager; protected $themeManager;
/**
* The file system.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/** /**
* Constructs a ThemeSettingsForm object. * Constructs a ThemeSettingsForm object.
* *
@ -67,14 +76,23 @@ class ThemeSettingsForm extends ConfigFormBase {
* The theme handler. * The theme handler.
* @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mime_type_guesser * @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mime_type_guesser
* The MIME type guesser instance to use. * The MIME type guesser instance to use.
* @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
* The theme manager.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system.
*/ */
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, MimeTypeGuesserInterface $mime_type_guesser, ThemeManagerInterface $theme_manager) { public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, MimeTypeGuesserInterface $mime_type_guesser, ThemeManagerInterface $theme_manager, FileSystemInterface $file_system = NULL) {
parent::__construct($config_factory); parent::__construct($config_factory);
$this->moduleHandler = $module_handler; $this->moduleHandler = $module_handler;
$this->themeHandler = $theme_handler; $this->themeHandler = $theme_handler;
$this->mimeTypeGuesser = $mime_type_guesser; $this->mimeTypeGuesser = $mime_type_guesser;
$this->themeManager = $theme_manager; $this->themeManager = $theme_manager;
if (!$file_system) {
@trigger_error('The file_system service must be passed to ThemeSettingsForm::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
$file_system = \Drupal::service('file_system');
}
$this->fileSystem = $file_system;
} }
/** /**
@ -86,7 +104,8 @@ class ThemeSettingsForm extends ConfigFormBase {
$container->get('module_handler'), $container->get('module_handler'),
$container->get('theme_handler'), $container->get('theme_handler'),
$container->get('file.mime_type.guesser'), $container->get('file.mime_type.guesser'),
$container->get('theme.manager') $container->get('theme.manager'),
$container->get('file_system')
); );
} }
@ -442,16 +461,26 @@ class ThemeSettingsForm extends ConfigFormBase {
// If the user uploaded a new logo or favicon, save it to a permanent location // If the user uploaded a new logo or favicon, save it to a permanent location
// and use it in place of the default theme-provided file. // and use it in place of the default theme-provided file.
if (!empty($values['logo_upload'])) { try {
$filename = file_unmanaged_copy($values['logo_upload']->getFileUri()); if (!empty($values['logo_upload'])) {
$values['default_logo'] = 0; $filename = $this->fileSystem->copy($values['logo_upload']->getFileUri());
$values['logo_path'] = $filename; $values['default_logo'] = 0;
$values['logo_path'] = $filename;
}
} }
if (!empty($values['favicon_upload'])) { catch (FileException $e) {
$filename = file_unmanaged_copy($values['favicon_upload']->getFileUri()); // Ignore.
$values['default_favicon'] = 0; }
$values['favicon_path'] = $filename; try {
$values['toggle_favicon'] = 1; if (!empty($values['favicon_upload'])) {
$filename = $this->fileSystem->copy($values['favicon_upload']->getFileUri());
$values['default_favicon'] = 0;
$values['favicon_path'] = $filename;
$values['toggle_favicon'] = 1;
}
}
catch (FileException $e) {
// Ignore.
} }
unset($values['logo_upload']); unset($values['logo_upload']);
unset($values['favicon_upload']); unset($values['favicon_upload']);
@ -488,7 +517,7 @@ class ThemeSettingsForm extends ConfigFormBase {
*/ */
protected function validatePath($path) { protected function validatePath($path) {
// Absolute local file paths are invalid. // Absolute local file paths are invalid.
if (\Drupal::service('file_system')->realpath($path) == $path) { if ($this->fileSystem->realpath($path) == $path) {
return FALSE; return FALSE;
} }
// A path relative to the Drupal root or a fully qualified URI is valid. // A path relative to the Drupal root or a fully qualified URI is valid.

View File

@ -4,6 +4,8 @@ namespace Drupal\system\Plugin\ImageToolkit;
use Drupal\Component\Utility\Color; use Drupal\Component\Utility\Color;
use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\ImageToolkit\ImageToolkitBase; use Drupal\Core\ImageToolkit\ImageToolkitBase;
use Drupal\Core\ImageToolkit\ImageToolkitOperationManagerInterface; use Drupal\Core\ImageToolkit\ImageToolkitOperationManagerInterface;
@ -58,6 +60,13 @@ class GDToolkit extends ImageToolkitBase {
*/ */
protected $streamWrapperManager; protected $streamWrapperManager;
/**
* The file system.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/** /**
* Constructs a GDToolkit object. * Constructs a GDToolkit object.
* *
@ -75,10 +84,17 @@ class GDToolkit extends ImageToolkitBase {
* The config factory. * The config factory.
* @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager
* The StreamWrapper manager. * The StreamWrapper manager.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system.
*/ */
public function __construct(array $configuration, $plugin_id, array $plugin_definition, ImageToolkitOperationManagerInterface $operation_manager, LoggerInterface $logger, ConfigFactoryInterface $config_factory, StreamWrapperManagerInterface $stream_wrapper_manager) { public function __construct(array $configuration, $plugin_id, array $plugin_definition, ImageToolkitOperationManagerInterface $operation_manager, LoggerInterface $logger, ConfigFactoryInterface $config_factory, StreamWrapperManagerInterface $stream_wrapper_manager, FileSystemInterface $file_system = NULL) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $operation_manager, $logger, $config_factory); parent::__construct($configuration, $plugin_id, $plugin_definition, $operation_manager, $logger, $config_factory);
$this->streamWrapperManager = $stream_wrapper_manager; $this->streamWrapperManager = $stream_wrapper_manager;
if (!$file_system) {
@trigger_error('The file_system service must be passed to GDToolkit::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
$file_system = \Drupal::service('file_system');
}
$this->fileSystem = $file_system;
} }
/** /**
@ -103,7 +119,8 @@ class GDToolkit extends ImageToolkitBase {
$container->get('image.toolkit.operation.manager'), $container->get('image.toolkit.operation.manager'),
$container->get('logger.channel.image'), $container->get('logger.channel.image'),
$container->get('config.factory'), $container->get('config.factory'),
$container->get('stream_wrapper_manager') $container->get('stream_wrapper_manager'),
$container->get('file_system')
); );
} }
@ -223,7 +240,7 @@ class GDToolkit extends ImageToolkitBase {
$destination = drupal_tempnam('temporary://', 'gd_'); $destination = drupal_tempnam('temporary://', 'gd_');
} }
// Convert stream wrapper URI to normal path. // Convert stream wrapper URI to normal path.
$destination = \Drupal::service('file_system')->realpath($destination); $destination = $this->fileSystem->realpath($destination);
} }
$function = 'image' . image_type_to_extension($this->getType(), FALSE); $function = 'image' . image_type_to_extension($this->getType(), FALSE);
@ -243,7 +260,13 @@ class GDToolkit extends ImageToolkitBase {
} }
// Move temporary local file to remote destination. // Move temporary local file to remote destination.
if (isset($permanent_destination) && $success) { if (isset($permanent_destination) && $success) {
return (bool) file_unmanaged_move($destination, $permanent_destination, FILE_EXISTS_REPLACE); try {
$this->fileSystem->move($destination, $permanent_destination, FileSystemInterface::EXISTS_REPLACE);
return TRUE;
}
catch (FileException $e) {
return FALSE;
}
} }
return $success; return $success;
} }

View File

@ -11,6 +11,7 @@ use Drupal\Component\FileSystem\FileSystem;
use Drupal\Component\Utility\OpCodeCache; use Drupal\Component\Utility\OpCodeCache;
use Drupal\Component\Utility\Unicode; use Drupal\Component\Utility\Unicode;
use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\Cache;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Path\AliasStorage; use Drupal\Core\Path\AliasStorage;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
@ -628,7 +629,7 @@ function system_requirements($phase) {
$directory = config_get_config_directory($type); $directory = config_get_config_directory($type);
// If we're installing Drupal try and create the config sync directory. // If we're installing Drupal try and create the config sync directory.
if (!is_dir($directory) && $phase == 'install') { if (!is_dir($directory) && $phase == 'install') {
file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
} }
if (!is_dir($directory)) { if (!is_dir($directory)) {
if ($phase == 'install') { if ($phase == 'install') {
@ -665,7 +666,7 @@ function system_requirements($phase) {
continue; continue;
} }
if ($phase == 'install') { if ($phase == 'install') {
file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
} }
$is_writable = is_writable($directory); $is_writable = is_writable($directory);
$is_directory = is_dir($directory); $is_directory = is_dir($directory);

View File

@ -11,6 +11,8 @@ use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Asset\AttachedAssetsInterface; use Drupal\Core\Asset\AttachedAssetsInterface;
use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\Cache;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Queue\QueueGarbageCollectionInterface; use Drupal\Core\Queue\QueueGarbageCollectionInterface;
use Drupal\Core\Database\Query\AlterableInterface; use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Extension\Extension; use Drupal\Core\Extension\Extension;
@ -1330,13 +1332,15 @@ function system_time_zones($blank = NULL, $grouped = FALSE) {
* object which describes the file. * object which describes the file.
* - If it fails, FALSE. * - If it fails, FALSE.
*/ */
function system_retrieve_file($url, $destination = NULL, $managed = FALSE, $replace = FILE_EXISTS_RENAME) { function system_retrieve_file($url, $destination = NULL, $managed = FALSE, $replace = FileSystemInterface::EXISTS_RENAME) {
$parsed_url = parse_url($url); $parsed_url = parse_url($url);
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
if (!isset($destination)) { if (!isset($destination)) {
$path = file_build_uri(drupal_basename($parsed_url['path'])); $path = file_build_uri(drupal_basename($parsed_url['path']));
} }
else { else {
if (is_dir(\Drupal::service('file_system')->realpath($destination))) { if (is_dir($file_system->realpath($destination))) {
// Prevent URIs with triple slashes when glueing parts together. // Prevent URIs with triple slashes when glueing parts together.
$path = str_replace('///', '//', "$destination/") . drupal_basename($parsed_url['path']); $path = str_replace('///', '//', "$destination/") . drupal_basename($parsed_url['path']);
} }
@ -1348,12 +1352,16 @@ function system_retrieve_file($url, $destination = NULL, $managed = FALSE, $repl
$data = (string) \Drupal::httpClient() $data = (string) \Drupal::httpClient()
->get($url) ->get($url)
->getBody(); ->getBody();
$local = $managed ? file_save_data($data, $path, $replace) : file_unmanaged_save_data($data, $path, $replace); $local = $managed ? file_save_data($data, $path, $replace) : $file_system->saveData($data, $path, $replace);
} }
catch (RequestException $exception) { catch (RequestException $exception) {
\Drupal::messenger()->addError(t('Failed to fetch file due to error "%error"', ['%error' => $exception->getMessage()])); \Drupal::messenger()->addError(t('Failed to fetch file due to error "%error"', ['%error' => $exception->getMessage()]));
return FALSE; return FALSE;
} }
catch (FileException $e) {
\Drupal::messenger()->addError(t('Failed to save file due to error "%error"', ['%error' => $e->getMessage()]));
return FALSE;
}
if (!$local) { if (!$local) {
\Drupal::messenger()->addError(t('@remote could not be saved to @path.', ['@remote' => $url, '@path' => $path])); \Drupal::messenger()->addError(t('@remote could not be saved to @path.', ['@remote' => $url, '@path' => $path]));
} }

View File

@ -33,7 +33,9 @@ class RetrieveFileTest extends BrowserTestBase {
$this->assertEqual($retrieved_file, 'public://' . $encoded_filename, 'Sane path for downloaded file returned (public:// scheme).'); $this->assertEqual($retrieved_file, 'public://' . $encoded_filename, 'Sane path for downloaded file returned (public:// scheme).');
$this->assertTrue(is_file($retrieved_file), 'Downloaded file does exist (public:// scheme).'); $this->assertTrue(is_file($retrieved_file), 'Downloaded file does exist (public:// scheme).');
$this->assertEqual(filesize($retrieved_file), 7, 'File size of downloaded file is correct (public:// scheme).'); $this->assertEqual(filesize($retrieved_file), 7, 'File size of downloaded file is correct (public:// scheme).');
file_unmanaged_delete($retrieved_file); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$file_system->delete($retrieved_file);
// Test downloading file to a different location. // Test downloading file to a different location.
drupal_mkdir($targetdir = 'temporary://' . $this->randomMachineName()); drupal_mkdir($targetdir = 'temporary://' . $this->randomMachineName());
@ -41,10 +43,10 @@ class RetrieveFileTest extends BrowserTestBase {
$this->assertEqual($retrieved_file, "$targetdir/$encoded_filename", 'Sane path for downloaded file returned (temporary:// scheme).'); $this->assertEqual($retrieved_file, "$targetdir/$encoded_filename", 'Sane path for downloaded file returned (temporary:// scheme).');
$this->assertTrue(is_file($retrieved_file), 'Downloaded file does exist (temporary:// scheme).'); $this->assertTrue(is_file($retrieved_file), 'Downloaded file does exist (temporary:// scheme).');
$this->assertEqual(filesize($retrieved_file), 7, 'File size of downloaded file is correct (temporary:// scheme).'); $this->assertEqual(filesize($retrieved_file), 7, 'File size of downloaded file is correct (temporary:// scheme).');
file_unmanaged_delete($retrieved_file); $file_system->delete($retrieved_file);
file_unmanaged_delete_recursive($sourcedir); $file_system->deleteRecursive($sourcedir);
file_unmanaged_delete_recursive($targetdir); $file_system->deleteRecursive($targetdir);
} }
} }

View File

@ -27,7 +27,7 @@ class UpdateDeleteFileIfStaleTest extends UpdateTestBase {
* Tests the deletion of stale files. * Tests the deletion of stale files.
*/ */
public function testUpdateDeleteFileIfStale() { public function testUpdateDeleteFileIfStale() {
$file_name = file_unmanaged_save_data($this->randomMachineName()); $file_name = \Drupal::service('file_system')->saveData($this->randomMachineName());
$this->assertNotNull($file_name); $this->assertNotNull($file_name);
// During testing the file change and the stale checking occurs in the same // During testing the file change and the stale checking occurs in the same

View File

@ -36,6 +36,7 @@
* root. * root.
*/ */
use Drupal\Core\File\Exception\FileException;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
/** /**
@ -165,7 +166,12 @@ function update_manager_archive_extract($file, $directory) {
$extract_location = $directory . '/' . $project; $extract_location = $directory . '/' . $project;
if (file_exists($extract_location)) { if (file_exists($extract_location)) {
file_unmanaged_delete_recursive($extract_location); try {
\Drupal::service('file_system')->deleteRecursive($extract_location);
}
catch (FileException $e) {
// Ignore failed deletes.
}
} }
$archiver->extract($directory); $archiver->extract($directory);

View File

@ -11,6 +11,7 @@
* ability to install contributed modules and themes via an user interface. * ability to install contributed modules and themes via an user interface.
*/ */
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteMatchInterface;
@ -826,7 +827,12 @@ function update_delete_file_if_stale($path) {
$max_age = \Drupal::config('system.file')->get('temporary_maximum_age'); $max_age = \Drupal::config('system.file')->get('temporary_maximum_age');
if (REQUEST_TIME - $filectime > $max_age || (preg_match('/.*-dev\.(tar\.gz|zip)/i', $path) && REQUEST_TIME - $filectime > 300)) { if (REQUEST_TIME - $filectime > $max_age || (preg_match('/.*-dev\.(tar\.gz|zip)/i', $path) && REQUEST_TIME - $filectime > 300)) {
file_unmanaged_delete_recursive($path); try {
\Drupal::service('file_system')->deleteRecursive($path);
}
catch (FileException $e) {
// Ignore failed deletes.
}
} }
} }
} }

View File

@ -2,13 +2,15 @@
namespace Drupal\demo_umami_content; namespace Drupal\demo_umami_content;
use Drupal\Component\Utility\Html;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Path\AliasManagerInterface; use Drupal\Core\Path\AliasManagerInterface;
use Drupal\Core\State\StateInterface; use Drupal\Core\State\StateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Component\Utility\Html;
/** /**
* Defines a helper class for importing default content. * Defines a helper class for importing default content.
@ -46,6 +48,13 @@ class InstallHelper implements ContainerInjectionInterface {
*/ */
protected $state; protected $state;
/**
* The file system.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/** /**
* Constructs a new InstallHelper object. * Constructs a new InstallHelper object.
* *
@ -57,12 +66,15 @@ class InstallHelper implements ContainerInjectionInterface {
* Module handler. * Module handler.
* @param \Drupal\Core\State\StateInterface $state * @param \Drupal\Core\State\StateInterface $state
* State service. * State service.
* @param \Drupal\Core\File\FileSystemInterface $fileSystem
* The file system.
*/ */
public function __construct(AliasManagerInterface $aliasManager, EntityTypeManagerInterface $entityTypeManager, ModuleHandlerInterface $moduleHandler, StateInterface $state) { public function __construct(AliasManagerInterface $aliasManager, EntityTypeManagerInterface $entityTypeManager, ModuleHandlerInterface $moduleHandler, StateInterface $state, FileSystemInterface $fileSystem) {
$this->aliasManager = $aliasManager; $this->aliasManager = $aliasManager;
$this->entityTypeManager = $entityTypeManager; $this->entityTypeManager = $entityTypeManager;
$this->moduleHandler = $moduleHandler; $this->moduleHandler = $moduleHandler;
$this->state = $state; $this->state = $state;
$this->fileSystem = $fileSystem;
} }
/** /**
@ -73,7 +85,8 @@ class InstallHelper implements ContainerInjectionInterface {
$container->get('path.alias_manager'), $container->get('path.alias_manager'),
$container->get('entity_type.manager'), $container->get('entity_type.manager'),
$container->get('module_handler'), $container->get('module_handler'),
$container->get('state') $container->get('state'),
$container->get('file_system')
); );
} }
@ -513,7 +526,13 @@ class InstallHelper implements ContainerInjectionInterface {
* File ID. * File ID.
*/ */
protected function createFileEntity($path) { protected function createFileEntity($path) {
$uri = $this->fileUnmanagedCopy($path); $filename = basename($path);
try {
$uri = $this->fileSystem->copy($path, 'public://' . $filename, FileSystemInterface::EXISTS_REPLACE);
}
catch (FileException $e) {
$uri = FALSE;
}
$file = $this->entityTypeManager->getStorage('file')->create([ $file = $this->entityTypeManager->getStorage('file')->create([
'uri' => $uri, 'uri' => $uri,
'status' => 1, 'status' => 1,
@ -535,18 +554,4 @@ class InstallHelper implements ContainerInjectionInterface {
$this->state->set('demo_umami_content_uuids', $uuids); $this->state->set('demo_umami_content_uuids', $uuids);
} }
/**
* Wrapper around file_unmanaged_copy().
*
* @param string $path
* Path to image.
*
* @return string|false
* The path to the new file, or FALSE in the event of an error.
*/
protected function fileUnmanagedCopy($path) {
$filename = basename($path);
return file_unmanaged_copy($path, 'public://' . $filename, FILE_EXISTS_REPLACE);
}
} }

View File

@ -12,6 +12,7 @@ use Drupal\Component\Uuid\Php;
use Drupal\Core\Composer\Composer; use Drupal\Core\Composer\Composer;
use Drupal\Core\Asset\AttachedAssets; use Drupal\Core\Asset\AttachedAssets;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\StreamWrapper\PublicStream; use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\Test\TestDatabase; use Drupal\Core\Test\TestDatabase;
use Drupal\Core\Test\TestRunnerKernel; use Drupal\Core\Test\TestRunnerKernel;
@ -962,8 +963,13 @@ function simpletest_script_cleanup($test_id, $test_class, $exitcode) {
// simpletest_clean_temporary_directories() cannot be used here, since it // simpletest_clean_temporary_directories() cannot be used here, since it
// would also delete file directories of other tests that are potentially // would also delete file directories of other tests that are potentially
// running concurrently. // running concurrently.
file_unmanaged_delete_recursive($test_directory, ['Drupal\simpletest\TestBase', 'filePreDeleteCallback']); try {
$messages[] = "- Removed test site directory."; \Drupal::service('file_system')->deleteRecursive($test_directory, ['Drupal\simpletest\TestBase', 'filePreDeleteCallback']);
$messages[] = "- Removed test site directory.";
}
catch (FileException $e) {
// Ignore failed deletes.
}
} }
// Clear out all database tables from the test. // Clear out all database tables from the test.
@ -1565,7 +1571,7 @@ function simpletest_script_open_browser() {
// Ensure we have assets verbose directory - tests with no verbose output will // Ensure we have assets verbose directory - tests with no verbose output will
// not have created one. // not have created one.
$directory = PublicStream::basePath() . '/simpletest/verbose'; $directory = PublicStream::basePath() . '/simpletest/verbose';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
$php = new Php(); $php = new Php();
$uuid = $php->generate(); $uuid = $php->generate();
$filename = $directory . '/results-' . $uuid . '.html'; $filename = $directory . '/results-' . $uuid . '.html';

View File

@ -22,7 +22,7 @@ class FolderTest extends BrowserTestBase {
public function testFolderSetup() { public function testFolderSetup() {
$directory = file_default_scheme() . '://styles'; $directory = file_default_scheme() . '://styles';
$this->assertTrue(file_prepare_directory($directory, FALSE), 'Directory created.'); $this->assertTrue(\Drupal::service('file_system')->prepareDirectory($directory, FALSE), 'Directory created.');
} }
} }

View File

@ -3,6 +3,7 @@
namespace Drupal\KernelTests\Core\File; namespace Drupal\KernelTests\Core\File;
use Drupal\Component\PhpStorage\FileStorage; use Drupal\Component\PhpStorage\FileStorage;
use Drupal\Core\File\FileSystemInterface;
/** /**
* Tests operations dealing with directories. * Tests operations dealing with directories.
@ -59,10 +60,12 @@ class DirectoryTest extends FileTestBase {
$this->assertFalse(is_dir($directory), 'Directory does not exist prior to testing.'); $this->assertFalse(is_dir($directory), 'Directory does not exist prior to testing.');
// Non-existent directory. // Non-existent directory.
$this->assertFalse(file_prepare_directory($directory, 0), 'Error reported for non-existing directory.', 'File'); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$this->assertFalse($file_system->prepareDirectory($directory, 0), 'Error reported for non-existing directory.', 'File');
// Make a directory. // Make a directory.
$this->assertTrue(file_prepare_directory($directory, FILE_CREATE_DIRECTORY), 'No error reported when creating a new directory.', 'File'); $this->assertTrue($file_system->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY), 'No error reported when creating a new directory.', 'File');
// Make sure directory actually exists. // Make sure directory actually exists.
$this->assertTrue(is_dir($directory), 'Directory actually exists.', 'File'); $this->assertTrue(is_dir($directory), 'Directory actually exists.', 'File');
@ -75,11 +78,11 @@ class DirectoryTest extends FileTestBase {
// Make directory read only. // Make directory read only.
@drupal_chmod($directory, 0444); @drupal_chmod($directory, 0444);
$this->assertFalse(file_prepare_directory($directory, 0), 'Error reported for a non-writeable directory.', 'File'); $this->assertFalse($file_system->prepareDirectory($directory, 0), 'Error reported for a non-writeable directory.', 'File');
// Test directory permission modification. // Test directory permission modification.
$this->setSetting('file_chmod_directory', 0777); $this->setSetting('file_chmod_directory', 0777);
$this->assertTrue(file_prepare_directory($directory, FILE_MODIFY_PERMISSIONS), 'No error reported when making directory writeable.', 'File'); $this->assertTrue($file_system->prepareDirectory($directory, FileSystemInterface::MODIFY_PERMISSIONS), 'No error reported when making directory writeable.', 'File');
} }
// Test that the directory has the correct permissions. // Test that the directory has the correct permissions.
@ -105,14 +108,16 @@ class DirectoryTest extends FileTestBase {
$basename = 'xyz.txt'; $basename = 'xyz.txt';
$directory = 'core/misc'; $directory = 'core/misc';
$original = $directory . '/' . $basename; $original = $directory . '/' . $basename;
$path = file_create_filename($basename, $directory); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$path = $file_system->createFilename($basename, $directory);
$this->assertEqual($path, $original, format_string('New filepath %new equals %original.', ['%new' => $path, '%original' => $original]), 'File'); $this->assertEqual($path, $original, format_string('New filepath %new equals %original.', ['%new' => $path, '%original' => $original]), 'File');
// Then we test against a file that already exists within that directory. // Then we test against a file that already exists within that directory.
$basename = 'druplicon.png'; $basename = 'druplicon.png';
$original = $directory . '/' . $basename; $original = $directory . '/' . $basename;
$expected = $directory . '/druplicon_0.png'; $expected = $directory . '/druplicon_0.png';
$path = file_create_filename($basename, $directory); $path = $file_system->createFilename($basename, $directory);
$this->assertEqual($path, $expected, format_string('Creating a new filepath from %original equals %new (expected %expected).', ['%new' => $path, '%original' => $original, '%expected' => $expected]), 'File'); $this->assertEqual($path, $expected, format_string('Creating a new filepath from %original equals %new (expected %expected).', ['%new' => $path, '%original' => $original, '%expected' => $expected]), 'File');
// @TODO: Finally we copy a file into a directory several times, to ensure a properly iterating filename suffix. // @TODO: Finally we copy a file into a directory several times, to ensure a properly iterating filename suffix.
@ -122,8 +127,8 @@ class DirectoryTest extends FileTestBase {
* This will test the filepath for a destination based on passed flags and * This will test the filepath for a destination based on passed flags and
* whether or not the file exists. * whether or not the file exists.
* *
* If a file exists, file_destination($destination, $replace) will either * If a file exists, ::getDestinationFilename($destination, $replace) will
* return: * either return:
* - the existing filepath, if $replace is FILE_EXISTS_REPLACE * - the existing filepath, if $replace is FILE_EXISTS_REPLACE
* - a new filepath if FILE_EXISTS_RENAME * - a new filepath if FILE_EXISTS_RENAME
* - an error (returning FALSE) if FILE_EXISTS_ERROR. * - an error (returning FALSE) if FILE_EXISTS_ERROR.
@ -133,20 +138,22 @@ class DirectoryTest extends FileTestBase {
public function testFileDestination() { public function testFileDestination() {
// First test for non-existent file. // First test for non-existent file.
$destination = 'core/misc/xyz.txt'; $destination = 'core/misc/xyz.txt';
$path = file_destination($destination, FILE_EXISTS_REPLACE); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FILE_EXISTS_REPLACE.', 'File'); $file_system = \Drupal::service('file_system');
$path = file_destination($destination, FILE_EXISTS_RENAME); $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_REPLACE);
$this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FILE_EXISTS_RENAME.', 'File'); $this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FileSystemInterface::EXISTS_REPLACE.', 'File');
$path = file_destination($destination, FILE_EXISTS_ERROR); $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_RENAME);
$this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FILE_EXISTS_ERROR.', 'File'); $this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FileSystemInterface::EXISTS_RENAME.', 'File');
$path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_ERROR);
$this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FileSystemInterface::EXISTS_ERROR.', 'File');
$destination = 'core/misc/druplicon.png'; $destination = 'core/misc/druplicon.png';
$path = file_destination($destination, FILE_EXISTS_REPLACE); $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_REPLACE);
$this->assertEqual($path, $destination, 'Existing filepath destination remains the same with FILE_EXISTS_REPLACE.', 'File'); $this->assertEqual($path, $destination, 'Existing filepath destination remains the same with FileSystemInterface::EXISTS_REPLACE.', 'File');
$path = file_destination($destination, FILE_EXISTS_RENAME); $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_RENAME);
$this->assertNotEqual($path, $destination, 'A new filepath destination is created when filepath destination already exists with FILE_EXISTS_RENAME.', 'File'); $this->assertNotEqual($path, $destination, 'A new filepath destination is created when filepath destination already exists with FileSystemInterface::EXISTS_RENAME.', 'File');
$path = file_destination($destination, FILE_EXISTS_ERROR); $path = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_ERROR);
$this->assertEqual($path, FALSE, 'An error is returned when filepath destination already exists with FILE_EXISTS_ERROR.', 'File'); $this->assertEqual($path, FALSE, 'An error is returned when filepath destination already exists with FileSystemInterface::EXISTS_ERROR.', 'File');
} }
/** /**

View File

@ -2,15 +2,18 @@
namespace Drupal\KernelTests\Core\File; namespace Drupal\KernelTests\Core\File;
use Drupal\Core\Site\Settings; use Drupal\Core\File\Exception\FileExistsException;
use Drupal\Core\File\Exception\FileNotExistsException;
use Drupal\Core\File\FileSystem; use Drupal\Core\File\FileSystem;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Site\Settings;
/** /**
* Tests the unmanaged file copy function. * Tests the unmanaged file copy function.
* *
* @group File * @group File
*/ */
class UnmanagedCopyTest extends FileTestBase { class FileCopyTest extends FileTestBase {
/** /**
* Copy a normal file. * Copy a normal file.
@ -21,7 +24,7 @@ class UnmanagedCopyTest extends FileTestBase {
// Copying to a new name. // Copying to a new name.
$desired_filepath = 'public://' . $this->randomMachineName(); $desired_filepath = 'public://' . $this->randomMachineName();
$new_filepath = file_unmanaged_copy($uri, $desired_filepath, FILE_EXISTS_ERROR); $new_filepath = \Drupal::service('file_system')->copy($uri, $desired_filepath, FileSystemInterface::EXISTS_ERROR);
$this->assertTrue($new_filepath, 'Copy was successful.'); $this->assertTrue($new_filepath, 'Copy was successful.');
$this->assertEqual($new_filepath, $desired_filepath, 'Returned expected filepath.'); $this->assertEqual($new_filepath, $desired_filepath, 'Returned expected filepath.');
$this->assertTrue(file_exists($uri), 'Original file remains.'); $this->assertTrue(file_exists($uri), 'Original file remains.');
@ -31,7 +34,7 @@ class UnmanagedCopyTest extends FileTestBase {
// Copying with rename. // Copying with rename.
$desired_filepath = 'public://' . $this->randomMachineName(); $desired_filepath = 'public://' . $this->randomMachineName();
$this->assertTrue(file_put_contents($desired_filepath, ' '), 'Created a file so a rename will have to happen.'); $this->assertTrue(file_put_contents($desired_filepath, ' '), 'Created a file so a rename will have to happen.');
$newer_filepath = file_unmanaged_copy($uri, $desired_filepath, FILE_EXISTS_RENAME); $newer_filepath = \Drupal::service('file_system')->copy($uri, $desired_filepath, FileSystemInterface::EXISTS_RENAME);
$this->assertTrue($newer_filepath, 'Copy was successful.'); $this->assertTrue($newer_filepath, 'Copy was successful.');
$this->assertNotEqual($newer_filepath, $desired_filepath, 'Returned expected filepath.'); $this->assertNotEqual($newer_filepath, $desired_filepath, 'Returned expected filepath.');
$this->assertTrue(file_exists($uri), 'Original file remains.'); $this->assertTrue(file_exists($uri), 'Original file remains.');
@ -49,7 +52,8 @@ class UnmanagedCopyTest extends FileTestBase {
// Copy non-existent file // Copy non-existent file
$desired_filepath = $this->randomMachineName(); $desired_filepath = $this->randomMachineName();
$this->assertFalse(file_exists($desired_filepath), "Randomly named file doesn't exist."); $this->assertFalse(file_exists($desired_filepath), "Randomly named file doesn't exist.");
$new_filepath = file_unmanaged_copy($desired_filepath, $this->randomMachineName()); $this->setExpectedException(FileNotExistsException::class);
$new_filepath = \Drupal::service('file_system')->copy($desired_filepath, $this->randomMachineName());
$this->assertFalse($new_filepath, 'Copying a missing file fails.'); $this->assertFalse($new_filepath, 'Copying a missing file fails.');
} }
@ -61,7 +65,9 @@ class UnmanagedCopyTest extends FileTestBase {
$uri = $this->createUri(); $uri = $this->createUri();
// Copy the file onto itself with renaming works. // Copy the file onto itself with renaming works.
$new_filepath = file_unmanaged_copy($uri, $uri, FILE_EXISTS_RENAME); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$new_filepath = $file_system->copy($uri, $uri, FileSystemInterface::EXISTS_RENAME);
$this->assertTrue($new_filepath, 'Copying onto itself with renaming works.'); $this->assertTrue($new_filepath, 'Copying onto itself with renaming works.');
$this->assertNotEqual($new_filepath, $uri, 'Copied file has a new name.'); $this->assertNotEqual($new_filepath, $uri, 'Copied file has a new name.');
$this->assertTrue(file_exists($uri), 'Original file exists after copying onto itself.'); $this->assertTrue(file_exists($uri), 'Original file exists after copying onto itself.');
@ -69,17 +75,18 @@ class UnmanagedCopyTest extends FileTestBase {
$this->assertFilePermissions($new_filepath, Settings::get('file_chmod_file', FileSystem::CHMOD_FILE)); $this->assertFilePermissions($new_filepath, Settings::get('file_chmod_file', FileSystem::CHMOD_FILE));
// Copy the file onto itself without renaming fails. // Copy the file onto itself without renaming fails.
$new_filepath = file_unmanaged_copy($uri, $uri, FILE_EXISTS_ERROR); $this->setExpectedException(FileExistsException::class);
$new_filepath = $file_system->copy($uri, $uri, FileSystemInterface::EXISTS_ERROR);
$this->assertFalse($new_filepath, 'Copying onto itself without renaming fails.'); $this->assertFalse($new_filepath, 'Copying onto itself without renaming fails.');
$this->assertTrue(file_exists($uri), 'File exists after copying onto itself.'); $this->assertTrue(file_exists($uri), 'File exists after copying onto itself.');
// Copy the file into same directory without renaming fails. // Copy the file into same directory without renaming fails.
$new_filepath = file_unmanaged_copy($uri, drupal_dirname($uri), FILE_EXISTS_ERROR); $new_filepath = $file_system->copy($uri, drupal_dirname($uri), FileSystemInterface::EXISTS_ERROR);
$this->assertFalse($new_filepath, 'Copying onto itself fails.'); $this->assertFalse($new_filepath, 'Copying onto itself fails.');
$this->assertTrue(file_exists($uri), 'File exists after copying onto itself.'); $this->assertTrue(file_exists($uri), 'File exists after copying onto itself.');
// Copy the file into same directory with renaming works. // Copy the file into same directory with renaming works.
$new_filepath = file_unmanaged_copy($uri, drupal_dirname($uri), FILE_EXISTS_RENAME); $new_filepath = $file_system->copy($uri, drupal_dirname($uri), FileSystemInterface::EXISTS_RENAME);
$this->assertTrue($new_filepath, 'Copying into same directory works.'); $this->assertTrue($new_filepath, 'Copying into same directory works.');
$this->assertNotEqual($new_filepath, $uri, 'Copied file has a new name.'); $this->assertNotEqual($new_filepath, $uri, 'Copied file has a new name.');
$this->assertTrue(file_exists($uri), 'Original file exists after copying onto itself.'); $this->assertTrue(file_exists($uri), 'Original file exists after copying onto itself.');

View File

@ -7,7 +7,7 @@ namespace Drupal\KernelTests\Core\File;
* *
* @group File * @group File
*/ */
class UnmanagedDeleteRecursiveTest extends FileTestBase { class FileDeleteRecursiveTest extends FileTestBase {
/** /**
* Delete a normal file. * Delete a normal file.
@ -18,7 +18,7 @@ class UnmanagedDeleteRecursiveTest extends FileTestBase {
file_put_contents($filepath, ''); file_put_contents($filepath, '');
// Delete the file. // Delete the file.
$this->assertTrue(file_unmanaged_delete_recursive($filepath), 'Function reported success.'); $this->assertTrue(\Drupal::service('file_system')->deleteRecursive($filepath), 'Function reported success.');
$this->assertFalse(file_exists($filepath), 'Test file has been deleted.'); $this->assertFalse(file_exists($filepath), 'Test file has been deleted.');
} }
@ -30,7 +30,7 @@ class UnmanagedDeleteRecursiveTest extends FileTestBase {
$directory = $this->createDirectory(); $directory = $this->createDirectory();
// Delete the directory. // Delete the directory.
$this->assertTrue(file_unmanaged_delete_recursive($directory), 'Function reported success.'); $this->assertTrue(\Drupal::service('file_system')->deleteRecursive($directory), 'Function reported success.');
$this->assertFalse(file_exists($directory), 'Directory has been deleted.'); $this->assertFalse(file_exists($directory), 'Directory has been deleted.');
} }
@ -46,7 +46,7 @@ class UnmanagedDeleteRecursiveTest extends FileTestBase {
file_put_contents($filepathB, ''); file_put_contents($filepathB, '');
// Delete the directory. // Delete the directory.
$this->assertTrue(file_unmanaged_delete_recursive($directory), 'Function reported success.'); $this->assertTrue(\Drupal::service('file_system')->deleteRecursive($directory), 'Function reported success.');
$this->assertFalse(file_exists($filepathA), 'Test file A has been deleted.'); $this->assertFalse(file_exists($filepathA), 'Test file A has been deleted.');
$this->assertFalse(file_exists($filepathB), 'Test file B has been deleted.'); $this->assertFalse(file_exists($filepathB), 'Test file B has been deleted.');
$this->assertFalse(file_exists($directory), 'Directory has been deleted.'); $this->assertFalse(file_exists($directory), 'Directory has been deleted.');
@ -65,7 +65,7 @@ class UnmanagedDeleteRecursiveTest extends FileTestBase {
file_put_contents($filepathB, ''); file_put_contents($filepathB, '');
// Delete the directory. // Delete the directory.
$this->assertTrue(file_unmanaged_delete_recursive($directory), 'Function reported success.'); $this->assertTrue(\Drupal::service('file_system')->deleteRecursive($directory), 'Function reported success.');
$this->assertFalse(file_exists($filepathA), 'Test file A has been deleted.'); $this->assertFalse(file_exists($filepathA), 'Test file A has been deleted.');
$this->assertFalse(file_exists($filepathB), 'Test file B has been deleted.'); $this->assertFalse(file_exists($filepathB), 'Test file B has been deleted.');
$this->assertFalse(file_exists($subdirectory), 'Subdirectory has been deleted.'); $this->assertFalse(file_exists($subdirectory), 'Subdirectory has been deleted.');

View File

@ -2,12 +2,14 @@
namespace Drupal\KernelTests\Core\File; namespace Drupal\KernelTests\Core\File;
use Drupal\Core\File\Exception\NotRegularFileException;
/** /**
* Tests the unmanaged file delete function. * Tests the unmanaged file delete function.
* *
* @group File * @group File
*/ */
class UnmanagedDeleteTest extends FileTestBase { class FileDeleteTest extends FileTestBase {
/** /**
* Delete a normal file. * Delete a normal file.
@ -17,7 +19,7 @@ class UnmanagedDeleteTest extends FileTestBase {
$uri = $this->createUri(); $uri = $this->createUri();
// Delete a regular file // Delete a regular file
$this->assertTrue(file_unmanaged_delete($uri), 'Deleted worked.'); $this->assertTrue(\Drupal::service('file_system')->delete($uri), 'Deleted worked.');
$this->assertFalse(file_exists($uri), 'Test file has actually been deleted.'); $this->assertFalse(file_exists($uri), 'Test file has actually been deleted.');
} }
@ -26,7 +28,7 @@ class UnmanagedDeleteTest extends FileTestBase {
*/ */
public function testMissing() { public function testMissing() {
// Try to delete a non-existing file // Try to delete a non-existing file
$this->assertTrue(file_unmanaged_delete(file_default_scheme() . '/' . $this->randomMachineName()), 'Returns true when deleting a non-existent file.'); $this->assertTrue(\Drupal::service('file_system')->delete(file_default_scheme() . '/' . $this->randomMachineName()), 'Returns true when deleting a non-existent file.');
} }
/** /**
@ -36,8 +38,14 @@ class UnmanagedDeleteTest extends FileTestBase {
// A directory to operate on. // A directory to operate on.
$directory = $this->createDirectory(); $directory = $this->createDirectory();
// Try to delete a directory // Try to delete a directory.
$this->assertFalse(file_unmanaged_delete($directory), 'Could not delete the delete directory.'); try {
\Drupal::service('file_system')->delete($directory);
$this->fail('Expected NotRegularFileException');
}
catch (NotRegularFileException $e) {
// Ignore.
}
$this->assertTrue(file_exists($directory), 'Directory has not been deleted.'); $this->assertTrue(file_exists($directory), 'Directory has not been deleted.');
} }

View File

@ -2,6 +2,9 @@
namespace Drupal\KernelTests\Core\File; namespace Drupal\KernelTests\Core\File;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\Exception\FileNotExistsException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Site\Settings; use Drupal\Core\Site\Settings;
use Drupal\Core\File\FileSystem; use Drupal\Core\File\FileSystem;
@ -10,7 +13,7 @@ use Drupal\Core\File\FileSystem;
* *
* @group File * @group File
*/ */
class UnmanagedMoveTest extends FileTestBase { class FileMoveTest extends FileTestBase {
/** /**
* Move a normal file. * Move a normal file.
@ -21,7 +24,9 @@ class UnmanagedMoveTest extends FileTestBase {
// Moving to a new name. // Moving to a new name.
$desired_filepath = 'public://' . $this->randomMachineName(); $desired_filepath = 'public://' . $this->randomMachineName();
$new_filepath = file_unmanaged_move($uri, $desired_filepath, FILE_EXISTS_ERROR); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$new_filepath = $file_system->move($uri, $desired_filepath, FileSystemInterface::EXISTS_ERROR);
$this->assertTrue($new_filepath, 'Move was successful.'); $this->assertTrue($new_filepath, 'Move was successful.');
$this->assertEqual($new_filepath, $desired_filepath, 'Returned expected filepath.'); $this->assertEqual($new_filepath, $desired_filepath, 'Returned expected filepath.');
$this->assertTrue(file_exists($new_filepath), 'File exists at the new location.'); $this->assertTrue(file_exists($new_filepath), 'File exists at the new location.');
@ -32,7 +37,7 @@ class UnmanagedMoveTest extends FileTestBase {
$desired_filepath = 'public://' . $this->randomMachineName(); $desired_filepath = 'public://' . $this->randomMachineName();
$this->assertTrue(file_exists($new_filepath), 'File exists before moving.'); $this->assertTrue(file_exists($new_filepath), 'File exists before moving.');
$this->assertTrue(file_put_contents($desired_filepath, ' '), 'Created a file so a rename will have to happen.'); $this->assertTrue(file_put_contents($desired_filepath, ' '), 'Created a file so a rename will have to happen.');
$newer_filepath = file_unmanaged_move($new_filepath, $desired_filepath, FILE_EXISTS_RENAME); $newer_filepath = $file_system->move($new_filepath, $desired_filepath, FileSystemInterface::EXISTS_RENAME);
$this->assertTrue($newer_filepath, 'Move was successful.'); $this->assertTrue($newer_filepath, 'Move was successful.');
$this->assertNotEqual($newer_filepath, $desired_filepath, 'Returned expected filepath.'); $this->assertNotEqual($newer_filepath, $desired_filepath, 'Returned expected filepath.');
$this->assertTrue(file_exists($newer_filepath), 'File exists at the new location.'); $this->assertTrue(file_exists($newer_filepath), 'File exists at the new location.');
@ -48,8 +53,8 @@ class UnmanagedMoveTest extends FileTestBase {
*/ */
public function testMissing() { public function testMissing() {
// Move non-existent file. // Move non-existent file.
$new_filepath = file_unmanaged_move($this->randomMachineName(), $this->randomMachineName()); $this->setExpectedException(FileNotExistsException::class);
$this->assertFalse($new_filepath, 'Moving a missing file fails.'); \Drupal::service('file_system')->move($this->randomMachineName(), $this->randomMachineName());
} }
/** /**
@ -60,12 +65,15 @@ class UnmanagedMoveTest extends FileTestBase {
$uri = $this->createUri(); $uri = $this->createUri();
// Move the file onto itself without renaming shouldn't make changes. // Move the file onto itself without renaming shouldn't make changes.
$new_filepath = file_unmanaged_move($uri, $uri, FILE_EXISTS_REPLACE); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$this->setExpectedException(FileException::class);
$new_filepath = $file_system->move($uri, $uri, FileSystemInterface::EXISTS_REPLACE);
$this->assertFalse($new_filepath, 'Moving onto itself without renaming fails.'); $this->assertFalse($new_filepath, 'Moving onto itself without renaming fails.');
$this->assertTrue(file_exists($uri), 'File exists after moving onto itself.'); $this->assertTrue(file_exists($uri), 'File exists after moving onto itself.');
// Move the file onto itself with renaming will result in a new filename. // Move the file onto itself with renaming will result in a new filename.
$new_filepath = file_unmanaged_move($uri, $uri, FILE_EXISTS_RENAME); $new_filepath = $file_system->move($uri, $uri, FileSystemInterface::EXISTS_RENAME);
$this->assertTrue($new_filepath, 'Moving onto itself with renaming works.'); $this->assertTrue($new_filepath, 'Moving onto itself with renaming works.');
$this->assertFalse(file_exists($uri), 'Original file has been removed.'); $this->assertFalse(file_exists($uri), 'Original file has been removed.');
$this->assertTrue(file_exists($new_filepath), 'File exists after moving onto itself.'); $this->assertTrue(file_exists($new_filepath), 'File exists after moving onto itself.');

View File

@ -7,7 +7,7 @@ namespace Drupal\KernelTests\Core\File;
* *
* @group File * @group File
*/ */
class UnmanagedSaveDataTest extends FileTestBase { class FileSaveDataTest extends FileTestBase {
/** /**
* Test the file_unmanaged_save_data() function. * Test the file_unmanaged_save_data() function.
@ -17,13 +17,15 @@ class UnmanagedSaveDataTest extends FileTestBase {
$this->setSetting('file_chmod_file', 0777); $this->setSetting('file_chmod_file', 0777);
// No filename. // No filename.
$filepath = file_unmanaged_save_data($contents); /** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$filepath = $file_system->saveData($contents);
$this->assertTrue($filepath, 'Unnamed file saved correctly.'); $this->assertTrue($filepath, 'Unnamed file saved correctly.');
$this->assertEqual(file_uri_scheme($filepath), file_default_scheme(), "File was placed in Drupal's files directory."); $this->assertEqual(file_uri_scheme($filepath), file_default_scheme(), "File was placed in Drupal's files directory.");
$this->assertEqual($contents, file_get_contents($filepath), 'Contents of the file are correct.'); $this->assertEqual($contents, file_get_contents($filepath), 'Contents of the file are correct.');
// Provide a filename. // Provide a filename.
$filepath = file_unmanaged_save_data($contents, 'public://asdf.txt', FILE_EXISTS_REPLACE); $filepath = $file_system->saveData($contents, 'public://asdf.txt', FILE_EXISTS_REPLACE);
$this->assertTrue($filepath, 'Unnamed file saved correctly.'); $this->assertTrue($filepath, 'Unnamed file saved correctly.');
$this->assertEqual('asdf.txt', drupal_basename($filepath), 'File was named correctly.'); $this->assertEqual('asdf.txt', drupal_basename($filepath), 'File was named correctly.');
$this->assertEqual($contents, file_get_contents($filepath), 'Contents of the file are correct.'); $this->assertEqual($contents, file_get_contents($filepath), 'Contents of the file are correct.');

View File

@ -26,4 +26,68 @@ class FileSystemDeprecationTest extends KernelTestBase {
$this->assertNotNull(drupal_move_uploaded_file('', '')); $this->assertNotNull(drupal_move_uploaded_file('', ''));
} }
/**
* @expectedDeprecation file_unmanaged_copy() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::copy(). See https://www.drupal.org/node/3006851.
*/
public function testDeprecatedUnmanagedFileCopy() {
$this->assertNotNull(file_unmanaged_copy(NULL));
}
/**
* @expectedDeprecation file_unmanaged_delete() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::delete(). See https://www.drupal.org/node/3006851.
*/
public function testDeprecatedUnmanagedFileDelete() {
$this->assertNotNull(file_unmanaged_delete(NULL));
}
/**
* @expectedDeprecation file_unmanaged_delete_recursive() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::deleteRecursive(). See https://www.drupal.org/node/3006851.
*/
public function testDeprecatedUnmanagedFileDeleteRecursive() {
$this->assertNotNull(file_unmanaged_delete_recursive(NULL));
}
/**
* @expectedDeprecation file_unmanaged_move() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::move(). See https://www.drupal.org/node/3006851.
*/
public function testDeprecatedUnmanagedFileMove() {
$this->assertNotNull(file_unmanaged_move(NULL));
}
/**
* @expectedDeprecation file_unmanaged_prepare() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::getDestinationFilename() instead. See https://www.drupal.org/node/3006851.
*/
public function testDeprecatedUnmanagedPrepare() {
$this->assertNotNull(file_unmanaged_prepare(NULL));
}
/**
* @expectedDeprecation file_unmanaged_save_data() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::saveData(). See https://www.drupal.org/node/3006851.
*/
public function testDeprecatedUnmanagedSaveData() {
$this->assertNotNull(file_unmanaged_save_data(NULL));
}
/**
* @expectedDeprecation file_prepare_directory() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::prepareDirectory(). See https://www.drupal.org/node/3006851.
*/
public function testDeprecatedFilePrepareDirectory() {
$dir = NULL;
$this->assertNotNull(file_prepare_directory($dir));
}
/**
* @expectedDeprecation file_destination() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::getDestinationFilename(). See https://www.drupal.org/node/3006851.
*/
public function testDeprecatedFileDestination() {
$this->assertNotNull(file_destination('', ''));
}
/**
* @expectedDeprecation file_create_filename() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::createFilename(). See https://www.drupal.org/node/3006851.
*/
public function testDeprecatedFileCreate() {
$this->assertNotNull(file_create_filename('', ''));
}
} }

View File

@ -0,0 +1,102 @@
<?php
namespace Drupal\KernelTests\Core\File;
use Drupal\Core\File\Exception\DirectoryNotReadyException;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\Exception\FileExistsException;
use Drupal\Core\File\Exception\FileNotExistsException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\KernelTests\KernelTestBase;
/**
* @coversDefaultClass \Drupal\Core\File\FileSystem
* @group File
*/
class FileSystemTest extends KernelTestBase {
/**
* The file handler under test.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/**
* {@inheritdoc}
*/
public static $modules = ['system'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->fileSystem = $this->container->get('file_system');
}
/**
* @covers ::copy
*/
public function testEnsureFileExistsBeforeCopy() {
// We need to compute the exception message here because it will include
// the 'real' path to the file, which varies with $this->siteDirectory.
$this->setExpectedException(
FileNotExistsException::class,
"File 'public://test.txt' ('{$this->siteDirectory}/files/test.txt') could not be copied because it does not exist"
);
$this->fileSystem->copy('public://test.txt', 'public://test-copy.txt');
}
/**
* @covers ::copy
*/
public function testDestinationDirectoryFailureOnCopy() {
$this->setExpectedException(DirectoryNotReadyException::class, "The specified file 'public://test.txt' could not be copied because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions");
touch('public://test.txt');
// public://subdirectory has not been created, so \Drupal::service('file_system')->prepareDirectory()
// will fail, causing copy() to throw DirectoryNotReadyException.
$this->fileSystem->copy('public://test.txt', 'public://subdirectory/test.txt');
}
/**
* @covers ::copy
*/
public function testCopyFailureIfFileAlreadyExists() {
$this->setExpectedException(FileExistsException::class, "File 'public://test.txt' could not be copied because a file by that name already exists in the destination directory ('')");
$uri = 'public://test.txt';
touch($uri);
$this->fileSystem->copy($uri, $uri, FileSystemInterface::EXISTS_ERROR);
}
/**
* @covers ::copy
*/
public function testCopyFailureIfSelfOverwrite() {
$this->setExpectedException(FileException::class, "'public://test.txt' could not be copied because it would overwrite itself");
$uri = 'public://test.txt';
touch($uri);
$this->fileSystem->copy($uri, $uri, FileSystemInterface::EXISTS_REPLACE);
}
/**
* @covers ::copy
*/
public function testCopySelfRename() {
$uri = 'public://test.txt';
touch($uri);
$this->fileSystem->copy($uri, $uri);
$this->assertFileExists('public://test_0.txt');
}
/**
* @covers ::copy
*/
public function testSuccessfulCopy() {
touch('public://test.txt');
$this->fileSystem->copy('public://test.txt', 'public://test-copy.txt');
$this->assertFileExists('public://test-copy.txt');
}
}

View File

@ -7,7 +7,7 @@ namespace Drupal\KernelTests\Core\File;
* *
* @group File * @group File
*/ */
class RemoteFileUnmanagedDeleteRecursiveTest extends UnmanagedDeleteRecursiveTest { class RemoteFileDeleteRecursiveTest extends FileDeleteRecursiveTest {
/** /**
* Modules to enable. * Modules to enable.

View File

@ -7,7 +7,7 @@ namespace Drupal\KernelTests\Core\File;
* *
* @group File * @group File
*/ */
class RemoteFileUnmanagedDeleteTest extends UnmanagedDeleteTest { class RemoteFileDeleteTest extends FileDeleteTest {
/** /**
* Modules to enable. * Modules to enable.

View File

@ -7,7 +7,7 @@ namespace Drupal\KernelTests\Core\File;
* *
* @group File * @group File
*/ */
class RemoteFileUnmanagedMoveTest extends UnmanagedMoveTest { class RemoteFileMoveTest extends FileMoveTest {
/** /**
* Modules to enable. * Modules to enable.

View File

@ -7,7 +7,7 @@ namespace Drupal\KernelTests\Core\File;
* *
* @group File * @group File
*/ */
class RemoteFileUnmanagedSaveDataTest extends UnmanagedSaveDataTest { class RemoteFileSaveDataTest extends FileSaveDataTest {
/** /**
* Modules to enable. * Modules to enable.

View File

@ -7,7 +7,7 @@ namespace Drupal\KernelTests\Core\File;
* *
* @group File * @group File
*/ */
class RemoteFileUnmanagedCopyTest extends UnmanagedCopyTest { class RemoteFileUnmanagedCopyTest extends FileCopyTest {
/** /**
* Modules to enable. * Modules to enable.

View File

@ -2,6 +2,7 @@
namespace Drupal\KernelTests\Core\Image; namespace Drupal\KernelTests\Core\Image;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Image\ImageInterface; use Drupal\Core\Image\ImageInterface;
use Drupal\Component\Render\FormattableMarkup; use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Site\Settings; use Drupal\Core\Site\Settings;
@ -274,7 +275,7 @@ class ToolkitGdTest extends KernelTestBase {
// Prepare a directory for test file results. // Prepare a directory for test file results.
$directory = Settings::get('file_public_path') . '/imagetest'; $directory = Settings::get('file_public_path') . '/imagetest';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
foreach ($files as $file) { foreach ($files as $file) {
foreach ($operations as $op => $values) { foreach ($operations as $op => $values) {
@ -450,7 +451,7 @@ class ToolkitGdTest extends KernelTestBase {
public function testGifTransparentImages() { public function testGifTransparentImages() {
// Prepare a directory for test file results. // Prepare a directory for test file results.
$directory = Settings::get('file_public_path') . '/imagetest'; $directory = Settings::get('file_public_path') . '/imagetest';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY); \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
// Test loading an indexed GIF image with transparent color set. // Test loading an indexed GIF image with transparent color set.
// Color at top-right pixel should be fully transparent. // Color at top-right pixel should be fully transparent.

View File

@ -290,7 +290,7 @@ class TypedDataTest extends KernelTestBase {
$files = []; $files = [];
for ($i = 0; $i < 3; $i++) { for ($i = 0; $i < 3; $i++) {
$path = "public://example_$i.png"; $path = "public://example_$i.png";
file_unmanaged_copy($this->root . '/core/misc/druplicon.png', $path); \Drupal::service('file_system')->copy($this->root . '/core/misc/druplicon.png', $path);
$image = File::create(['uri' => $path]); $image = File::create(['uri' => $path]);
$image->save(); $image->save();
$files[] = $image; $files[] = $image;

View File

@ -415,7 +415,7 @@ abstract class BrowserTestBase extends TestCase {
} }
/** /**
* Ensures test files are deletable within file_unmanaged_delete_recursive(). * Ensures test files are deletable.
* *
* Some tests chmod generated files to be read only. During * Some tests chmod generated files to be read only. During
* BrowserTestBase::cleanupEnvironment() and other cleanup operations, * BrowserTestBase::cleanupEnvironment() and other cleanup operations,
@ -423,6 +423,8 @@ abstract class BrowserTestBase extends TestCase {
* *
* @param string $path * @param string $path
* The file path. * The file path.
*
* @see \Drupal\Core\File\FileSystemInterface::deleteRecursive()
*/ */
public static function filePreDeleteCallback($path) { public static function filePreDeleteCallback($path) {
// When the webserver runs with the same system user as phpunit, we can // When the webserver runs with the same system user as phpunit, we can
@ -451,7 +453,7 @@ abstract class BrowserTestBase extends TestCase {
} }
// Delete test site directory. // Delete test site directory.
file_unmanaged_delete_recursive($this->siteDirectory, [$this, 'filePreDeleteCallback']); \Drupal::service('file_system')->deleteRecursive($this->siteDirectory, [$this, 'filePreDeleteCallback']);
} }
/** /**

View File

@ -71,7 +71,7 @@ trait TestFileCreationTrait {
$original = drupal_get_path('module', 'simpletest') . '/files'; $original = drupal_get_path('module', 'simpletest') . '/files';
$files = file_scan_directory($original, '/(html|image|javascript|php|sql)-.*/'); $files = file_scan_directory($original, '/(html|image|javascript|php|sql)-.*/');
foreach ($files as $file) { foreach ($files as $file) {
file_unmanaged_copy($file->uri, PublicStream::basePath()); \Drupal::service('file_system')->copy($file->uri, PublicStream::basePath());
} }
$this->generatedTestFiles = TRUE; $this->generatedTestFiles = TRUE;