diff --git a/core/includes/file.inc b/core/includes/file.inc index de6c177..adedc0a 100644 --- a/core/includes/file.inc +++ b/core/includes/file.inc @@ -11,6 +11,7 @@ use Drupal\Component\PhpStorage\FileStorage; use Drupal\Component\Utility\Bytes; use Drupal\Core\File\Exception\FileException; +use Drupal\Core\File\FileHandlerInterface; use Drupal\Core\File\FileSystem; use Drupal\Core\Site\Settings; use Drupal\Core\StreamWrapper\PublicStream; @@ -54,7 +55,7 @@ * @deprecated in Drupal 8.3.x, will be removed before Drupal 9.0.0. * Use \Drupal\Core\File\FileHandlerInterface::FILE_EXISTS_RENAME. */ -const FILE_EXISTS_RENAME = \Drupal\Core\File\FileHandlerInterface::FILE_EXISTS_RENAME; +const FILE_EXISTS_RENAME = FileHandlerInterface::FILE_EXISTS_RENAME; /** * Flag for dealing with existing files: Replace the existing file. @@ -62,7 +63,7 @@ * @deprecated in Drupal 8.3.x, will be removed before Drupal 9.0.0. * Use \Drupal\Core\File\FileHandlerInterface::FILE_EXISTS_REPLACE. */ -const FILE_EXISTS_REPLACE = \Drupal\Core\File\FileHandlerInterface::FILE_EXISTS_REPLACE; +const FILE_EXISTS_REPLACE = FileHandlerInterface::FILE_EXISTS_REPLACE; /** * Flag for dealing with existing files: Do nothing and return FALSE. @@ -70,7 +71,7 @@ * @deprecated in Drupal 8.3.x, will be removed before Drupal 9.0.0. * Use \Drupal\Core\File\FileHandlerInterface::FILE_EXISTS_ERROR. */ -const FILE_EXISTS_ERROR = \Drupal\Core\File\FileHandlerInterface::FILE_EXISTS_ERROR; +const FILE_EXISTS_ERROR = FileHandlerInterface::FILE_EXISTS_ERROR; /** * Indicates that the file is permanent and should not be deleted. @@ -472,91 +473,17 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST /** * Internal function that prepares the destination for a file_unmanaged_copy or * file_unmanaged_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 $source - * A string specifying the filepath or URI of the source file. - * @param $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 $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 - * TRUE, or FALSE in the event of an error. - * - * @see file_unmanaged_copy() - * @see file_unmanaged_move() + + * @deprecated in Drupal 8.3.x, will be removed before Drupal 9.0.0. */ function file_unmanaged_prepare($source, &$destination = NULL, $replace = FILE_EXISTS_RENAME) { - $original_source = $source; - $logger = \Drupal::logger('file'); - - // Assert that the source file actually exists. - if (!file_exists($source)) { - // @todo Replace drupal_set_message() calls with exceptions instead. - drupal_set_message(t('The specified file %file could not be moved/copied because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => $original_source)), 'error'); - if (($realpath = drupal_realpath($original_source)) !== FALSE) { - $logger->notice('File %file (%realpath) could not be moved/copied because it does not exist.', array('%file' => $original_source, '%realpath' => $realpath)); - } - else { - $logger->notice('File %file could not be moved/copied because it does not exist.', array('%file' => $original_source)); - } - return FALSE; - } - - // Build a destination URI if necessary. - if (!isset($destination)) { - $destination = file_build_uri(drupal_basename($source)); - } - - - // Prepare the destination directory. - if (file_prepare_directory($destination)) { - // The destination is already a directory, so append the source basename. - $destination = file_stream_wrapper_uri_normalize($destination . '/' . drupal_basename($source)); - } - else { - // Perhaps $destination is a dir/file? - $dirname = drupal_dirname($destination); - if (!file_prepare_directory($dirname)) { - // The destination is not valid. - $logger->notice('File %file could not be moved/copied because the destination directory %destination is not configured correctly.', array('%file' => $original_source, '%destination' => $dirname)); - drupal_set_message(t('The specified file %file could not be moved/copied because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.', array('%file' => $original_source)), 'error'); - return FALSE; - } - } - - // Determine whether we can perform this operation based on overwrite rules. - $destination = file_destination($destination, $replace); - if ($destination === FALSE) { - drupal_set_message(t('The file %file could not be moved/copied because a file by that name already exists in the destination directory.', array('%file' => $original_source)), 'error'); - $logger->notice('File %file could not be moved/copied because a file by that name already exists in the destination directory (%destination)', array('%file' => $original_source, '%destination' => $destination)); - return FALSE; + try { + return \Drupal::service('file_handler.unmanaged')->prepare($source, $destination, $replace); } - - // Assert that the source and destination filenames are not the same. - $real_source = drupal_realpath($source); - $real_destination = drupal_realpath($destination); - if ($source == $destination || ($real_source !== FALSE) && ($real_source == $real_destination)) { - drupal_set_message(t('The specified file %file was not moved/copied because it would overwrite itself.', array('%file' => $source)), 'error'); - $logger->notice('File %file could not be moved/copied because it would overwrite itself.', array('%file' => $source)); + catch (FileException $e) { + \Drupal::logger('file')->error($e->getMessage()); return FALSE; } - // Make sure the .htaccess files are present. - file_ensure_htaccess(); - return TRUE; } /** diff --git a/core/lib/Drupal/Core/File/UnmanagedFileHandler.php b/core/lib/Drupal/Core/File/UnmanagedFileHandler.php index 2481297..c06c6e6 100644 --- a/core/lib/Drupal/Core/File/UnmanagedFileHandler.php +++ b/core/lib/Drupal/Core/File/UnmanagedFileHandler.php @@ -6,6 +6,7 @@ use Drupal\Core\File\Exception\FileException; use Drupal\Core\File\Exception\FileExistsException; use Drupal\Core\File\Exception\FileNotExistsException; +use Drupal\Core\File\FileHandlerInterface; /** * Implements service for low-level unhandled file operations. @@ -32,7 +33,63 @@ public function __construct(FileSystemInterface $file_system) { /** * {@inheritdoc} */ - public function copy($source, $destination, $replace = self::FILE_EXISTS_RENAME) { + public function copy($source, $destination, $replace = FileSystemInterface::FILE_EXISTS_RENAME) { + $this->prepare($source, $destination, $replace); + + // Perform the copy operation. + if (!@copy($source, $destination)) { + // If the copy failed and realpaths exist, retry the operation using them + // instead. + if ($real_source === FALSE || $real_destination === FALSE || !@copy($real_source, $real_destination)) { + throw new FileException(sprintf("The specified file '%s' could not be copied to '%s'.", $source, $destination)); + } + } + + // Set the permissions on the new file. + $this->fileSystem->chmod($destination); + + return $destination; + } + + /** + * Internal function that prepares the destination for a file_unmanaged_copy or + * file_unmanaged_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. + * + * @internal + * This public method is marked internal in 8.3.x and will be + * converted into private method before 9.0.0. + * + * @param $source + * A string specifying the filepath or URI of the source file. + * @param $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 $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 void + * + * @throws \Drupal\Core\File\Exception\DirectoryNotReadyException + * @throws \Drupal\Core\File\Exception\FileException + * @throws \Drupal\Core\File\Exception\FileExistsException + * @throws \Drupal\Core\File\Exception\FileNotExistsException + * + * @see \Drupal\Core\File\UnmanagedFileHandler::copy() + * @see \Drupal\Core\File\UnmanagedFileHandler::move() + */ + public function prepare($source, &$destination = NULL, $replace = FileSystemInterface::FILE_EXISTS_RENAME) { $original_source = $source; // Assert that the source file actually exists. @@ -77,20 +134,6 @@ public function copy($source, $destination, $replace = self::FILE_EXISTS_RENAME) } // Make sure the .htaccess files are present. file_ensure_htaccess(); - - // Perform the copy operation. - if (!@copy($source, $destination)) { - // If the copy failed and realpaths exist, retry the operation using them - // instead. - if ($real_source === FALSE || $real_destination === FALSE || !@copy($real_source, $real_destination)) { - throw new FileException(sprintf("The specified file '%s' could not be copied to '%s'.", $source, $destination)); - } - } - - // Set the permissions on the new file. - $this->fileSystem->chmod($destination); - - return $destination; } }