summaryrefslogtreecommitdiff
path: root/includes/file.inc
diff options
context:
space:
mode:
Diffstat (limited to 'includes/file.inc')
-rw-r--r--includes/file.inc141
1 files changed, 110 insertions, 31 deletions
diff --git a/includes/file.inc b/includes/file.inc
index b7a096f98..d047e1f7e 100644
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -361,18 +361,21 @@ function file_save($file) {
* replace the file or rename the file based on the $replace parameter.
* - Adds the new file to the files database. If the source file is a
* temporary file, the resulting file will also be a temporary file.
- * @see file_save_upload about temporary files.
+ * @see file_save_upload() for details on temporary files.
*
* @param $source
* A file object.
* @param $destination
- * A string containing the directory $source should be copied to. If this
- * value is omitted, Drupal's 'files' directory will be used.
+ * A string containing the destination that $source should be copied to. This
+ * can be a complete file path, a directory path or, if this value is omitted,
+ * Drupal's 'files' directory will be used.
* @param $replace
* Replace behavior when the destination file already exists:
- * - FILE_EXISTS_REPLACE - Replace the existing file.
+ * - FILE_EXISTS_REPLACE - Replace the existing file. If a managed file with
+ * the destination name exists then its database entry will be updated. If
+ * no database entry is found then a new one will be created.
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
- * unique.
+ * unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
* @return
* File object if the copy is successful, or FALSE in the event of an error.
@@ -385,14 +388,30 @@ function file_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
if ($filepath = file_unmanaged_copy($source->filepath, $destination, $replace)) {
$file = clone $source;
- $file->fid = NULL;
- $file->filename = basename($filepath);
+ $file->fid = NULL;
$file->filepath = $filepath;
- if ($file = file_save($file)) {
- // Inform modules that the file has been copied.
- module_invoke_all('file_copy', $file, $source);
- return $file;
+ $file->filename = basename($filepath);
+ // If we are replacing an existing file re-use its database record.
+ if ($replace == FILE_EXISTS_REPLACE) {
+ $existing_files = file_load_multiple(array(), array('filepath' => $filepath));
+ if (count($existing_files)) {
+ $existing = reset($existing_files);
+ $file->fid = $existing->fid;
+ $file->filename = $existing->filename;
+ }
}
+ // If we are renaming around an existing file (rather than a directory),
+ // use its basename for the filename.
+ else if ($replace == FILE_EXISTS_RENAME && is_file(file_create_path($destination))) {
+ $file->filename = basename($destination);
+ }
+
+ $file = file_save($file);
+
+ // Inform modules that the file has been copied.
+ module_invoke_all('file_copy', $file, $source);
+
+ return $file;
}
return FALSE;
}
@@ -412,13 +431,14 @@ function file_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
* @param $source
* A string specifying the file location of the original file.
* @param $destination
- * A string containing the directory $source should be copied to. If this
- * value is omitted, Drupal's 'files' directory will be used.
+ * A string containing the destination that $source should be copied to. This
+ * can be a complete file path, a directory path or, if this value is omitted,
+ * Drupal's 'files' directory will be used.
* @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.
+ * unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
* @return
* The path to the new file, or FALSE in the event of an error.
@@ -482,7 +502,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
* 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.
+ * unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
* @return
* The destination file path or FALSE if the file already exists and
@@ -523,13 +543,18 @@ function file_destination($destination, $replace) {
* @param $source
* A file object.
* @param $destination
- * A string containing the directory $source should be copied to. If this
- * value is omitted, Drupal's 'files' directory will be used.
+ * A string containing the destination that $source should be moved to. This
+ * can be a complete file path, a directory path or, if this value is omitted,
+ * Drupal's 'files' directory will be used.
* @param $replace
* Replace behavior when the destination file already exists:
- * - FILE_EXISTS_REPLACE - Replace the existing file.
+ * - FILE_EXISTS_REPLACE - Replace the existing file. If a managed file with
+ * the destination name exists then its database entry will be updated and
+ * file_delete() called on the source file after hook_file_move is called.
+ * If no database entry is found then the source files record will be
+ * updated.
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
- * unique.
+ * unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
* @return
* Resulting file object for success, or FALSE in the event of an error.
@@ -541,15 +566,36 @@ function file_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
$source = (object)$source;
if ($filepath = file_unmanaged_move($source->filepath, $destination, $replace)) {
+ $delete_source = FALSE;
+
$file = clone $source;
- $file->filename = basename($filepath);
$file->filepath = $filepath;
- if ($file = file_save($file)) {
- // Inform modules that the file has been moved.
- module_invoke_all('file_move', $file, $source);
- return $file;
+ // If we are replacing an existing file re-use its database record.
+ if ($replace == FILE_EXISTS_REPLACE) {
+ $existing_files = file_load_multiple(array(), array('filepath' => $filepath));
+ if (count($existing_files)) {
+ $existing = reset($existing_files);
+ $delete_source = TRUE;
+ $file->fid = $existing->fid;
+ }
}
- drupal_set_message(t('The removal of the original file %file has failed.', array('%file' => $source->filepath)), 'error');
+ // If we are renaming around an existing file (rather than a directory),
+ // use its basename for the filename.
+ else if ($replace == FILE_EXISTS_RENAME && is_file(file_create_path($destination))) {
+ $file->filename = basename($destination);
+ }
+
+ $file = file_save($file);
+
+ // Inform modules that the file has been moved.
+ module_invoke_all('file_move', $file, $source);
+
+ if ($delete_source) {
+ // Try a soft delete to remove original if it's not in use elsewhere.
+ file_delete($source);
+ }
+
+ return $file;
}
return FALSE;
}
@@ -561,13 +607,14 @@ function file_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
* @param $source
* A string specifying the file location of the original file.
* @param $destination
- * A string containing the directory $source should be copied to. If this
- * value is omitted, Drupal's 'files' directory will be used.
+ * A string containing the destination that $source should be moved to. This
+ * can be a complete file path, a directory name or, if this value is omitted,
+ * Drupal's 'files' directory will be used.
* @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.
+ * unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
* @return
* The filepath of the moved file, or FALSE in the event of an error.
@@ -875,6 +922,11 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
$file->source = $source;
$file->destination = file_destination(file_create_path($destination . '/' . $file->filename), $replace);
+ // If file_destination() returns FALSE then $replace == FILE_EXISTS_ERROR and
+ // there's an existing file so we need to bail.
+ if ($file->destination === FALSE) {
+ return FALSE;
+ }
// Add in our check of the the file name length.
$validators['file_validate_name_length'] = array();
@@ -905,6 +957,15 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
return FALSE;
}
+ // If we are replacing an existing file re-use its database record.
+ if ($replace == FILE_EXISTS_REPLACE) {
+ $existing_files = file_load_multiple(array(), array('filepath' => $file->filepath));
+ if (count($existing_files)) {
+ $existing = reset($existing_files);
+ $file->fid = $existing->fid;
+ }
+ }
+
// If we made it this far it's safe to record this file in the database.
if ($file = file_save($file)) {
// Add file to the cache.
@@ -1121,9 +1182,11 @@ function file_validate_image_resolution(&$file, $maximum_dimensions = 0, $minimu
* files directory.
* @param $replace
* Replace behavior when the destination file already exists:
- * - FILE_EXISTS_REPLACE - Replace the existing file.
+ * - FILE_EXISTS_REPLACE - Replace the existing file. If a managed file with
+ * the destination name exists then its database entry will be updated. If
+ * no database entry is found then a new one will be created.
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
- * unique.
+ * unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
* @return
* A file object, or FALSE on error.
@@ -1136,11 +1199,27 @@ function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAM
if ($filepath = file_unmanaged_save_data($data, $destination, $replace)) {
// Create a file object.
$file = new stdClass();
+ $file->fid = NULL;
$file->filepath = $filepath;
- $file->filename = basename($file->filepath);
+ $file->filename = basename($filepath);
$file->filemime = file_get_mimetype($file->filepath);
$file->uid = $user->uid;
$file->status |= FILE_STATUS_PERMANENT;
+ // If we are replacing an existing file re-use its database record.
+ if ($replace == FILE_EXISTS_REPLACE) {
+ $existing_files = file_load_multiple(array(), array('filepath' => $filepath));
+ if (count($existing_files)) {
+ $existing = reset($existing_files);
+ $file->fid = $existing->fid;
+ $file->filename = $existing->filename;
+ }
+ }
+ // If we are renaming around an existing file (rather than a directory),
+ // use its basename for the filename.
+ else if ($replace == FILE_EXISTS_RENAME && is_file(file_create_path($destination))) {
+ $file->filename = basename($destination);
+ }
+
return file_save($file);
}
return FALSE;