? .DS_Store
? .cache
? .git
? .project
? .settings
? diff.patch
? logs
? modules/.DS_Store
? sites/all/modules
? sites/default/files
? sites/default/settings.php
? sites/default/test
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.790
diff -u -p -r1.790 common.inc
--- includes/common.inc 6 Sep 2008 15:06:10 -0000 1.790
+++ includes/common.inc 7 Sep 2008 00:09:47 -0000
@@ -1815,7 +1815,7 @@ function drupal_build_css_cache($types,
$data = implode('', $matches[0]) . $data;
// Create the CSS file.
- file_save_data($data, $csspath . '/' . $filename, FILE_EXISTS_REPLACE);
+ file_save_data_plain($data, $csspath . '/' . $filename, FILE_EXISTS_REPLACE);
}
return $csspath . '/' . $filename;
}
@@ -1916,7 +1916,7 @@ function _drupal_load_stylesheet($matche
* Delete all cached CSS files.
*/
function drupal_clear_css_cache() {
- file_scan_directory(file_create_path('css'), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE);
+ file_scan_directory(file_create_path('css'), '.*', array('.', '..', 'CVS'), 'file_delete_plain', TRUE);
}
/**
@@ -2279,7 +2279,7 @@ function drupal_build_js_cache($files, $
}
// Create the JS file.
- file_save_data($contents, $jspath . '/' . $filename, FILE_EXISTS_REPLACE);
+ file_save_data_plain($contents, $jspath . '/' . $filename, FILE_EXISTS_REPLACE);
}
return $jspath . '/' . $filename;
@@ -2290,6 +2290,7 @@ function drupal_build_js_cache($files, $
*/
function drupal_clear_js_cache() {
file_scan_directory(file_create_path('js'), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE);
+ file_scan_directory(file_create_path('js'), '.*', array('.', '..', 'CVS'), 'file_delete_plain', TRUE);
variable_set('javascript_parsed', array());
}
Index: includes/file.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/file.inc,v
retrieving revision 1.130
diff -u -p -r1.130 file.inc
--- includes/file.inc 6 Sep 2008 08:36:19 -0000 1.130
+++ includes/file.inc 7 Sep 2008 00:09:47 -0000
@@ -10,6 +10,19 @@
* @defgroup file File interface
* @{
* Common file handling functions.
+ *
+ * Fields on the file object:
+ * - fid - Primary Key: Unique files ID.
+ * - uid - The {users}.uid of the user who is associated with the file.
+ * filename - Name of the file with no path components. This may differ
+ * from the basename of the filepath if the file is renamed to avoid
+ * overwriting an existing file.
+ * - filepath - Path of the file relative to Drupal root.
+ * - filemime - The file's MIME type.
+ * - filesize - The size of the file in bytes.
+ * - status - A flag indicating whether file is temporary (1) or permanent (0).
+ * Files that are temporary will removed be removed during
+ * - timestamp' UNIX timestamp for the date the file was added to the database.
*/
/**
@@ -29,17 +42,18 @@ define('FILE_DOWNLOADS_PUBLIC', 1);
define('FILE_DOWNLOADS_PRIVATE', 2);
/**
- * Flag used by file_create_directory() -- create directory if not present.
+ * Flag used by file_check_directory() -- create directory if not present.
*/
define('FILE_CREATE_DIRECTORY', 1);
/**
- * Flag used by file_create_directory() -- file permissions may be changed.
+ * Flag used by file_check_directory() -- file permissions may be changed.
*/
define('FILE_MODIFY_PERMISSIONS', 2);
/**
- * Flag for dealing with existing files: Append number until filename is unique.
+ * Flag for dealing with existing files: Append number until filename is
+ * unique.
*/
define('FILE_EXISTS_RENAME', 0);
@@ -77,7 +91,8 @@ define('FILE_STATUS_PERMANENT', 1);
* @return A string containing a URL that can be used to download the file.
*/
function file_create_url($path) {
- // Strip file_directory_path from $path. We only include relative paths in urls.
+ // Strip file_directory_path from $path. We only include relative paths in
+ // URLs.
if (strpos($path, file_directory_path() . '/') === 0) {
$path = trim(substr($path, strlen(file_directory_path())), '\\/');
}
@@ -93,28 +108,30 @@ function file_create_url($path) {
* Make sure the destination is a complete path and resides in the file system
* directory, if it is not prepend the file system directory.
*
- * @param $dest A string containing the path to verify. If this value is
+ * @param $destination A string containing the path to verify. If this value is
* omitted, Drupal's 'files' directory will be used.
* @return A string containing the path to file, with file system directory
* appended if necessary, or FALSE if the path is invalid (i.e. outside the
* configured 'files' or temp directories).
*/
-function file_create_path($dest = 0) {
+function file_create_path($destination = NULL) {
$file_path = file_directory_path();
- if (!$dest) {
+ if (!$destination) {
return $file_path;
}
- // file_check_location() checks whether the destination is inside the Drupal files directory.
- if (file_check_location($dest, $file_path)) {
- return $dest;
- }
- // check if the destination is instead inside the Drupal temporary files directory.
- else if (file_check_location($dest, file_directory_temp())) {
- return $dest;
+ // file_check_location() checks whether the destination is inside the Drupal
+ // files directory.
+ if (file_check_location($destination, $file_path)) {
+ return $destination;
+ }
+ // Check if the destination is instead inside the Drupal temporary files
+ // directory.
+ else if (file_check_location($destination, file_directory_temp())) {
+ return $destination;
}
// Not found, try again with prefixed directory path.
- else if (file_check_location($file_path . '/' . $dest, $file_path)) {
- return $file_path . '/' . $dest;
+ else if (file_check_location($file_path . '/' . $destination, $file_path)) {
+ return $file_path . '/' . $destination;
}
// File not found.
return FALSE;
@@ -133,7 +150,7 @@ function file_create_path($dest = 0) {
* work, a form error will be set preventing them from saving the settings.
* @return FALSE when directory not found, or TRUE when directory exists.
*/
-function file_check_directory(&$directory, $mode = 0, $form_item = NULL) {
+function file_check_directory(&$directory, $mode = FALSE, $form_item = NULL) {
$directory = rtrim($directory, '/\\');
// Check if directory exists.
@@ -152,9 +169,13 @@ function file_check_directory(&$director
// Check to see if the directory is writable.
if (!is_writable($directory)) {
- if (($mode & FILE_MODIFY_PERMISSIONS) && !@chmod($directory, 0775)) {
- form_set_error($form_item, t('The directory %directory is not writable', array('%directory' => $directory)));
- watchdog('file system', 'The directory %directory is not writable, because it does not have the correct permissions set.', array('%directory' => $directory), WATCHDOG_ERROR);
+ // If not able to modify permissions, or if able to, but chmod
+ // fails, return false.
+ if (!$mode || (($mode & FILE_MODIFY_PERMISSIONS) && !@chmod($directory, 0775))) {
+ if ($form_item) {
+ form_set_error($form_item, t('The directory %directory is not writable', array('%directory' => $directory)));
+ watchdog('file system', 'The directory %directory is not writable, because it does not have the correct permissions set.', array('%directory' => $directory), WATCHDOG_ERROR);
+ }
return FALSE;
}
}
@@ -202,7 +223,8 @@ function file_check_path(&$path) {
/**
* Check if a file is really located inside $directory. Should be used to make
* sure a file specified is really located within the directory to prevent
- * exploits.
+ * exploits. Note that the file or path being checked does not actually need
+ * to exist yet.
*
* @code
* // Returns FALSE:
@@ -211,7 +233,8 @@ function file_check_path(&$path) {
*
* @param $source A string set to the file to check.
* @param $directory A string where the file should be located.
- * @return FALSE for invalid path or the real path of the source.
+ * @return FALSE if the path does not exist in the directory;
+ * otherwise, the real path of the source.
*/
function file_check_location($source, $directory = '') {
$check = realpath($source);
@@ -219,7 +242,7 @@ function file_check_location($source, $d
$source = $check;
}
else {
- // This file does not yet exist
+ // This file does not yet exist.
$source = realpath(dirname($source)) . '/' . basename($source);
}
$directory = realpath($directory);
@@ -230,88 +253,122 @@ function file_check_location($source, $d
}
/**
- * Copies a file to a new location. This is a powerful function that in many ways
+ * Copy a file to a new location and adds a file record to the database.
+ *
+ * This function should be used when manipulating files that have records
+ * stored in the database. This is a powerful function that in many ways
* performs like an advanced version of copy().
- * - Checks if $source and $dest are valid and readable/writable.
- * - Performs a file copy if $source is not equal to $dest.
- * - If file already exists in $dest either the call will error out, replace the
- * file or rename the file based on the $replace parameter.
- *
- * @param $source A string specifying the file location of the original file.
- * This parameter will contain the resulting destination filename in case of
- * success.
- * @param $dest A string containing the directory $source should be copied to.
- * 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
+ * - 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.
+ * - 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.
+ *
+ * @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.
+ * @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 for success, FALSE for failure.
+ * @return
+ * File object if the copy is successful, or FALSE in the event of an error.
+ *
+ * @see file_copy_plain()
*/
-function file_copy(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
- $dest = file_create_path($dest);
-
- $directory = $dest;
- $basename = file_check_path($directory);
-
- // Make sure we at least have a valid directory.
- if ($basename === FALSE) {
- $source = is_object($source) ? $source->filepath : $source;
- drupal_set_message(t('The selected file %file could not be uploaded, because the destination %directory is not properly configured.', array('%file' => $source, '%directory' => $dest)), 'error');
- watchdog('file system', 'The selected file %file could not be uploaded, because the destination %directory could not be found, or because its permissions do not allow the file to be written.', array('%file' => $source, '%directory' => $dest), WATCHDOG_ERROR);
- return FALSE;
- }
-
- // Process a file upload object.
- if (is_object($source)) {
- $file = $source;
- $source = $file->filepath;
- if (!$basename) {
- $basename = $file->filename;
+function file_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
+ if ($filepath = file_copy_plain($source->filepath, $destination, $replace)) {
+ $file = clone $source;
+ $file->fid = NULL;
+ $file->filename = basename($filepath);
+ $file->filepath = $filepath;
+ if ($file = file_save($file)) {
+ module_invoke_all('file_copy', $file, $source);
+ return $file;
}
}
+ return FALSE;
+}
+/**
+ * Copy a file to a new location without saving a record in the database.
+ *
+ * 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.
+ * - 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 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.
+ * @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
+ * The path to the new file, or FALSE in the event of an error.
+ *
+ * @see file_copy()
+ */
+function file_copy_plain($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
$source = realpath($source);
if (!file_exists($source)) {
- drupal_set_message(t('The selected file %file could not be copied, because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => $source)), 'error');
+ drupal_set_message(t('The specified file %file could not be copied, because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => $source)), 'error');
return FALSE;
}
- // If the destination file is not specified then use the filename of the source file.
- $basename = $basename ? $basename : basename($source);
- $dest = $directory . '/' . $basename;
+ $destination = file_create_path($destination);
+ $directory = $destination;
+ $basename = file_check_path($directory);
- // Make sure source and destination filenames are not the same, makes no sense
- // to copy it if they are. In fact copying the file will most likely result in
- // a 0 byte file. Which is bad. Real bad.
- if ($source != realpath($dest)) {
- if (!$dest = file_destination($dest, $replace)) {
- drupal_set_message(t('The selected file %file could not be copied, because a file by that name already exists in the destination.', array('%file' => $source)), 'error');
- return FALSE;
- }
+ // Make sure we at least have a valid directory.
+ if ($basename === FALSE) {
+ drupal_set_message(t('The specified file %file could not be copied, because the destination %directory is not properly configured.', array('%file' => $source, '%directory' => $destination)), 'error');
+ return FALSE;
+ }
- if (!@copy($source, $dest)) {
- drupal_set_message(t('The selected file %file could not be copied.', array('%file' => $source)), 'error');
- return FALSE;
- }
+ // If the destination file is not specified then use the filename of the
+ // source file.
+ $basename = $basename ? $basename : basename($source);
+ $destination = file_destination($directory . '/' . $basename, $replace);
- // Give everyone read access so that FTP'd users or
- // non-webserver users can see/read these files,
- // and give group write permissions so group members
- // can alter files uploaded by the webserver.
- @chmod($dest, 0664);
+ if ($destination === FALSE) {
+ drupal_set_message(t('The specified file %file could not be copied because a file by that name already exists in the destination.', array('%file' => $source)), 'error');
+ return FALSE;
}
-
- if (isset($file) && is_object($file)) {
- $file->filename = $basename;
- $file->filepath = $dest;
- $source = $file;
+ // Make sure source and destination filenames are not the same, makes no
+ // sense to copy it if they are. In fact copying the file will most likely
+ // result in a 0 byte file. Which is bad. Real bad.
+ if ($source == realpath($destination)) {
+ drupal_set_message(t('The specified file %file was not copied because it would overwrite itself.', array('%file' => $source)), 'error');
+ return FALSE;
}
- else {
- $source = $dest;
+ if (!@copy($source, $destination)) {
+ drupal_set_message(t('The specified file %file could not be copied.', array('%file' => $source)), 'error');
+ return FALSE;
}
- return TRUE; // Everything went ok.
+ // Give everyone read access so that FTP'd users or
+ // non-webserver users can see/read these files,
+ // and give group write permissions so group members
+ // can alter files uploaded by the webserver.
+ @chmod($destination, 0664);
+
+ return $destination;
}
/**
@@ -320,9 +377,9 @@ function file_copy(&$source, $dest = 0,
*
* @param $destination A string specifying the desired path.
* @param $replace Replace behavior when the destination file already exists.
- * - FILE_EXISTS_REPLACE - Replace the existing file
+ * - 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
* FILE_EXISTS_ERROR was specified.
@@ -330,6 +387,10 @@ function file_copy(&$source, $dest = 0,
function file_destination($destination, $replace) {
if (file_exists($destination)) {
switch ($replace) {
+ case FILE_EXISTS_REPLACE:
+ // Do nothing here, we want to overwrite the existing file.
+ break;
+
case FILE_EXISTS_RENAME:
$basename = basename($destination);
$directory = dirname($destination);
@@ -337,7 +398,7 @@ function file_destination($destination,
break;
case FILE_EXISTS_ERROR:
- drupal_set_message(t('The selected file %file could not be copied, because a file by that name already exists in the destination.', array('%file' => $destination)), 'error');
+ drupal_set_message(t('The specified file %file could not be copied, because a file by that name already exists in the destination.', array('%file' => $destination)), 'error');
return FALSE;
}
}
@@ -345,38 +406,74 @@ function file_destination($destination,
}
/**
- * Moves a file to a new location.
- * - Checks if $source and $dest are valid and readable/writable.
- * - Performs a file move if $source is not equal to $dest.
- * - If file already exists in $dest either the call will error out, replace the
- * file or rename the file based on the $replace parameter.
- *
- * @param $source A string specifying the file location of the original file.
- * This parameter will contain the resulting destination filename in case of
- * success.
- * @param $dest A string containing the directory $source should be copied to.
- * 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
+ * Move a file to a new location and update the file's database entry.
+ *
+ * Moving a file is performed by copying the file to the new location and then
+ * deleting the original.
+ * - Checks if $source and $destination are valid and readable/writable.
+ * - Performs a file move if $source is not equal to $destination.
+ * - If file already exists in $destination either the call will error out,
+ * replace the file or rename the file based on the $replace parameter.
+ * - Adds the new file to the files database.
+ *
+ * @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.
+ * @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 for success, FALSE for failure.
+ * @return
+ * Resulting file object for success, or FALSE in the event of an error.
+ *
+ * @see file_move_plain()
*/
-function file_move(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
- $path_original = is_object($source) ? $source->filepath : $source;
-
- if (file_copy($source, $dest, $replace)) {
- $path_current = is_object($source) ? $source->filepath : $source;
-
- if ($path_original == $path_current || file_delete($path_original)) {
- return TRUE;
+function file_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
+ if ($filepath = file_move_plain($source->filepath, $destination, $replace)) {
+ $file = clone $source;
+ $file->filename = basename($filepath);
+ $file->filepath = $filepath;
+ if ($file = file_save($file)) {
+ module_invoke_all('file_move', $file, $source);
+ return $file;
}
- drupal_set_message(t('The removal of the original file %file has failed.', array('%file' => $path_original)), 'error');
+ drupal_set_message(t('The removal of the original file %file has failed.', array('%file' => $source->filepath)), 'error');
}
return FALSE;
}
/**
+ * Move a file to a new location but make no changes to the database.
+ *
+ * @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.
+ * @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
+ * The filepath of the moved file, or FALSE in the event of an error.
+ *
+ * @see file_move()
+ */
+function file_move_plain($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
+ $filepath = file_copy_plain($source, $destination, $replace);
+ if ($filepath == FALSE || file_delete_plain($source) == FALSE) {
+ return FALSE;
+ }
+ return $filepath;
+}
+
+/**
* Munge the filename as needed for security purposes. For instance the file
* name "exploit.php.pps" would become "exploit.php_.pps".
*
@@ -438,9 +535,9 @@ function file_unmunge_filename($filename
* @return
*/
function file_create_filename($basename, $directory) {
- $dest = $directory . '/' . $basename;
+ $destination = $directory . '/' . $basename;
- if (file_exists($dest)) {
+ if (file_exists($destination)) {
// Destination file already exists, generate an alternative.
if ($pos = strrpos($basename, '.')) {
$name = substr($basename, 0, $pos);
@@ -452,45 +549,106 @@ function file_create_filename($basename,
$counter = 0;
do {
- $dest = $directory . '/' . $name . '_' . $counter++ . $ext;
- } while (file_exists($dest));
+ $destination = $directory . '/' . $name . '_' . $counter++ . $ext;
+ } while (file_exists($destination));
}
- return $dest;
+ return $destination;
+}
+
+/**
+ * Delete a file and its database record.
+ *
+ * @param $path
+ * A file object.
+ * @param $force
+ * Boolean indicating that the file should be deleted even if
+ * hook_file_references() reports that the file is in use.
+ * @return mixed
+ * TRUE for success, Array for reference count block, or FALSE in the event
+ * of an error.
+ *
+ * @see hook_file_references()
+ * @see file_delete_plain()
+ */
+function file_delete($file, $force = FALSE) {
+ // If any module returns a value from the reference hook, the
+ // file will not be deleted from Drupal, but file_delete will
+ // return a populated array that tests as TRUE.
+ if (!$force && ($references = module_invoke_all('file_references', $file))) {
+ return $references;
+ }
+
+ // Let other modules clean up on delete.
+ module_invoke_all('file_delete', $file);
+
+ // Make sure the file is deleted before removing its row from the
+ // database, so UIs can still find the file in the database.
+ if (file_delete_plain($file->filepath)) {
+ db_query('DELETE FROM {files} WHERE fid = %d', array($file->fid));
+ return TRUE;
+ }
+ return FALSE;
}
/**
* Delete a file.
*
- * @param $path A string containing a file path.
- * @return TRUE for success, FALSE for failure.
+ * This function should be used when the file to be deleted does not have an
+ * entry recorded in the files table.
+ *
+ * @param $path
+ * A string containing a file path.
+ * @return
+ * TRUE for success or path does not exist, or FALSE in the event of an
+ * error.
+ *
+ * @see file_delete()
*/
-function file_delete($path) {
+function file_delete_plain($path) {
+ if (is_dir($path)) {
+ watchdog('file', t('%path is a directory and cannot be removed with file_delete_plain.', array('%path' => $path)), WATCHDOG_ERROR);
+ return FALSE;
+ }
if (is_file($path)) {
return unlink($path);
}
+ // Return TRUE for non-existant file, but log that nothing was actually
+ // deleted, as the intended result of file_delete_plain is in fact the
+ // current state.
+ if (!file_exists($path)) {
+ watchdog('file', t('The file %path was not deleted, because it does not exist.', array('%path' => $path)), WATCHDOG_NOTICE);
+ return TRUE;
+ }
+ // Catch all for everything else: sockets, symbolic links, etc.
+ return FALSE;
}
/**
* Determine total disk space used by a single user or the whole filesystem.
*
* @param $uid
- * An optional user id. A NULL value returns the total space used
- * by all files.
+ * Optional. A user id, specifying NULL returns the total space used by all
+ * non-temporary files.
+ * @param $status
+ * Optional. File Status to return. Combine with a bitwise OR(|) to return
+ * multiple statuses. The default status is FILE_STATUS_PERMANENT.
+ * @return
+ * An integer containing the number of bytes used.
*/
-function file_space_used($uid = NULL) {
+function file_space_used($uid = NULL, $status = FILE_STATUS_PERMANENT) {
if (isset($uid)) {
- return (int) db_result(db_query('SELECT SUM(filesize) FROM {files} WHERE uid = %d', $uid));
+ return (int)db_result(db_query('SELECT SUM(filesize) FROM {files} WHERE uid = %d AND status & %d', array($uid, $status)));
}
- return (int) db_result(db_query('SELECT SUM(filesize) FROM {files}'));
+ return (int)db_result(db_query('SELECT SUM(filesize) FROM {files} WHERE status & %d', array($status)));
}
/**
* Saves a file upload to a new location. The source file is validated as a
* proper upload and handled as such.
*
- * The file will be added to the files table as a temporary file. Temporary files
- * are periodically cleaned. To make the file permanent file call
+ * The file will be added to the files table as a temporary file. Temporary
+ * files are periodically cleaned. To make the file permanent file call
* file_set_status() to change its status.
*
* @param $source
@@ -502,7 +660,7 @@ function file_space_used($uid = NULL) {
* functions should return an array of error messages, an empty array
* indicates that the file passed validation. The functions will be called in
* the order specified.
- * @param $dest
+ * @param $destination
* A string containing the directory $source should be copied to. If this is
* not provided or is not writable, the temporary directory will be used.
* @param $replace
@@ -510,25 +668,27 @@ function file_space_used($uid = NULL) {
* destination directory should overwritten. A false value will generate a
* new, unique filename in the destination directory.
* @return
- * An object containing the file information, or FALSE in the event of an error.
+ * An object containing the file information, or FALSE in the event of an
+ * error.
*/
-function file_save_upload($source, $validators = array(), $dest = FALSE, $replace = FILE_EXISTS_RENAME) {
+function file_save_upload($source, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME) {
global $user;
static $upload_cache;
- // Add in our check of the the file name length.
- $validators['file_validate_name_length'] = array();
-
// Return cached objects without processing since the file will have
// already been processed and the paths in _FILES will be invalid.
if (isset($upload_cache[$source])) {
return $upload_cache[$source];
}
+ // Add in our check of the the file name length.
+ $validators['file_validate_name_length'] = array();
+
+
// If a file was uploaded, process it.
if (isset($_FILES['files']) && $_FILES['files']['name'][$source] && is_uploaded_file($_FILES['files']['tmp_name'][$source])) {
- // Check for file upload errors and return FALSE if a
- // lower level system error occurred.
+ // Check for file upload errors and return FALSE if a lower level system
+ // error occurred.
switch ($_FILES['files']['error'][$source]) {
// @see http://php.net/manual/en/features.file-upload.errors.php
case UPLOAD_ERR_OK:
@@ -560,9 +720,12 @@ function file_save_upload($source, $vali
// Begin building file object.
$file = new stdClass();
+ $file->uid = $user->uid;
+ $file->status = FILE_STATUS_TEMPORARY;
$file->filename = file_munge_filename(trim(basename($_FILES['files']['name'][$source]), '.'), $extensions);
$file->filepath = $_FILES['files']['tmp_name'][$source];
$file->filemime = file_get_mimetype($file->filename);
+ $file->filesize = $_FILES['files']['size'][$source];
// Rename potentially executable files, to help prevent exploits.
if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
@@ -573,26 +736,21 @@ function file_save_upload($source, $vali
// If the destination is not provided, or is not writable, then use the
// temporary directory.
- if (empty($dest) || file_check_path($dest) === FALSE) {
- $dest = file_directory_temp();
+ if (empty($destination) || file_check_path($destination) === FALSE) {
+ $destination = file_directory_temp();
}
$file->source = $source;
- $file->destination = file_destination(file_create_path($dest . '/' . $file->filename), $replace);
- $file->filesize = $_FILES['files']['size'][$source];
+ $file->destination = file_destination(file_create_path($destination . '/' . $file->filename), $replace);
- // Call the validation functions.
- $errors = array();
- foreach ($validators as $function => $args) {
- array_unshift($args, $file);
- $errors = array_merge($errors, call_user_func_array($function, $args));
- }
+ // Call the validation functions specified by this function's caller.
+ $errors = file_validate($file, $validators);
- // Check for validation errors.
+ // Check for errors.
if (!empty($errors)) {
- $message = t('The selected file %name could not be uploaded.', array('%name' => $file->filename));
+ $message = t('The specified file %name could not be uploaded.', array('%name' => $file->filename));
if (count($errors) > 1) {
- $message .= '
- ' . implode('
- ', $errors) . '
';
+ $message .= theme('item_list', $errors);
}
else {
$message .= ' ' . array_pop($errors);
@@ -601,8 +759,9 @@ function file_save_upload($source, $vali
return FALSE;
}
- // Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary directory.
- // This overcomes open_basedir restrictions for future file operations.
+ // Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary
+ // directory. This overcomes open_basedir restrictions for future file
+ // operations.
$file->filepath = $file->destination;
if (!move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->filepath)) {
form_set_error($source, t('File upload error. Could not move uploaded file.'));
@@ -610,15 +769,11 @@ function file_save_upload($source, $vali
return FALSE;
}
- // If we made it this far it's safe to record this file in the database.
- $file->uid = $user->uid;
- $file->status = FILE_STATUS_TEMPORARY;
- $file->timestamp = $_SERVER['REQUEST_TIME'];
- drupal_write_record('files', $file);
-
- // Add file to the cache.
- $upload_cache[$source] = $file;
- return $file;
+ if ($file = file_save($file)) {
+ // Add file to the cache.
+ $upload_cache[$source] = $file;
+ return $file;
+ }
}
return FALSE;
}
@@ -634,6 +789,9 @@ function file_save_upload($source, $vali
function file_validate_name_length($file) {
$errors = array();
+ if (empty($file->filename)) {
+ $errors[] = t('Its name is empty. Please give a name to the file.');
+ }
if (strlen($file->filename) > 255) {
$errors[] = t('Its name exceeds the 255 characters limit. Please rename the file and try again.');
}
@@ -641,27 +799,24 @@ function file_validate_name_length($file
}
/**
- * Check that the filename ends with an allowed extension. This check is not
- * enforced for the user #1.
+ * Check that the filename ends with an allowed extension.
*
* @param $file
* A Drupal file object.
* @param $extensions
* A string with a space separated
* @return
- * An array. If the file extension is not allowed, it will contain an error message.
+ * An array. If the file extension is not allowed, it will contain an error
+ * message.
*/
function file_validate_extensions($file, $extensions) {
global $user;
$errors = array();
- // Bypass validation for uid = 1.
- if ($user->uid != 1) {
- $regex = '/\.(' . preg_replace('/ +/', '|', preg_quote($extensions)) . ')$/i';
- if (!preg_match($regex, $file->filename)) {
- $errors[] = t('Only files with the following extensions are allowed: %files-allowed.', array('%files-allowed' => $extensions));
- }
+ $regex = '/\.(' . preg_replace('/ +/', '|', preg_quote($extensions)) . ')$/i';
+ if (!preg_match($regex, $file->filename)) {
+ $errors[] = t('Only files with the following extensions are allowed: %files-allowed.', array('%files-allowed' => $extensions));
}
return $errors;
}
@@ -676,10 +831,11 @@ function file_validate_extensions($file,
* An integer specifying the maximum file size in bytes. Zero indicates that
* no limit should be enforced.
* @param $$user_limit
- * An integer specifying the maximum number of bytes the user is allowed. Zero
- * indicates that no limit should be enforced.
+ * An integer specifying the maximum number of bytes the user is allowed.
+ * Zero indicates that no limit should be enforced.
* @return
- * An array. If the file size exceeds limits, it will contain an error message.
+ * An array. If the file size exceeds limits, it will contain an error
+ * message.
*/
function file_validate_size($file, $file_limit = 0, $user_limit = 0) {
global $user;
@@ -724,15 +880,16 @@ function file_validate_is_image(&$file)
* maximum and minimum dimensions. Non-image files will be ignored.
*
* @param $file
- * A Drupal file object. This function may resize the file affecting its size.
+ * A Drupal file object. This function may resize the file affecting its
+ * size.
* @param $maximum_dimensions
* An optional string in the form WIDTHxHEIGHT e.g. '640x480' or '85x85'. If
* an image toolkit is installed the image will be resized down to these
* dimensions. A value of 0 indicates no restriction on size, so resizing
* will be attempted.
* @param $minimum_dimensions
- * An optional string in the form WIDTHxHEIGHT. This will check that the image
- * meets a minimum size. A value of 0 indicates no restriction.
+ * An optional string in the form WIDTHxHEIGHT. This will check that the
+ * image meets a minimum size. A value of 0 indicates no restriction.
* @return
* An array. If the file is an image and did not meet the requirements, it
* will contain an error message.
@@ -774,47 +931,98 @@ function file_validate_image_resolution(
}
/**
- * Save a string to the specified destination.
+ * Save a string to the specified destination and create a database file entry.
*
- * @param $data A string containing the contents of the file.
- * @param $dest A string containing the destination location.
- * @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
+ * @param $data
+ * A string containing the contents of the file.
+ * @param $destination
+ * A string containing the destination location. If no value is provided
+ * then a randomly name will be generated and the file saved in Drupal's
+ * files directory.
+ * @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
+ * A string containing the resulting filename or FALSE on error
*
- * @return A string containing the resulting filename or FALSE on error
+ * @see file_save_data_plain()
*/
-function file_save_data($data, $dest, $replace = FILE_EXISTS_RENAME) {
- $temp = file_directory_temp();
- // On Windows, tempnam() requires an absolute path, so we use realpath().
- $file = tempnam(realpath($temp), 'file');
- if (!$fp = fopen($file, 'wb')) {
- drupal_set_message(t('The file could not be created.'), 'error');
- return FALSE;
+function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
+ global $user;
+
+ if ($filepath = file_save_data_plain($data, $destination, $replace)) {
+ // Create a file object.
+ $file = new stdClass();
+ $file->filepath = $filepath;
+ $file->filename = basename($file->filepath);
+ $file->filemime = file_get_mimetype($file->filepath);
+ $file->uid = $user->uid;
+ $file->status = FILE_STATUS_PERMANENT;
+ return file_save($file);
}
- fwrite($fp, $data);
- fclose($fp);
+ return FALSE;
+}
- if (!file_move($file, $dest, $replace)) {
+/**
+ * Save a string to the specified destination.
+ *
+ * This function is identical to file_save_data() except the file will not be
+ * saved to the files table.
+ *
+ * @param $data
+ * A string containing the contents of the file.
+ * @param $destination
+ * A string containing the destination location. If no value is provided
+ * then a randomly name will be generated and the file saved in Drupal's
+ * files directory.
+ * @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
+ * A string with the path of the resulting file, or FALSE on error.
+ *
+ * @see file_save_data()
+ */
+function file_save_data_plain($data, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
+ global $user;
+
+ // Write the data to a temporary file.
+ $temp_name = tempnam(file_directory_temp(), 'file');
+ if (file_put_contents($temp_name, $data) === FALSE) {
+ drupal_set_message(t('The file could not be created.'), 'error');
return FALSE;
}
- return $file;
+ // Move the file to its final destination.
+ return file_move_plain($temp_name, $destination, $replace);
}
/**
* Set the status of a file.
*
- * @param file A Drupal file object
- * @param status A status value to set the file to.
- * @return FALSE on failure, TRUE on success and $file->status will contain the
- * status.
+ * @param $file
+ * A Drupal file object.
+ * @param $status
+ * A status value to set the file to.
+ * - FILE_STATUS_TEMPORARY - A temporary file that Drupal's garbage
+ * collection will remove.
+ * - FILE_STATUS_PERMANENT - A permanent file that Drupal's garbage
+ * collection will not remove.
+ * @return
+ * File object if the change is successful, or FALSE in the event of an
+ * error.
*/
-function file_set_status(&$file, $status) {
- if (db_query('UPDATE {files} SET status = %d WHERE fid = %d', $status, $file->fid)) {
+function file_set_status($file, $status = FILE_STATUS_PERMANENT) {
+ if (db_query('UPDATE {files} SET status = %d WHERE fid = %d', array($status, $file->fid))) {
$file->status = $status;
- return TRUE;
+ module_invoke_all('file_status', $file);
+ return $file;
}
return FALSE;
}
@@ -823,8 +1031,10 @@ function file_set_status(&$file, $status
* Transfer file using http to client. Pipes a file through Drupal to the
* client.
*
- * @param $source File to transfer.
- * @param $headers An array of http headers to send along with file.
+ * @param $source
+ * String specifying the file path to transfer.
+ * @param $headers
+ * An array of http headers to send along with file.
*/
function file_transfer($source, $headers) {
ob_end_clean();
@@ -907,7 +1117,8 @@ function file_download() {
* @param $min_depth
* Minimum depth of directories to return files from.
* @param $depth
- * Current depth of recursion. This parameter is only used internally and should not be passed.
+ * Current depth of recursion. This parameter is only used internally and
+ * should not be passed.
*
* @return
* An associative array (keyed on the provided key) of objects with
@@ -926,7 +1137,8 @@ function file_scan_directory($dir, $mask
$files = array_merge(file_scan_directory("$dir/$file", $mask, $nomask, $callback, $recurse, $key, $min_depth, $depth + 1), $files);
}
elseif ($depth >= $min_depth && ereg($mask, $file)) {
- // Always use this match over anything already set in $files with the same $$key.
+ // Always use this match over anything already set in $files with the
+ // same $$key.
$filename = "$dir/$file";
$basename = basename($file);
$name = substr($basename, 0, strrpos($basename, '.'));
@@ -965,13 +1177,11 @@ function file_directory_temp() {
// Operating system specific dirs.
if (substr(PHP_OS, 0, 3) == 'WIN') {
- $directories[] = 'c:\\windows\\temp';
- $directories[] = 'c:\\winnt\\temp';
- $path_delimiter = '\\';
+ $directories[] = 'c:/windows/temp';
+ $directories[] = 'c:/winnt/temp';
}
else {
$directories[] = '/tmp';
- $path_delimiter = '/';
}
foreach ($directories as $directory) {
@@ -980,8 +1190,8 @@ function file_directory_temp() {
}
}
- // if a directory has been found, use it, otherwise default to 'files/tmp' or 'files\\tmp';
- $temporary_directory = $temporary_directory ? $temporary_directory : file_directory_path() . $path_delimiter . 'tmp';
+ // if a directory has been found, use it, otherwise default to 'files/tmp'
+ $temporary_directory = $temporary_directory ? $temporary_directory : file_directory_path() . '/tmp';
variable_set('file_directory_temp', $temporary_directory);
}
@@ -1001,7 +1211,8 @@ function file_directory_path() {
* Determine the maximum file upload size by querying the PHP settings.
*
* @return
- * A file size limit in bytes based on the PHP upload_max_filesize and post_max_size
+ * A file size limit in bytes based on the PHP upload_max_filesize and
+ * post_max_size
*/
function file_upload_max_size() {
static $max_size = -1;
@@ -1387,5 +1598,108 @@ function file_get_mimetype($filename, $m
}
/**
+ * Load a file object from the database.
+ *
+ * @param $param
+ * Either the id of a file or an array of conditions to match against in the
+ * database query
+ * @param $reset
+ * Whether to reset the internal file_load cache.
+ * @return
+ * A file object.
+ */
+function file_load($param, $reset = NULL) {
+ static $files = array();
+
+ if ($reset) {
+ $files = array();
+ }
+
+ $arguments = array();
+ if (is_numeric($param)) {
+ if (isset($files[(string) $param])) {
+ return is_object($files[$param]) ? clone $files[$param] : $files[$param];
+ }
+ $cond = 'f.fid = %d';
+ $arguments[] = $param;
+ }
+ elseif (is_array($param)) {
+ // Turn the conditions into a query.
+ $cond = array();
+ foreach ($param as $key => $value) {
+ $cond[] = 'f.' . db_escape_table($key) . " = '%s'";
+ $arguments[] = $value;
+ }
+ $cond = implode(' AND ', $cond);
+ }
+ else {
+ return FALSE;
+ }
+ $file = db_fetch_object(db_query('SELECT f.* FROM {files} f WHERE ' . $cond, $arguments));
+
+ if ($file && $file->fid) {
+ module_invoke_all('file_load', $file);
+
+ // Cache the fully loaded value.
+ $files[(string) $file->fid] = clone $file;
+ }
+
+ return $file;
+}
+
+/**
+ * Check that a file meets the criteria specified by the validators.
+ *
+ * @param $file
+ * A Drupal file object.
+ * @param $validators
+ * An optional, associative array of callback functions used to validate the
+ * file. The keys are function names and the values arrays of callback
+ * parameters which will be passed in after the user and file objects. The
+ * functions should return an array of error messages, an empty array
+ * indicates that the file passed validation. The functions will be called in
+ * the order specified.
+ * @return
+ * An array contaning validation error messages.
+ */
+function file_validate(&$file, $validators = array()) {
+ // Call the validation functions specified by this function's caller.
+ $errors = array();
+ foreach ($validators as $function => $args) {
+ array_unshift($args, $file);
+ $errors = array_merge($errors, call_user_func_array($function, $args));
+ }
+
+ // Let other modules perform validation on the new file.
+ return array_merge($errors, module_invoke_all('file_validate', $file));
+}
+/**
+ * Save a file object to the database.
+ *
+ * If the $file->fid is not set a new record will be added. Re-saving an
+ * existing file will not change its status.
+ *
+ * @param $file
+ * A file object returned by file_load().
+ * @return
+ * The updated file object.
+ */
+function file_save($file) {
+ $file->timestamp = $_SERVER['REQUEST_TIME'];
+ $file->filesize = filesize($file->filepath);
+
+ if (empty($file->fid)) {
+ drupal_write_record('files', $file);
+ module_invoke_all('file_insert', $file);
+ }
+ else {
+ drupal_write_record('files', $file, 'fid');
+ module_invoke_all('file_update', $file);
+ }
+
+ return $file;
+}
+
+/**
* @} End of "defgroup file".
*/
Index: modules/blogapi/blogapi.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/blogapi/blogapi.module,v
retrieving revision 1.123
diff -u -p -r1.123 blogapi.module
--- modules/blogapi/blogapi.module 6 Sep 2008 08:36:19 -0000 1.123
+++ modules/blogapi/blogapi.module 7 Sep 2008 00:09:47 -0000
@@ -385,12 +385,12 @@ function blogapi_metaweblog_new_media_ob
return blogapi_error(t('No file sent.'));
}
- if (!$file = file_save_data($data, $name)) {
+ if (!$filepath = file_save_data_plain($data, $name)) {
return blogapi_error(t('Error storing file.'));
}
// Return the successful result.
- return array('url' => file_create_url($file), 'struct');
+ return array('url' => file_create_url($filepath), 'struct');
}
/**
* Blogging API callback. Returns a list of the taxonomy terms that can be
Index: modules/color/color.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/color/color.module,v
retrieving revision 1.43
diff -u -p -r1.43 color.module
--- modules/color/color.module 31 Aug 2008 09:15:12 -0000 1.43
+++ modules/color/color.module 7 Sep 2008 00:09:47 -0000
@@ -308,7 +308,7 @@ function color_scheme_form_submit($form,
foreach ($info['copy'] as $file) {
$base = basename($file);
$source = $paths['source'] . $file;
- file_copy($source, $paths['target'] . $base);
+ file_copy_plain($source, $paths['target'] . $base);
$paths['map'][$file] = $base;
$paths['files'][] = $paths['target'] . $base;
}
Index: modules/simpletest/simpletest.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.install,v
retrieving revision 1.7
diff -u -p -r1.7 simpletest.install
--- modules/simpletest/simpletest.install 16 Aug 2008 20:57:14 -0000 1.7
+++ modules/simpletest/simpletest.install 7 Sep 2008 00:09:47 -0000
@@ -33,7 +33,7 @@ function simpletest_install() {
$original = drupal_get_path('module', 'simpletest') . '/files';
$files = file_scan_directory($original, '(html|image|javascript|php|sql)-.*');
foreach ($files as $file) {
- file_copy($file->filename, $path . '/' . $file->basename);
+ file_copy_plain($file->filename, $path . '/' . $file->basename);
}
$generated = TRUE;
}
Index: modules/simpletest/simpletest.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.module,v
retrieving revision 1.11
diff -u -p -r1.11 simpletest.module
--- modules/simpletest/simpletest.module 21 Aug 2008 19:36:38 -0000 1.11
+++ modules/simpletest/simpletest.module 7 Sep 2008 00:09:47 -0000
@@ -558,7 +558,7 @@ function simpletest_clean_temporary_dire
simpletest_clean_temporary_directory($file_path);
}
else {
- file_delete($file_path);
+ file_delete_plain($file_path);
}
}
}
Index: modules/simpletest/tests/file.test
===================================================================
RCS file: modules/simpletest/tests/file.test
diff -N modules/simpletest/tests/file.test
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/file.test 7 Sep 2008 00:09:48 -0000
@@ -0,0 +1,770 @@
+ t('File validation'),
+ 'description' => t('Tests the functions used to validate uploaded files.'),
+ 'group' => t('File'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('file_test');
+
+ $this->image = new stdClass();
+ $this->image->filepath = 'misc/druplicon.png';
+ $this->iamge->filename = basename($this->image->filepath);
+
+ $this->non_image = new stdClass();
+ $this->non_image->filepath = 'misc/jquery.js';
+ $this->non_image->filename = basename($this->non_image->filepath);
+ }
+
+ function testFileValidate() {
+ // Empty validators
+ $this->assertEqual(file_validate($this->image, array()), array(), t('Validating an empty array works succesfully.'));
+
+ // Use the file_test.module's test validator to ensure that passing tests
+ // return correctly.
+ $passing = array('file_test_validator' => array(array()));
+ $this->assertEqual(file_validate($this->image, $passing), array(), t('Validating passes.'));
+
+ $failing = array('file_test_validator' => array(array('Failed', 'Badly')));
+ $this->assertEqual(file_validate($this->image, $failing), array('Failed', 'Badly'), t('Validating returns errors.'));
+ }
+
+ /**
+ * Test the file_validate_extensions() function.
+ */
+ function testFileValidateExtensions() {
+ $file = new stdClass();
+ $file->filename = 'asdf.txt';
+ $errors = file_validate_extensions($file, 'asdf txt pork');
+ $this->assertEqual(count($errors), 0, t("Valid extension accepted."), 'File');
+
+ $file->filename = 'asdf.txt';
+ $errors = file_validate_extensions($file, 'exe png');
+ $this->assertEqual(count($errors), 1, t("Invalid extension blocked."), 'File');
+ }
+
+ /**
+ * This ensures a specific file is actually an image.
+ */
+ function testFileValidateIsImage() {
+ $this->assertTrue(file_exists($this->image->filepath), t('The image being tested exists.'), 'File');
+ $errors = file_validate_is_image($this->image);
+ $this->assertEqual(count($errors), 0, t("No error reported for our image file."), 'File');
+
+ $this->assertTrue(file_exists($this->non_image->filepath), t('The non-image being tested exists.'), 'File');
+ $errors = file_validate_is_image($this->non_image);
+ $this->assertEqual(count($errors), 1, t("An error reported for our non-image file."), 'File');
+ }
+
+ /**
+ * This ensures the resolution of a specific file is within bounds.
+ * The image will be resized if it's too large.
+ */
+ function testFileValidateImageResolution() {
+ // Non-images
+ $errors = file_validate_image_resolution($this->non_image);
+ $this->assertEqual(count($errors), 0, t("Shouldn't get any errors for a non-image file."), 'File');
+ $errors = file_validate_image_resolution($this->non_image, '50x50', '100x100');
+ $this->assertEqual(count($errors), 0, t("Don't check the resolution on non files."), 'File');
+
+ // Minimum size
+ $errors = file_validate_image_resolution($this->image);
+ $this->assertEqual(count($errors), 0, t("No errors for an image when there is no minimum or maximum resolution."), 'File');
+ $errors = file_validate_image_resolution($this->image, 0, '200x1');
+ $this->assertEqual(count($errors), 1, t("Got an error for an image that wasn't wide enough"), 'File');
+ $errors = file_validate_image_resolution($this->image, 0, '1x200');
+ $this->assertEqual(count($errors), 1, t("Got an error for an image that wasn't tall enough"), 'File');
+ $errors = file_validate_image_resolution($this->image, 0, '200x200');
+ $this->assertEqual(count($errors), 1, t("Small images report an error."), 'File');
+
+ // Maximum size
+ if (image_get_toolkit()) {
+ // Copy the image so that the original doesn't get resized.
+ $temp_dir = file_directory_temp();
+ copy(realpath('misc/druplicon.png'), realpath($temp_dir) .'/druplicon.png');
+ $this->image->filepath = $temp_dir .'/druplicon.png';
+
+ $errors = file_validate_image_resolution($this->image, '10x5');
+ $this->assertEqual(count($errors), 0, t("No errors should be reported when an oversized image can be scaled down."), 'File');
+
+ $info = image_get_info($this->image->filepath);
+ $this->assertTrue($info['width'] <= 10, t("Image scaled to correct width."), 'File');
+ $this->assertTrue($info['height'] <= 5, t("Image scaled to correct height."), 'File');
+
+ unlink(realpath($temp_dir .'/druplicon.png'));
+ }
+ else {
+ // TODO: should check that the error is returned if no toolkit is available.
+ $errors = file_validate_image_resolution($this->image, '5x10');
+ $this->assertEqual(count($errors), 1, t("Oversize images that can't be scaled get an error."), 'File');
+ }
+
+ // Clear out any resizing messages.
+# drupal_get_messages();
+ }
+
+ /**
+ * This will ensure the filename length is valid.
+ */
+ function testFileValidateNameLength() {
+ // Create a new file object.
+ $file = new stdClass();
+
+ // Add a filename with an allowed length and test it.
+ $file->filename = str_repeat('x', 255);
+ $this->assertEqual(strlen($file->filename), 255);
+ $errors = file_validate_name_length($file);
+ $this->assertEqual(count($errors), 0, t('No errors reported for 255 length filename.'), 'File');
+
+ // Add a filename with a length too long and test it.
+ $file->filename = str_repeat('x', 256);
+ $errors = file_validate_name_length($file);
+ $this->assertEqual(count($errors), 1, t('An error reported for 256 length filename.'), 'File');
+
+ // Add a filename with an empty string and test it.
+ $file->filename = '';
+ $errors = file_validate_name_length($file);
+ $this->assertEqual(count($errors), 1, t('An error reported for 0 length filename.'), 'File');
+ }
+
+
+ /**
+ * Test file_validate_size().
+ */
+ function testFileValidateSize() {
+ global $user;
+ $original_user = $user;
+ session_save_session(FALSE);
+
+ // Run these test as uid = 1
+ $user = user_load(array('uid' => 1));
+
+ $file = new stdClass();
+ $file->filesize = 999999;
+ $errors = file_validate_size($file, 1, 1);
+ $this->assertEqual(count($errors), 0, t("No size limits enforced on uid=1."), 'File');
+
+
+ // Run these test as a regular user
+ $user = $this->drupalCreateUser();
+
+ $file = new stdClass();
+ $file->filesize = 1000;
+ $errors = file_validate_size($file, 0, 0);
+ $this->assertEqual(count($errors), 0, t("No limits means no errors."), 'File');
+ $errors = file_validate_size($file, 1, 0);
+ $this->assertEqual(count($errors), 1, t("Error for the file being over the limit."), 'File');
+ $errors = file_validate_size($file, 0, 1);
+ $this->assertEqual(count($errors), 1, t("Error for the user being over their limit."), 'File');
+ $errors = file_validate_size($file, 1, 1);
+ $this->assertEqual(count($errors), 2, t("Errors for both the file and their limit."), 'File');
+
+
+ $user = $original_user;
+ session_save_session(TRUE);
+ }
+}
+
+
+/**
+ * This will run tests against file validation.
+ *
+ */
+class FileLoadSaveTest extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('File loading and saving'),
+ 'description' => t('Tests the file save process, by creating a new text file, and moving and copying an image file.'),
+ 'group' => t('File'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('file_test');
+ }
+
+ /**
+ * This will test saving file data to the database.
+ */
+ function testFileLoadSave() {
+ // Create a new file object.
+ $file = array(
+ 'uid' => 1,
+ 'filename' => 'druplicon.png',
+ 'filepath' => 'misc/druplicon.png',
+ 'filemime' => 'image/png',
+ 'timestamp' => 1,
+ 'status' => FILE_STATUS_PERMANENT,
+ );
+ $this->file = (object) $file;
+
+ // Try to load bogus stuff
+ file_test_reset_calls();
+ $this->assertFalse(file_load(-1), t("Try to load an invalid fid"));
+ $this->assertEqual(count(file_test_get_calls('load')), 0, t('hook_file_load was not called.'));
+ file_test_reset_calls();
+ $this->assertFalse(file_load(array('filepath' => $this->file->filepath)), t("Try to load a file that doesn't exist in the database."));
+ $this->assertEqual(count(file_test_get_calls('load')), 0, t('hook_file_load was not called.'));
+
+ // Save it, inserting a new record
+ file_test_reset_calls();
+ $saved_file = file_save($this->file);
+ $this->assertEqual(count(file_test_get_calls('insert')), 1, t('hook_file_insert was called.'));
+ $this->assertNotNull($saved_file, t("Saving the file should give us back a file object."), 'File');
+ $this->assertTrue($saved_file->fid > 0, t("A new file ID is set when saving a new file to the database."), 'File');
+ $this->assertEqual(db_result(db_query('SELECT COUNT(*) FROM {files} f WHERE f.fid = %d', array($saved_file->fid))), 1, t("Record exists in the database."));
+ $this->assertEqual($saved_file->filesize, filesize($this->file->filepath), t("File size was set correctly."), 'File');
+ $this->assertTrue($saved_file->timestamp > 1, t("File size was set correctly."), 'File');
+
+ // Load by path
+ file_test_reset_calls();
+ $by_path_file = file_load(array('filepath' => $this->file->filepath));
+ $this->assertEqual(count(file_test_get_calls('load')), 1, t('hook_file_load was called.'));
+ $this->assertEqual($by_path_file->fid, $this->file->fid, t("Loading by filepath got the correct fid."), 'File');
+
+ // Load by fid.
+ file_test_reset_calls();
+ $by_fid_file = file_load($this->file->fid);
+ $this->assertEqual(count(file_test_get_calls('load')), 0, t('hook_file_load was not called because the loaded file was cached.'));
+ $this->assertEqual($by_fid_file->filepath, $this->file->filepath, t("Loading by fid got the correct filepath."), 'File');
+
+ // Load again by fid to make sure the caching doesn't screw anythign up
+ file_test_reset_calls();
+ $by_fid_file = file_load($this->file->fid);
+ $this->assertEqual(count(file_test_get_calls('load')), 0, t('hook_file_load was not called since it loaded from cache.'));
+ $this->assertEqual($by_fid_file->filepath, $this->file->filepath, t("Loading by fid got the correct filepath."), 'File');
+
+ // Resave the file, updating the existing record.
+ file_test_reset_calls();
+ $resaved_file = file_save($saved_file);
+ $this->assertEqual(count(file_test_get_calls('update')), 1, t('hook_file_update was called.'));
+ $this->assertEqual($resaved_file->fid, $saved_file->fid, t("The file ID of an existing file is not changed when updating the database."), 'File');
+ $this->assertTrue($resaved_file->timestamp >= $saved_file->timestamp, t("Timestamp didn't go backwards."), 'File');
+ $count = db_result(db_query('SELECT COUNT(*) FROM {files} f WHERE f.fid = %d', array($saved_file->fid)));
+ $this->assertEqual($count, 1, t("Record still exists in the database."), 'File');
+
+ // TODO: test the reset parameter
+ }
+
+ function testFileSaveDataPlain() {
+ $contents = $this->randomName(8);
+
+ // No filename
+ $filepath = file_save_data_plain($contents);
+ $this->assertTrue($filepath, t("Unnamed file saved correctly"));
+ $this->assertEqual(file_directory_path(), dirname($filepath), t("File was placed in Drupal's files directory"));
+ $this->assertEqual($contents, file_get_contents(realpath($filepath)), t("Contents of the file are correct."));
+
+ // Provide a filename
+ $filepath = file_save_data_plain($contents, 'asdf.txt', FILE_EXISTS_REPLACE);
+ $this->assertTrue($filepath, t("Unnamed file saved correctly"));
+ $this->assertEqual(file_directory_path(), dirname($filepath), t("File was placed in Drupal's files directory."));
+ $this->assertEqual('asdf.txt', basename($filepath), t("File was named correctly."));
+ $this->assertEqual($contents, file_get_contents(realpath($filepath)), t("Contents of the file are correct."));
+ }
+
+ function testFileSaveData() {
+ $contents = $this->randomName(8);
+
+ // No filename
+ $file = file_save_data($contents);
+ $this->assertTrue($file, t("Unnamed file saved correctly"));
+ $this->assertEqual(file_directory_path(), dirname($file->filepath), t("File was placed in Drupal's files directory"));
+ $this->assertEqual($contents, file_get_contents(realpath($file->filepath)), t("Contents of the file are correct."));
+ $this->assertEqual($file->filemime, 'application/octet-stream', t("A MIME type was set."));
+ $this->assertEqual($file->status, FILE_STATUS_PERMANENT, t("The file's status was set to permanent."));
+
+ // Try loading the file.
+ $loaded_file = file_load($file->fid);
+ $this->assertTrue($loaded_file, t("File loaded from database."));
+
+ // Provide a filename
+ $file = file_save_data($contents, 'asdf.txt', FILE_EXISTS_REPLACE);
+ $this->assertTrue($file, t("Unnamed file saved correctly"));
+ $this->assertEqual(file_directory_path(), dirname($file->filepath), t("File was placed in Drupal's files directory."));
+ $this->assertEqual('asdf.txt', basename($file->filepath), t("File was named correctly."));
+ $this->assertEqual($contents, file_get_contents(realpath($file->filepath)), t("Contents of the file are correct."));
+
+ // Check the overwrite error.
+ $file = file_save_data($contents, 'asdf.txt', FILE_EXISTS_ERROR);
+ $this->assertFalse($file, t("Overwriting a file fails when FILE_EXISTS_ERROR is specified."));
+
+ // Clear out the error messages.
+# drupal_get_messages();
+ }
+
+ function testFileSaveUpload() {
+ $max_fid_before = db_result(db_query("SELECT MAX(fid) AS fid FROM {files}"));
+
+ $upload_user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($upload_user);
+
+ $image = current($this->drupalGetTestFiles('image'));
+ $this->assertTrue(is_file($image->filename), t("the file we're going to upload exists."));
+ $edit = array('files[file_test_upload]' => realpath($image->filename));
+ $this->drupalPost('file-test/upload', $edit, t('Submit'));
+ $this->assertResponse(200, t("Received a 200 response for posted test file."));
+ $this->assertText(t('hook_file_validate() was called.'), t('hook_file_validate() was called.'));
+ $this->assertText(t('hook_file_insert() was called.'), t('hook_file_insert() was called.'));
+
+ $max_fid_after = db_result(db_query("SELECT MAX(fid) AS fid FROM {files}"));
+
+ $this->assertTrue($max_fid_after > $max_fid_before, t("A new file was created."));
+ }
+}
+
+/**
+ * Directory related tests.
+ */
+class FileDirectoryTest extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('File paths and directories'),
+ 'description' => t('Tests operations dealing with directories.'),
+ 'group' => t('File'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('file_test');
+
+ // A directory to operate on.
+ $this->directory = file_directory_path() . '/' . $this->randomName();
+ // Save initial temp directory as this gets modified.
+ $this->initial_temp_directory = variable_get('file_directory_temp', NULL);
+ }
+
+ /**
+ * Implementation of tearDown().
+ */
+ function tearDown() {
+ @rmdir($this->directory);
+ variable_set('file_directory_temp', $this->initial_temp_directory);
+
+ // clear out form error messages generated
+# drupal_get_messages();
+
+ parent::tearDown();
+ }
+
+ /**
+ * Check directory creation and validation
+ */
+ function testFileCheckDirectory() {
+ // non-existent directory
+ $form_element = $this->randomName();
+ $this->assertFalse(file_check_directory($this->directory, 0, $form_element), t("Error reported for non-existing directory."), 'File');
+
+ // check that an error was set for the form element above
+ $errors = form_get_errors();
+ $this->assertEqual($errors[$form_element], t('The directory %directory does not exist.', array('%directory' => $this->directory)), t("Properly generated an error for the passed form element."), 'File');
+
+ // make a directory
+ $this->assertTrue(file_check_directory($this->directory, FILE_CREATE_DIRECTORY), t("No error reported when creating a new directory"), 'File');
+
+ // make sure directory actually exists
+ $this->assertTrue(is_dir($this->directory), t("Directory actually exists"), 'File');
+
+ // make directory read only
+ @chmod($this->directory, 0444);
+ $form_element = $this->randomName();
+ $this->assertFalse(file_check_directory($this->directory, 0, $form_element), t("Error reported for a non-writeable directory"), 'File');
+
+ // check if form error was set
+ $errors = form_get_errors();
+ $this->assertEqual($errors[$form_element], t('The directory %directory is not writable', array('%directory' => $this->directory)), t("Properly generated an error for the passed form element."), 'File');
+
+ // test directory permission modification
+ $this->assertTrue(file_check_directory($this->directory, FILE_MODIFY_PERMISSIONS), t("No error reported when making directory writeable."), 'File');
+
+ // verify directory actually is writeable
+ $this->assertTrue(is_writeable($this->directory), t("Directory is writeable"), 'File');
+
+ // remove .htaccess file to then test the writing of .htaccess file
+ @unlink(file_directory_path() .'/.htaccess');
+ file_check_directory(file_directory_path());
+ $this->assertTrue(is_file(file_directory_path() . '/.htaccess'), t('Successfully created the .htaccess file in the files directory.'), 'File');
+
+ // verify contents of .htaccess file
+ $file = file_get_contents(file_directory_path() .'/.htaccess');
+ $this->assertEqual($file, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks", t('The .htaccess file contains the proper content.'), 'File');
+ }
+
+ /**
+ * Check file_directory_path() and file_directory_temp().
+ */
+ function testFileDirectoryPath() {
+ // directory path
+ $path = variable_get('file_directory_path', conf_path() . '/files');
+ $this->assertEqual($path, file_directory_path(), t("Properly returns the stored file directory path."), 'File');
+ }
+
+ /**
+ * Check file_directory_path() and file_directory_temp().
+ */
+ function testFileDirectoryTemp() {
+ // temp directory handling
+ variable_set('file_directory_temp', NULL);
+ $temp = file_directory_temp();
+ $this->assertTrue(!is_null($temp), t("Properly set and retrieved temp directory %directory", array('%directory' => $temp)), 'File');
+ }
+
+ /**
+ * This tests that a file is actually in the specified directory, to prevent exploits.
+ */
+ function testFileCheckLocation() {
+ $source = 'misc/xyz.txt';
+ $directory = 'misc';
+ $result = file_check_location($source, $directory);
+ $this->assertTrue($result, t("Non-existent file validates when checked for location in existing directory."), 'File');
+
+ $source = 'fake/xyz.txt';
+ $directory = 'fake';
+ $result = file_check_location($source, $directory);
+ $this->assertTrue($result, t("Non-existent file validates when checked for location in non-existing directory."), 'File');
+
+ $source = 'misc/fake/xyz.txt';
+ $directory = 'misc';
+ $result = file_check_location($source, $directory);
+ $this->assertTrue($result, t("Non-existent file validates when checked for location in directory, but name contains a non-existent subfolder."), 'File');
+
+ $source = 'misc/../install.php';
+ $directory = 'misc';
+ $result = file_check_location($source, $directory);
+ $this->assertFalse($result, t("Existing file fails validation when it exists outside the directory path, using a /../ exploit."), 'File');
+
+ $source = 'misc/druplicon.png';
+ $directory = 'misc';
+ $result = file_check_location($source, $directory);
+ $this->assertTrue($result, t("Existing file passes validation when checked for location in directory path, and filepath contains a subfolder of the checked path."), 'File');
+
+ $result = file_check_location($source, $directory);
+ $this->assertTrue($result, t("Existing file passes validation, returning the source when checked for location in directory."), 'File');
+ }
+
+
+ /**
+ * This will take a directory and path, and find a valid filepath that is not taken by another file.
+ * First we test against an imaginary file that does not exist in a directory.
+ * Then we test against a file that already exists within that directory.
+ * @TODO: Finally we copy a file into a directory several times, to ensure a properly iterating filename suffix.
+ */
+ function testFileCreateNewFilepath() {
+ $basename = 'xyz.txt';
+ $directory = 'misc';
+ $original = $directory .'/'. $basename;
+ $path = file_create_filename($basename, $directory);
+ $this->assertEqual($path, $original, t("New filepath %new equals %original.", array('%new' => $path, '%original' => $original)), 'File');
+
+ $basename = 'druplicon.png';
+ $original = $directory .'/'. $basename;
+ $expected = $directory .'/druplicon_0.png';
+ $path = file_create_filename($basename, $directory);
+ $this->assertEqual($path, $expected, t("Creating a new filepath from %original equals %new.", array('%new' => $path, '%original' => $original)), 'File');
+ }
+
+ /**
+ * This will test the filepath for a destination based on passed flags and
+ * whether or not the file exists.
+ * If a file exists, file_destination($destination, $replace) will either return the existing filepath,
+ * if $replace is FILE_EXISTS_REPLACE, a new filepath if FILE_EXISTS_RENAME, or an error (returning FALSE)
+ * if FILE_EXISTS_ERROR.
+ * If the file doesn't currently exist, then it will simply return the filepath.
+ */
+ function testFileDestination() {
+ // First test for non-existent file.
+ $destination = 'misc/xyz.txt';
+ $path = file_destination($destination, FILE_EXISTS_REPLACE);
+ $this->assertEqual($path, $destination, t("Non-existing filepath destination is correct with FILE_EXISTS_REPLACE."), 'File');
+ $path = file_destination($destination, FILE_EXISTS_RENAME);
+ $this->assertEqual($path, $destination, t("Non-existing filepath destination is correct with FILE_EXISTS_RENAME."), 'File');
+ $path = file_destination($destination, FILE_EXISTS_ERROR);
+ $this->assertEqual($path, $destination, t("Non-existing filepath destination is correct with FILE_EXISTS_ERROR."), 'File');
+
+ $destination = 'misc/druplicon.png';
+ $path = file_destination($destination, FILE_EXISTS_REPLACE);
+ $this->assertEqual($path, $destination, t("Existing filepath destination remains the same with FILE_EXISTS_REPLACE."), 'File');
+ $path = file_destination($destination, FILE_EXISTS_RENAME);
+ $this->assertNotEqual($path, $destination, t("A new filepath destination is created when filepath destination already exists with FILE_EXISTS_RENAME."), 'File');
+ $path = file_destination($destination, FILE_EXISTS_ERROR);
+ $this->assertEqual($path, FALSE, t("An error is returned when filepath destination already exists with FILE_EXISTS_ERROR."), 'File');
+ }
+}
+
+
+/**
+ * Deletion related tests
+ */
+class FileCopyDeleteMoveTest extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('File management'),
+ 'description' => t('Tests the file copy, delete and move functions.'),
+ 'group' => t('File'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ // Install file_test module
+ parent::setUp('file_test');
+
+ // A directory to operate on.
+ $this->dirname = file_directory_path() . '/' . $this->randomName();
+ mkdir($this->dirname);
+
+ // Create a file for testing
+ $f = new stdClass();
+ $f->filepath = file_directory_path() . '/' . $this->randomName();
+ $f->filename = basename($f->filepath);
+ $f->filemime = 'text/plain';
+ $f->uid = 1;
+ touch($f->filepath);
+ $this->file = file_save($f);
+ }
+
+ /**
+ * Implementation of tearDown().
+ */
+ function tearDown() {
+ @rmdir($this->dirname);
+ @unlink($this->file->filepath);
+ if (!empty($this->file->fid)) {
+ db_query('DELETE FROM {files} WHERE fid = %d', array($this->file->fid));
+ }
+
+ parent::tearDown();
+ }
+
+
+ function testFileDeletePlain() {
+ // Delete a regular file
+ $this->assertTrue(is_file($this->file->filepath), t("File exists."));
+ $this->assertTrue(file_delete_plain($this->file->filepath), t("Deleted worked."));
+ $this->assertFalse(file_exists($this->file->filepath), t("Test file has actually been deleted."));
+ }
+
+ function testFileDeletePlain_Missing() {
+ // Try to delete a non-existing file
+ $this->assertTrue(file_delete_plain(file_directory_path() . '/' . $this->randomName()), t("Returns true when deleting a non-existant file."));
+ }
+
+ function testFileDeletePlain_Directory() {
+ // Try to delete a directory
+ $this->assertTrue(is_dir($this->dirname), t("Directory exists."));
+ $this->assertFalse(file_delete_plain($this->dirname), t("Could not delete the delete directory."));
+ $this->assertTrue(file_exists($this->dirname), t("Directory has not been deleted."));
+ }
+
+
+ function testFileDelete() {
+ file_test_reset_calls();
+
+ // Check that deletion removes the file and database record.
+ $this->assertTrue(is_file($this->file->filepath), t("File exists."));
+ $this->assertTrue(file_delete($this->file), t("Delete worked."));
+ $this->assertEqual(count(file_test_get_calls('references')), 1, t('hook_file_references was called.'));
+ $this->assertEqual(count(file_test_get_calls('delete')), 1, t('hook_file_delete was called.'));
+ $this->assertFalse(file_exists($this->file->filepath), t("Test file has actually been deleted."));
+ $this->assertFalse(file_load(array('filepath' => $this->file->filepath)), t("File was removed from the database"));
+
+ // TODO: figure out how to implement hook_file_references() so we can
+ // report a file in use and test the $force parameter.
+ }
+
+ function testFileMovePlain() {
+ // Moving to a new name.
+ $this->assertTrue(file_exists($this->file->filepath), t("File exists before moving."));
+ $desired_filepath = file_directory_path() . '/' . $this->randomName();
+ $new_filepath = file_move_plain($this->file->filepath, $desired_filepath, FILE_EXISTS_ERROR);
+ $this->assertTrue($new_filepath, t("Move was successful."));
+ $this->assertEqual($new_filepath, $desired_filepath, t("Returned expected filepath."));
+ $this->assertTrue(file_exists($new_filepath), t("File exists at the new location."));
+ $this->assertFalse(file_exists($this->file->filepath), t("No file remains at the old location."));
+
+ // Moving with rename.
+ $desired_filepath = file_directory_path() . '/' . $this->randomName();
+ $this->assertTrue(file_exists($new_filepath), t("File exists before moving."));
+ $this->assertTrue(touch($desired_filepath), t('Created a file so a rename will have to happen.'));
+ $newer_filepath = file_move_plain($new_filepath, $desired_filepath, FILE_EXISTS_RENAME);
+ $this->assertTrue($newer_filepath, t("Move was successful."));
+ $this->assertNotEqual($newer_filepath, $desired_filepath, t("Returned expected filepath."));
+ $this->assertTrue(file_exists($newer_filepath), t("File exists at the new location."));
+ $this->assertFalse(file_exists($new_filepath), t("No file remains at the old location."));
+
+ // TODO: test moving to a directory (rather than full directory/file path)
+ }
+
+ function testFileMovePlain_Missing() {
+ // Move non-existant file
+ $new_filepath = file_move_plain($this->randomName(), $this->randomName());
+ $this->assertFalse($new_filepath, t("Moving a missing file fails"));
+
+ drupal_get_messages();
+ }
+
+ function testFileMovePlain_OverwriteSelf() {
+ // Move the file onto itself without renaming shouldn't make changes.
+ $this->assertTrue(file_exists($this->file->filepath), t("File exists before moving."));
+ $new_filepath = file_move_plain($this->file->filepath, $this->file->filepath, FILE_EXISTS_REPLACE);
+ $this->assertFalse($new_filepath, t("Moving onto itself without renaming fails."));
+ $this->assertTrue(file_exists($this->file->filepath), t("File exists after moving onto itself."));
+
+ // Move the file onto itself with renaming will result in a new filename.
+ $this->assertTrue(file_exists($this->file->filepath), t("File exists before moving."));
+ $new_filepath = file_move_plain($this->file->filepath, $this->file->filepath, FILE_EXISTS_RENAME);
+ $this->assertTrue($new_filepath, t("Moving onto itself with renaming works."));
+ $this->assertFalse(file_exists($this->file->filepath), t("Original file has been removed."));
+ $this->assertTrue(file_exists($new_filepath), t("File exists after moving onto itself."));
+
+ drupal_get_messages();
+ }
+
+ function testFileMove() {
+ file_test_reset_calls();
+ $desired_filepath = file_directory_path() . '/' . $this->randomName();
+
+ $file = file_move(clone $this->file, $desired_filepath, FILE_EXISTS_ERROR);
+ $this->assertTrue($file, t("File moved sucessfully."));
+ $this->assertEqual(count(file_test_get_calls('move')), 1, t('hook_file_move was called.'));
+ $this->assertEqual(count(file_test_get_calls('update')), 1, t('hook_file_update was called.'));
+ $this->assertEqual($file->fid, $this->file->fid, t("File id $file->fid is unchanged after move."));
+
+ $loaded_file = file_load($file->fid, TRUE);
+ $this->assertTrue($loaded_file, t("File can be loaded from the database."));
+ $this->assertEqual($file->filename, $loaded_file->filename, t("File name was updated correctly in the database."));
+ $this->assertEqual($file->filepath, $loaded_file->filepath, t("File path was updated correctly in the database."));
+
+ // Clean up the file so that the directory can be removed
+ @unlink($loaded_file->filepath);
+ }
+
+
+ function testFileCopyPlain() {
+ // Copying to a new name.
+ $desired_filepath = file_directory_path() . '/' . $this->randomName();
+ $new_filepath = file_copy_plain($this->file->filepath, $desired_filepath, FILE_EXISTS_ERROR);
+ $this->assertTrue($new_filepath, t("Copy was successful."));
+ $this->assertEqual($new_filepath, $desired_filepath, t("Returned expected filepath."));
+ $this->assertTrue(file_exists($this->file->filepath), t("Original file remains."));
+ $this->assertTrue(file_exists($new_filepath), t("New file exists."));
+
+ // Copying with rename.
+ $desired_filepath = file_directory_path() . '/' . $this->randomName();
+ $this->assertTrue(touch($desired_filepath), t('Created a file so a rename will have to happen.'));
+ $newer_filepath = file_copy_plain($new_filepath, $desired_filepath, FILE_EXISTS_RENAME);
+ $this->assertTrue($newer_filepath, t("Copy was successful."));
+ $this->assertNotEqual($newer_filepath, $desired_filepath, t("Returned expected filepath."));
+ $this->assertTrue(file_exists($this->file->filepath), t("Original file remains."));
+ $this->assertTrue(file_exists($new_filepath), t("New file exists."));
+
+ // TODO: test copying to a directory (rather than full directory/file path)
+ }
+
+ function testFileCopyPlain_NonExistant() {
+ // Copy non-existant file
+ $desired_filepath = $this->randomName();
+ $this->assertFalse(file_exists($desired_filepath), t("Randomly named file doesn't exists."));
+ $new_filepath = file_copy_plain($desired_filepath, $this->randomName());
+ $this->assertFalse($new_filepath, t("Copying a missing file fails"));
+
+ drupal_get_messages();
+ }
+
+ function testFileCopyPlain_OverwriteSelf() {
+ // Copy the file onto itself with renaming works.
+ $this->assertTrue(file_exists($this->file->filepath), t("File exists before copying."));
+ $new_filepath = file_copy_plain($this->file->filepath, $this->file->filepath, FILE_EXISTS_RENAME);
+ $this->assertTrue($new_filepath, t("Copying onto itself with renaming works."));
+ $this->assertNotEqual($new_filepath, $this->file->filepath, t("Copied file has a new name."));
+ $this->assertTrue(file_exists($this->file->filepath), t("Original file exists after copying onto itself."));
+ $this->assertTrue(file_exists($new_filepath), t("Copied file exists after copying onto itself."));
+
+ // Copy the file onto itself without renaming fails.
+ $this->assertTrue(file_exists($this->file->filepath), t("File exists before copying."));
+ $new_filepath = file_copy_plain($this->file->filepath, $this->file->filepath, FILE_EXISTS_ERROR);
+ $this->assertFalse($new_filepath, t("Copying onto itself without renaming fails."));
+ $this->assertTrue(file_exists($this->file->filepath), t("File exists after copying onto itself."));
+
+ // Copy the file into same directory without renaming fails.
+ $this->assertTrue(file_exists($this->file->filepath), t("File exists before copying."));
+ $new_filepath = file_copy_plain($this->file->filepath, dirname($this->file->filepath), FILE_EXISTS_ERROR);
+ $this->assertFalse($new_filepath, t("Copying onto itself fails."));
+ $this->assertTrue(file_exists($this->file->filepath), t("File exists after copying onto itself."));
+
+ // Copy the file into same directory with renaming works.
+ $this->assertTrue(file_exists($this->file->filepath), t("File exists before copying."));
+ $new_filepath = file_copy_plain($this->file->filepath, dirname($this->file->filepath), FILE_EXISTS_RENAME);
+ $this->assertTrue($new_filepath, t("Copying into same directory works."));
+ $this->assertNotEqual($new_filepath, $this->file->filepath, t("Copied file has a new name."));
+ $this->assertTrue(file_exists($this->file->filepath), t("Original file exists after copying onto itself."));
+ $this->assertTrue(file_exists($new_filepath), t("Copied file exists after copying onto itself."));
+
+ drupal_get_messages();
+ }
+
+
+ function testFileCopy() {
+ file_test_reset_calls();
+ $desired_filepath = file_directory_path() . '/' . $this->randomName();
+
+ $file = file_copy(clone $this->file, $desired_filepath, FILE_EXISTS_ERROR);
+ $this->assertTrue($file, t("File copied sucessfully."));
+ $this->assertEqual(count(file_test_get_calls('copy')), 1, t('hook_file_copy was called.'));
+ $this->assertEqual(count(file_test_get_calls('insert')), 1, t('hook_file_insert was called.'));
+ $this->assertNotEqual($file->fid, $this->file->fid, t("A new file id was created."));
+ $this->assertNotEqual($file->filepath, $this->file->filepath, t("A new filepath was created."));
+ $this->assertEqual($file->filepath, $desired_filepath, t('The copied file object has the desired filepath'));
+ $this->assertTrue(file_exists($this->file->filepath), t('The original file still exists.'));
+ $this->assertTrue(file_exists($file->filepath), t('The copied file exists'));
+
+ // Check that the changes were actually saved to the database.
+ $loaded_file = file_load($file->fid, TRUE);
+ $this->assertTrue($loaded_file, t("File can be loaded from the database."));
+ $this->assertEqual($file->filename, $loaded_file->filename, t("File name was updated correctly in the database."));
+ $this->assertEqual($file->filepath, $loaded_file->filepath, t("File path was updated correctly in the database."));
+
+ // Clean up the file so that the directory can be removed
+ @unlink($loaded_file->filepath);
+ }
+
+}
+
Index: modules/simpletest/tests/file_test.info
===================================================================
RCS file: modules/simpletest/tests/file_test.info
diff -N modules/simpletest/tests/file_test.info
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/file_test.info 7 Sep 2008 00:09:48 -0000
@@ -0,0 +1,8 @@
+; $Id$
+name = "File test"
+description = "Support module for file handling tests."
+package = Testing
+version = VERSION
+core = 7.x
+files[] = file_test.module
+hidden = TRUE
Index: modules/simpletest/tests/file_test.module
===================================================================
RCS file: modules/simpletest/tests/file_test.module
diff -N modules/simpletest/tests/file_test.module
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/file_test.module 7 Sep 2008 00:09:48 -0000
@@ -0,0 +1,191 @@
+ t('Upload test'),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('_file_test_form'),
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+ return $items;
+}
+
+/**
+ * Reset/initialize the history of calls to the file_* hooks.
+ */
+function file_test_reset_calls() {
+ global $file_test_results;
+
+ $file_test_results = array(
+ 'load' => array(),
+ 'validate' => array(),
+ 'download' => array(),
+ 'references' => array(),
+ 'status' => array(),
+ 'insert' => array(),
+ 'update' => array(),
+ 'copy' => array(),
+ 'move' => array(),
+ 'delete' => array(),
+ );
+}
+
+/**
+ * Log the invocation of a file hook.
+ *
+ * @param $op One of the hook_file_* operations.
+ * @param $args Arguments passed to the hook.
+ */
+function _file_test_add_call($op, $args) {
+ global $file_test_results;
+ $file_test_results[$op][] = $args;
+}
+
+/**
+ * Get the values passed to a the hook calls for a given operation.
+ *
+ * @param $op One of the hook_file_* operations.
+ * @returns Array of the parameters passed to each call.
+ */
+function file_test_get_calls($op) {
+ global $file_test_results;
+ return $file_test_results[$op];
+}
+
+
+/**
+ * Helper validator that returns the $errors parameter.
+ */
+function file_test_validator($file, $errors) {
+ return $errors;
+}
+
+
+/**
+ * Implementation of hook_file_load().
+ */
+function file_test_file_load(&$file) {
+ $args = func_get_args();
+ _file_test_add_call('load', $args);
+}
+
+/**
+ * Implementation of hook_file_validate().
+ */
+function file_test_file_validate(&$file) {
+ $args = func_get_args();
+ _file_test_add_call('validate', $args);
+}
+
+/**
+ * Implementation of hook_file_status().
+ */
+function file_test_file_status(&$file) {
+ $args = func_get_args();
+ _file_test_add_call('status', $args);
+}
+
+/**
+ * Implementation of hook_file_download().
+ */
+function file_test_file_download(&$file) {
+ $args = func_get_args();
+ _file_test_add_call('download', $args);
+}
+
+/**
+ * Implementation of hook_file_references().
+ */
+function file_test_file_references(&$file) {
+ $args = func_get_args();
+ _file_test_add_call('references', $args);
+}
+
+/**
+ * Implementation of hook_file_insert().
+ */
+function file_test_file_insert(&$file) {
+ $args = func_get_args();
+ _file_test_add_call('insert', $args);
+}
+
+/**
+ * Implementation of hook_file_update().
+ */
+function file_test_file_update(&$file) {
+ $args = func_get_args();
+ _file_test_add_call('update', $args);
+}
+
+/**
+ * Implemenation of hook_file_copy().
+ */
+function file_test_file_copy(&$file, &$source) {
+ $args = func_get_args();
+ _file_test_add_call('copy', $args);
+}
+
+/**
+ * Implemenation of hook_file_move().
+ */
+function file_test_file_move(&$file, &$source) {
+ $args = func_get_args();
+ _file_test_add_call('move', $args);
+}
+
+/**
+ * Implementation of hook_file_delete().
+ */
+function file_test_file_delete(&$file) {
+ $args = func_get_args();
+ _file_test_add_call('delete', $args);
+}
+
+
+/**
+ * Form to test file uploads.
+ */
+function _file_test_form(&$form_state) {
+ $form['#validate'][] = '_file_test_validate_upload';
+ $form['file_test_upload'] = array(
+ '#type' => 'file',
+ '#title' => t('Upload image file'),
+ );
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Submit'),
+ );
+ return $form;
+}
+
+/**
+ * Process the upload.
+ */
+function _file_test_validate_upload(&$form, &$form_state) {
+ // Validate the uploaded picture.
+ $validators = array(
+ 'file_validate_is_image' => array(),
+ );
+file_put_contents('/Users/amorton/Sites/dh/sites/default/files/drupal.log', "before upload\n", FILE_APPEND);
+ if ($file = file_save_upload('file_test_upload', $validators)) {
+ $form_state['values']['file_test_upload'] = $file;
+ if (count(file_test_get_calls('validate'))) {
+ drupal_set_message(t('hook_file_validate() was called.'));
+ }
+ if (count(file_test_get_calls('insert'))) {
+ drupal_set_message(t('hook_file_insert() was called.'));
+ }
+ }
+}
Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.87
diff -u -p -r1.87 system.admin.inc
--- modules/system/system.admin.inc 6 Sep 2008 08:36:21 -0000 1.87
+++ modules/system/system.admin.inc 7 Sep 2008 00:09:48 -0000
@@ -338,9 +338,9 @@ function system_theme_settings(&$form_st
// The image was saved using file_save_upload() and was added to the
// files table as a temporary file. We'll make a copy and let the garbage
// collector delete the original upload.
- if (file_copy($file, $filename, FILE_EXISTS_REPLACE)) {
+ if ($filepath = file_copy_plain($file->filepath, $filename, FILE_EXISTS_REPLACE)) {
$_POST['default_logo'] = 0;
- $_POST['logo_path'] = $file->filepath;
+ $_POST['logo_path'] = $filepath;
$_POST['toggle_logo'] = 1;
}
}
@@ -353,9 +353,9 @@ function system_theme_settings(&$form_st
// The image was saved using file_save_upload() and was added to the
// files table as a temporary file. We'll make a copy and let the garbage
// collector delete the original upload.
- if (file_copy($file, $filename)) {
+ if ($filepath = file_copy_plain($file->filepath, $filename, FILE_EXISTS_REPLACE)) {
$_POST['default_favicon'] = 0;
- $_POST['favicon_path'] = $file->filepath;
+ $_POST['favicon_path'] = $filepath;
$_POST['toggle_favicon'] = 1;
}
}
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.617
diff -u -p -r1.617 system.module
--- modules/system/system.module 6 Sep 2008 08:36:21 -0000 1.617
+++ modules/system/system.module 7 Sep 2008 00:09:48 -0000
@@ -1401,12 +1401,14 @@ function system_cron() {
if (file_exists($file->filepath)) {
// If files that exist cannot be deleted, continue so the database remains
// consistent.
- if (!file_delete($file->filepath)) {
+ if (!file_delete($file)) {
watchdog('file system', 'Could not delete temporary file "%path" during garbage collection', array('%path' => $file->filepath), WATCHDOG_ERROR);
continue;
}
}
- db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
+ else {
+ db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
+ }
}
}
Index: modules/upload/upload.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload/upload.admin.inc,v
retrieving revision 1.10
diff -u -p -r1.10 upload.admin.inc
--- modules/upload/upload.admin.inc 16 Jul 2008 21:59:28 -0000 1.10
+++ modules/upload/upload.admin.inc 7 Sep 2008 00:09:48 -0000
@@ -74,11 +74,10 @@ function upload_admin_settings() {
'#field_suffix' => '' . t('WIDTHxHEIGHT') . ''
);
$form['settings_general']['upload_list_default'] = array(
- '#type' => 'select',
+ '#type' => 'checkbox',
'#title' => t('List files by default'),
'#default_value' => variable_get('upload_list_default', 1),
- '#options' => array(0 => t('No'), 1 => t('Yes')),
- '#description' => t('Display attached files when viewing a post.'),
+ '#description' => t('Determines whether attached files are shown to users by default.'),
);
$form['settings_general']['upload_extensions_default'] = array(
Index: modules/upload/upload.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload/upload.module,v
retrieving revision 1.205
diff -u -p -r1.205 upload.module
--- modules/upload/upload.module 24 Jul 2008 16:25:19 -0000 1.205
+++ modules/upload/upload.module 7 Sep 2008 00:09:48 -0000
@@ -263,6 +263,38 @@ function upload_form_alter(&$form, $form
}
/**
+ * Implementation of hook_file_load().
+ */
+function upload_file_load(&$file, $source = NULL) {
+ // Add the upload specific data into the file object.
+ $values = db_fetch_array(db_query('SELECT * FROM {upload} u WHERE u.fid = %d', $file->fid));
+ foreach ((array)$values as $key => $value) {
+ $file->{$key} = $value;
+ }
+}
+
+/**
+ * Implementation of hook_file_references().
+ */
+function upload_file_references(&$file, $source = NULL) {
+ // If upload.module is still using a file, do not let other modules delete it.
+ $count = db_result(db_query('SELECT count(*) FROM {upload} WHERE fid = %d', $file->fid));
+ if ($count) {
+ // return the name of the module and how many references it has to the file.
+ return array('upload' => $count);
+ }
+}
+
+/**
+ * Implementation of hook_file_delete().
+ */
+function upload_file_delete(&$file, $source = NULL) {
+ // Delete all information associated with the file.
+ db_query('DELETE FROM {upload} WHERE fid = %d', $file->fid);
+}
+
+
+/**
* Implementation of hook_nodeapi().
*/
function upload_nodeapi(&$node, $op, $teaser) {
@@ -406,13 +438,15 @@ function upload_save(&$node) {
// If the file isn't used by any other revisions delete it.
$count = db_result(db_query('SELECT COUNT(fid) FROM {upload} WHERE fid = %d', $fid));
if ($count < 1) {
- file_delete($file->filepath);
+ file_delete($file);
db_query('DELETE FROM {files} WHERE fid = %d', $fid);
}
// Remove it from the session in the case of new uploads,
// that you want to disassociate before node submission.
unset($_SESSION['upload_files'][$fid]);
+ // Try to clean up a file that is no longer in use.
+ file_delete($file);
// Move on, so the removed file won't be added to new revisions.
continue;
}
@@ -420,13 +454,12 @@ function upload_save(&$node) {
// Create a new revision, or associate a new file needed.
if (!empty($node->old_vid) || isset($_SESSION['upload_files'][$fid])) {
db_query("INSERT INTO {upload} (fid, nid, vid, list, description, weight) VALUES (%d, %d, %d, %d, '%s', %d)", $file->fid, $node->nid, $node->vid, $file->list, $file->description, $file->weight);
- file_set_status($file, FILE_STATUS_PERMANENT);
}
// Update existing revision.
else {
db_query("UPDATE {upload} SET list = %d, description = '%s', weight = %d WHERE fid = %d AND vid = %d", $file->list, $file->description, $file->weight, $file->fid, $node->vid);
- file_set_status($file, FILE_STATUS_PERMANENT);
}
+ file_set_status($file, FILE_STATUS_PERMANENT);
}
// Empty the session storage after save. We use this variable to track files
// that haven't been related to the node yet.
@@ -434,38 +467,23 @@ function upload_save(&$node) {
}
function upload_delete($node) {
- $files = array();
- $result = db_query('SELECT DISTINCT f.* FROM {upload} u INNER JOIN {files} f ON u.fid = f.fid WHERE u.nid = %d', $node->nid);
- while ($file = db_fetch_object($result)) {
- $files[$file->fid] = $file;
+ db_query('DELETE FROM {upload} WHERE nid = %d', $node->nid);
+ if (!is_array($node->files)) {
+ return;
}
-
- foreach ($files as $fid => $file) {
- // Delete all files associated with the node
- db_query('DELETE FROM {files} WHERE fid = %d', $fid);
- file_delete($file->filepath);
+ foreach($node->files as $file) {
+ file_delete($file);
}
-
- // Delete all file revision information associated with the node
- db_query('DELETE FROM {upload} WHERE nid = %d', $node->nid);
}
function upload_delete_revision($node) {
- if (is_array($node->files)) {
- foreach ($node->files as $file) {
- // Check if the file will be used after this revision is deleted
- $count = db_result(db_query('SELECT COUNT(fid) FROM {upload} WHERE fid = %d', $file->fid));
-
- // if the file won't be used, delete it
- if ($count < 2) {
- db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
- file_delete($file->filepath);
- }
- }
- }
-
- // delete the revision
db_query('DELETE FROM {upload} WHERE vid = %d', $node->vid);
+ if (!is_array($node->files)) {
+ return;
+ }
+ foreach ($node->files as $file) {
+ file_delete($file);
+ }
}
function _upload_form($node) {
@@ -479,11 +497,11 @@ function _upload_form($node) {
if (!empty($node->files) && is_array($node->files)) {
$form['files']['#theme'] = 'upload_form_current';
$form['files']['#tree'] = TRUE;
- foreach ($node->files as $key => $file) {
+ foreach ($node->files as $file) {
$file = (object)$file;
- $description = file_create_url($file->filepath);
- $description = "" . check_plain($description) . "";
- $form['files'][$key]['description'] = array('#type' => 'textfield', '#default_value' => !empty($file->description) ? $file->description : $file->filename, '#maxlength' => 256, '#description' => $description );
+ $key = $file->fid;
+
+ $form['files'][$key]['description'] = array('#type' => 'textfield', '#default_value' => !empty($file->description) ? $file->description : $file->filename, '#maxlength' => 256, '#description' => '' . file_create_url($file->filepath) . '');
$form['files'][$key]['size'] = array('#markup' => format_size($file->filesize));
$form['files'][$key]['remove'] = array('#type' => 'checkbox', '#default_value' => !empty($file->remove));
$form['files'][$key]['list'] = array('#type' => 'checkbox', '#default_value' => $file->list);
@@ -498,12 +516,26 @@ function _upload_form($node) {
if (user_access('upload files')) {
$limits = _upload_file_limits($user);
+
+ $limit_description = t('The maximum size of file uploads is %filesize. ', array('%filesize' => format_size($limits['file_size'])));
+ if (!empty($limits['resolution'])) {
+ if (image_get_toolkit()) {
+ $limit_description .= t('Images larger than %resolution will be resized. ', array('%resolution' => $limits['resolution']));
+ }
+ else {
+ $limit_description .= t('Images may not be larger than %resolution. ', array('%resolution' => $limits['resolution']));
+ }
+ }
+ if ($user->uid != 1) {
+ $limit_description .= t('Only files with the following extensions may be uploaded: %extensions. ', array('%extensions' => $limits['extensions']));
+ }
+
$form['new']['#weight'] = 10;
$form['new']['upload'] = array(
'#type' => 'file',
'#title' => t('Attach new file'),
'#size' => 40,
- '#description' => ($limits['resolution'] ? t('Images are larger than %resolution will be resized. ', array('%resolution' => $limits['resolution'])) : '') . t('The maximum upload size is %filesize. Only files with the following extensions may be uploaded: %extensions. ', array('%extensions' => $limits['extensions'], '%filesize' => format_size($limits['file_size']))),
+ '#description' => $limit_description,
);
$form['new']['attach'] = array(
'#type' => 'submit',
@@ -565,9 +597,9 @@ function upload_load($node) {
$files = array();
if ($node->vid) {
- $result = db_query('SELECT * FROM {files} f INNER JOIN {upload} r ON f.fid = r.fid WHERE r.vid = %d ORDER BY r.weight, f.fid', $node->vid);
+ $result = db_query('SELECT u.fid FROM {upload} u WHERE u.vid = %d ORDER BY u.fid', $node->vid);
while ($file = db_fetch_object($result)) {
- $files[$file->fid] = $file;
+ $files[$file->fid] = file_load($file->fid);
}
}
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.918
diff -u -p -r1.918 user.module
--- modules/user/user.module 6 Sep 2008 08:36:22 -0000 1.918
+++ modules/user/user.module 7 Sep 2008 00:09:49 -0000
@@ -406,8 +406,8 @@ function user_validate_picture(&$form, &
);
if ($file = file_save_upload('picture_upload', $validators)) {
// Remove the old picture.
- if (isset($form_state['values']['_account']->picture) && file_exists($form_state['values']['_account']->picture)) {
- file_delete($form_state['values']['_account']->picture);
+ if (isset($form_state['values']['_account']->picture)) {
+ file_delete_plain($form_state['values']['_account']->picture);
}
// The image was saved using file_save_upload() and was added to the
@@ -415,8 +415,8 @@ function user_validate_picture(&$form, &
// collector delete the original upload.
$info = image_get_info($file->filepath);
$destination = variable_get('user_picture_path', 'pictures') . '/picture-' . $form['#uid'] . '.' . $info['extension'];
- if (file_copy($file, $destination, FILE_EXISTS_REPLACE)) {
- $form_state['values']['picture'] = $file->filepath;
+ if (file_copy_plain($file->filepath, $destination, FILE_EXISTS_REPLACE)) {
+ $form_state['values']['picture'] = $destination;
}
else {
form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures'))));
@@ -839,7 +839,7 @@ function template_preprocess_user_pictur
$variables['picture'] = '';
if (variable_get('user_pictures', 0)) {
$account = $variables['account'];
- if (!empty($account->picture) && file_exists($account->picture)) {
+ if (!empty($account->picture) && file_exists(file_create_path($account->picture))) {
$picture = file_create_url($account->picture);
}
else if (variable_get('user_picture_default', '')) {
@@ -1537,8 +1537,8 @@ function _user_edit_submit($uid, &$edit)
$user = user_load(array('uid' => $uid));
// Delete picture if requested, and if no replacement picture was given.
if (!empty($edit['picture_delete'])) {
- if ($user->picture && file_exists($user->picture)) {
- file_delete($user->picture);
+ if ($user->picture) {
+ file_delete_plain($user->picture);
}
$edit['picture'] = '';
}