diff --git includes/file.inc includes/file.inc
index 8cc6e0a..6f47969 100644
--- includes/file.inc
+++ includes/file.inc
@@ -34,7 +34,7 @@ DrupalStreamWrapperRegistry::register('temp', 'DrupalTempStreamWrapper');
* - 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.
+ * - uri - URI of the file.
* - filemime - The file's MIME type.
* - filesize - The size of the file in bytes.
* - status - A bitmapped field indicating the status of the file. The first 8
@@ -45,7 +45,9 @@ DrupalStreamWrapperRegistry::register('temp', 'DrupalTempStreamWrapper');
*/
/**
- * Flag to indicate that the 'public' file download method is enabled.
+ * Flag to indicate that the 'public' file download method is enabled (DEPRECATED).
+ *
+ * TODO: Deprecated, cleanup.
*
* When using this method, files are available from a regular HTTP request,
* which provides no additional access restrictions.
@@ -53,7 +55,9 @@ DrupalStreamWrapperRegistry::register('temp', 'DrupalTempStreamWrapper');
define('FILE_DOWNLOADS_PUBLIC', 1);
/**
- * Flag to indicate that the 'private' file download method is enabled.
+ * Flag to indicate that the 'private' file download method is enabled (DEPRECATED).
+ *
+ * TODO: Deprecated, cleanup.
*
* When using this method, all file requests are served by Drupal, during which
* access-control checking can be performed.
@@ -94,80 +98,122 @@ define('FILE_EXISTS_ERROR', 2);
define('FILE_STATUS_PERMANENT', 1);
/**
- * Create the download path to a file.
+ * Creates the web accessible URL to a stream.
*
- * @param $path A string containing the path of the file to generate URL for.
- * @return A string containing a URL that can be used to download the file.
+ * Compatibility: only stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string $uri
+ * A string containing the URI to verify. If this value is omitted,
+ * Drupal's public files directory will be used [public://].
+ * @return mixed
+ * Returns a string containing a URL that may be used to access the stream.
+ * If the provided string already contains a preceding 'http', nothing is done
+ * and the same string is returned. If a Valid stream wrapper could not be found
+ * to generate an external Url, then FALSE will be returned.
*/
-function file_create_url($path) {
- // Strip file_directory_path from $path. We only include relative paths in
- // URLs.
- $path = file_directory_strip($path);
- switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
- case FILE_DOWNLOADS_PUBLIC:
- return $GLOBALS['base_url'] . '/' . file_directory_path() . '/' . str_replace('\\', '/', $path);
- case FILE_DOWNLOADS_PRIVATE:
- return url('system/files/' . $path, array('absolute' => TRUE));
+function file_create_url($uri) {
+
+ // Flat out check for http so that we don't have to actually implement getExternalUrl()
+ // for the http wrapper.
+ if (DrupalStreamWrapperRegistry::getStreamScheme($uri) == 'http') {
+ // This is already a somewhat properly formatted URL, so do nothing and return.
+ return $uri;
+ }
+
+ if ($wrapper = DrupalStreamWrapperRegistry::getInstanceByUri($uri)) {
+ return $wrapper->getExternalUrl();
+ }
+ else {
+ return FALSE;
}
}
/**
- * Make sure the destination is a complete path and resides in the file system
- * directory, if it is not prepend the file system directory.
+ * Asserts that the URI is a complete path that resides in a valid
+ * filesystem directory.
*
- * @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).
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string $uri
+ * A string containing the URI to verify. If this value is omitted,
+ * Drupal's public files directory will be used [public://].
+ * @param bool $stream
+ * TRUE indicates that $uri should be a stream and a valid scheme is
+ * required. FALSE indicates that $uri should be treated as a normal
+ * path.
+ * @return mixed
+ * Returns a string containing the path to the stream. If the URI is
+ * invalid (i.e. outside a valid filesystem directory), FALSE will be
+ * returned.
*/
-function file_create_path($destination = NULL) {
- $file_path = file_directory_path();
- if (is_null($destination)) {
- return $file_path;
+function file_create_path($uri = NULL, $stream = TRUE) {
+ // If URI is omitted, use Drupal's public files directory [public://].
+ if (is_null($uri)) {
+ return SCHEME_PUBLIC;
+ }
+
+ if ($scheme = DrupalStreamWrapperRegistry::getValidStreamScheme($uri)) {
+ // The URI contains a valid stream scheme.
+ $file_path = $scheme . '://';
}
- // file_check_location() checks whether the destination is inside the Drupal
- // files directory.
- if (file_check_location($destination, $file_path)) {
- return $destination;
+ elseif ($stream) {
+ // The URI must contain a valid scheme.
+ $file_path = SCHEME_PUBLIC . $uri;
+ $uri = SCHEME_PUBLIC . $uri;
}
- // Check if the destination is instead inside the Drupal temporary files
- // directory.
- elseif (file_check_location($destination, file_directory_temp())) {
- return $destination;
+ else {
+ /**
+ * Normal paths must still fall within a directory managed by a registered
+ * stream wrapper for security reasons. We'll assume public:// for now.
+ * TODO: Search all registered wrapper paths for a valid match.
+ */
+ $file_path = file_directory_path(SCHEME_PUBLIC);
+ }
+
+ // Check if the destination is inside the specified path.
+ if ($path = file_check_location($uri, $file_path)) {
+ return $path;
}
- // Not found, try again with prefixed directory path.
- elseif (file_check_location($file_path . '/' . $destination, $file_path)) {
- return $file_path . '/' . $destination;
+ elseif (file_check_location($file_path . '/' . $uri, $file_path)) {
+ return $file_path . '/' . $uri;
}
+
// File not found.
return FALSE;
}
/**
- * Check that the directory exists and is writable.
+ * Asserts that the directory exists and is writable.
*
* Directories need to have execute permissions to be considered a directory by
* FTP servers, etc.
*
- * @param $directory
- * A string containing the name of a directory path.
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string &$directory
+ * A string reference containing the name of a directory path.
* @param $mode
* A bitmask to indicate if the directory should be created if it does
* not exist (FILE_CREATE_DIRECTORY) or made writable if it is read-only
* (FILE_MODIFY_PERMISSIONS).
* @param $form_item
- * An optional string containing the name of a form item that any errors will
- * be attached to. This is useful for settings forms that require the user to
- * specify a writable directory. If it can't be made to work, a form error
- * will be set preventing them from saving the settings.
- * @return
- * FALSE when directory not found, or TRUE when directory exists.
+ * An optional string containing the name of a form item. Any errors will be
+ * attached to this item making it useful for settings forms that require the
+ * user to specify a writable directory. If it can't be made to work, a form
+ * error will be set preventing them from saving the settings.
+ * @return bool
+ * Returns TRUE if the directory exists and is wriable. Otherwise, FALSE
+ * is returned.
*/
function file_check_directory(&$directory, $mode = 0, $form_item = NULL) {
- $directory = rtrim($directory, '/\\');
+
+ if (!DrupalStreamWrapperRegistry::getValidStreamScheme($directory)) {
+ // Only trim if we're not dealing with a stream.
+ $directory = rtrim($directory, '/\\');
+ }
// Check if directory exists.
if (!is_dir($directory)) {
@@ -198,10 +244,21 @@ function file_check_directory(&$directory, $mode = 0, $form_item = NULL) {
}
}
- if ((file_directory_path() == $directory || file_directory_temp() == $directory) && !is_file("$directory/.htaccess")) {
+ // Security SA_2006_06 compliance
+ if (DrupalStreamWrapperRegistry::getValidStreamScheme($directory)) {
+ $htaccess_path = $directory . '.htaccess';
+ }
+ else {
+ $htaccess_path = $directory . '/.htaccess';
+ }
+
+ // Try creating the .htaccess file if it's missing from the public, private, or temp directories.
+ if ((file_directory_path('public') == $directory || file_directory_path('private') == $directory || file_directory_path('temp') == $directory) ||
+ $directory == SCHEME_PUBLIC || $directory == SCHEME_PRIVATE || $directory == SCHEME_TEMP && !is_file("$directory/.htaccess")) {
+
$htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks";
- if (file_put_contents("$directory/.htaccess", $htaccess_lines)) {
- drupal_chmod("$directory/.htaccess");
+ if (file_put_contents($htaccess_path, $htaccess_lines)) {
+ drupal_chmod($htaccess_path);
}
else {
$variables = array('%directory' => $directory, '!htaccess' => '
' . nl2br(check_plain($htaccess_lines)));
@@ -214,15 +271,20 @@ function file_check_directory(&$directory, $mode = 0, $form_item = NULL) {
}
/**
- * Checks path to see if it is a directory, or a directory/file.
+ * Determines whether a path is a directory, or a directory/file.
*
- * @param $path
- * A string containing a file path. This will be set to the directory's path.
- * @return
- * If the directory is not in a Drupal writable directory, FALSE is returned.
- * Otherwise, the base name of the path is returned.
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string &$path
+ * A string reference containing a file path. This will be set to the
+ * directory's path.
+ * @return mixed
+ * Returns the basename of the path. If the directory is not in a Drupal
+ * writable directory FALSE is returned.
*/
function file_check_path(&$path) {
+
// Check if path is a directory.
if (file_check_directory($path)) {
return '';
@@ -239,57 +301,73 @@ function file_check_path(&$path) {
}
/**
- * Check if a file is really located inside $directory.
+ * Assert that a file is located inside the specified directory.
*
- * This should be used to make sure a file specified is really located within
+ * This should be used to make sure that a file is really located within
* the directory to prevent exploits. Note that the file or path being checked
* does not actually need to exist yet.
*
* @code
* // Returns FALSE:
* file_check_location('/www/example.com/files/../../../etc/passwd', '/www/example.com/files');
+ *
+ * // Returns TRUE:
+ * file_check_location('public://dir1/../example.txt', 'public://');
* @endcode
*
- * @param $source
- * A string set to the file to check.
- * @param $directory
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string $source
+ * A string set to the file to check. May be a literal path or a stream wrapper URI.
+ * @param string $directory
* A string where the file should be located.
- * @return
- * FALSE if the path does not exist in the directory; otherwise, the real
- * path of the source.
+ * @return mixed
+ * Returns FALSE if the path does not exist in the directory. Otherwise,
+ * returns the real path of the source.
*/
function file_check_location($source, $directory = '') {
- $check = drupal_realpath($source);
- if ($check) {
- $source = $check;
+ $original_source = $source;
+ $abs_pathname = drupal_realpath($source);
+
+ if ($abs_pathname) {
+ $source = $abs_pathname;
}
else {
- // This file does not yet exist.
- $source = drupal_realpath(drupal_dirname($source)) . '/' . basename($source);
+ // The file does not exist yet.
+ if ($scheme = DrupalStreamWrapperRegistry::getValidStreamScheme($source)) {
+ // We're dealing with a valid stream wrapper.
+ $source = drupal_realpath(file_directory_path($scheme)) . '/' . basename($source);
+ }
+ else {
+ $source = drupal_realpath(dirname($source)) . '/' . basename($source);
+ }
}
+
$directory = drupal_realpath($directory);
if ($directory && strpos($source, $directory) !== 0) {
return FALSE;
}
- return $source;
+
+ return $original_source;
}
/**
- * Load file objects from the database.
+ * Loads multiple file objects from the database.
*
- * @param $fids
+ * @param array $fids
* An array of file IDs.
- * @param $conditions
- * An array of conditions to match against the {files} table. These
+ * @param array $conditions
+ * An array of conditions to match against the {file} table. These
* should be supplied in the form array('field_name' => 'field_value').
* @return
- * An array of file objects, indexed by fid.
+ * Returns an array of file objects, indexed by fid.
*
* @see hook_file_load()
* @see file_load()
*/
function file_load_multiple($fids = array(), $conditions = array()) {
- $query = db_select('files', 'f')->fields('f');
+ $query = db_select('file', 'f')->fields('f');
// If the $fids array is populated, add those to the query.
if ($fids) {
@@ -316,9 +394,9 @@ function file_load_multiple($fids = array(), $conditions = array()) {
}
/**
- * Load a file object from the database.
+ * Loads a file object from the database.
*
- * @param $fid
+ * @param int $fid
* A file ID.
* @return
* A file object.
@@ -332,12 +410,12 @@ function file_load($fid) {
}
/**
- * Save a file object to the database.
+ * Saves 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
+ * @param object $file
* A file object returned by file_load().
* @return
* The updated file object.
@@ -348,15 +426,15 @@ function file_load($fid) {
function file_save($file) {
$file = (object)$file;
$file->timestamp = REQUEST_TIME;
- $file->filesize = filesize($file->filepath);
+ $file->filesize = filesize($file->uri);
if (empty($file->fid)) {
- drupal_write_record('files', $file);
+ drupal_write_record('file', $file);
// Inform modules about the newly added file.
module_invoke_all('file_insert', $file);
}
else {
- drupal_write_record('files', $file, 'fid');
+ drupal_write_record('file', $file, 'fid');
// Inform modules that the file has been updated.
module_invoke_all('file_update', $file);
}
@@ -365,7 +443,7 @@ function file_save($file) {
}
/**
- * Copy a file to a new location and adds a file record to the database.
+ * Copies 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
@@ -379,10 +457,15 @@ function file_save($file) {
* temporary file, the resulting file will also be a temporary file.
* @see file_save_upload() for details on temporary files.
*
- * @param $source
+ * Compatibility: only stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param object $source
* A file object.
- * @param $destination
- * A string containing the destination that $source should be copied to. This
+ * @param string $destination
+ * A string containing the destination that $source should be copied to. This should
+ * be a stream wrapper URI. If this value is omitted, Drupal's public files directory
+ * will be used [public://].
* can be a complete file path, a directory path or, if this value is omitted,
* Drupal's 'files' directory will be used.
* @param $replace
@@ -393,8 +476,9 @@ function file_save($file) {
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
* unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
- * @return
- * File object if the copy is successful, or FALSE in the event of an error.
+ * @return mixed
+ * Returns file object if the copy is successful, or FALSE in the event of an
+ * error.
*
* @see file_unmanaged_copy()
* @see hook_file_copy()
@@ -402,14 +486,14 @@ function file_save($file) {
function file_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
$source = (object)$source;
- if ($filepath = file_unmanaged_copy($source->filepath, $destination, $replace)) {
+ if ($uri = file_unmanaged_copy($source->uri, $destination, $replace)) {
$file = clone $source;
$file->fid = NULL;
- $file->filepath = $filepath;
- $file->filename = basename($filepath);
+ $file->uri = $uri;
+ $file->filename = basename($uri);
// If we are replacing an existing file re-use its database record.
if ($replace == FILE_EXISTS_REPLACE) {
- $existing_files = file_load_multiple(array(), array('filepath' => $filepath));
+ $existing_files = file_load_multiple(array(), array('uri' => $uri));
if (count($existing_files)) {
$existing = reset($existing_files);
$file->fid = $existing->fid;
@@ -429,11 +513,12 @@ function file_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
return $file;
}
+
return FALSE;
}
/**
- * Copy a file to a new location without calling any hooks or making any
+ * Copies a file to a new location without calling any hooks or making any
* changes to the database.
*
* This is a powerful function that in many ways performs like an advanced
@@ -444,9 +529,12 @@ function file_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
* - 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
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string $source
* A string specifying the file location of the original file.
- * @param $destination
+ * @param string $destination
* A string containing the destination that $source should be copied to. This
* can be a complete file path, a directory path or, if this value is omitted,
* Drupal's 'files' directory will be used.
@@ -456,13 +544,16 @@ function file_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
* - 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.
+ * @return mixed
+ * Returns the path to the new file, or FALSE in the event of an error.
*
* @see file_copy()
*/
function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
- $original_source = $source;
+
+ $stream = TRUE; // Should we handle this operation as a stream or normal path?
+
+ $original_source = $source;
$original_destination = $destination;
$source = drupal_realpath($source);
@@ -471,9 +562,15 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
return FALSE;
}
- $proposed_destination = file_create_path($destination);
+ // If $source and $destination do not contain a scheme we're dealing with a normal path.
+ if (!DrupalStreamWrapperRegistry::getValidStreamScheme($source) &&
+ !DrupalStreamWrapperRegistry::getValidStreamScheme($destination)) {
+ $stream = FALSE;
+ }
+
+ $proposed_destination = file_create_path($destination, $stream);
$directory = $proposed_destination;
- $basename = file_check_path($directory);
+ $basename = file_check_path($directory);
// Make sure we at least have a valid directory.
if ($basename === FALSE) {
@@ -481,10 +578,10 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
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);
+ // 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);
+ DrupalStreamWrapperRegistry::normalizeUri($destination);
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 %directory.', array('%file' => $source, '%directory' => $proposed_destination)), 'error');
@@ -493,7 +590,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
// 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 == drupal_realpath($destination)) {
+ if (drupal_realpath($source) == drupal_realpath($destination)) {
drupal_set_message(t('The specified file %file was not copied because it would overwrite itself.', array('%file' => $source)), 'error');
return FALSE;
}
@@ -512,7 +609,10 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
* Determines the destination path for a file depending on how replacement of
* existing files should be handled.
*
- * @param $destination
+ * Compatibility: only stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string $destination
* A string specifying the desired path.
* @param $replace
* Replace behavior when the destination file already exists.
@@ -520,9 +620,9 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
* 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.
+ * @return mixed
+ * Returns the destination file path, or FALSE if the file already exists
+ * and FILE_EXISTS_ERROR is speciefied.
*/
function file_destination($destination, $replace) {
if (file_exists($destination)) {
@@ -546,7 +646,7 @@ function file_destination($destination, $replace) {
}
/**
- * Move a file to a new location and update the file's database entry.
+ * Moves 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.
@@ -556,9 +656,12 @@ function file_destination($destination, $replace) {
* replace the file or rename the file based on the $replace parameter.
* - Adds the new file to the files database.
*
- * @param $source
+ * Compatibility: only stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param object $source
* A file object.
- * @param $destination
+ * @param string $destination
* A string containing the destination that $source should be moved to. This
* can be a complete file path, a directory path or, if this value is omitted,
* Drupal's 'files' directory will be used.
@@ -572,8 +675,9 @@ function file_destination($destination, $replace) {
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
* unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
- * @return
- * Resulting file object for success, or FALSE in the event of an error.
+ * @return mixed
+ * Returns the resulting file object for success, or FALSE in the event of an
+ * error.
*
* @see file_unmanaged_move()
* @see hook_file_move()
@@ -581,14 +685,14 @@ function file_destination($destination, $replace) {
function file_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
$source = (object)$source;
- if ($filepath = file_unmanaged_move($source->filepath, $destination, $replace)) {
+ if ($uri = file_unmanaged_move($source->uri, $destination, $replace)) {
$delete_source = FALSE;
$file = clone $source;
- $file->filepath = $filepath;
+ $file->uri = $uri;
// If we are replacing an existing file re-use its database record.
if ($replace == FILE_EXISTS_REPLACE) {
- $existing_files = file_load_multiple(array(), array('filepath' => $filepath));
+ $existing_files = file_load_multiple(array(), array('uri' => $uri));
if (count($existing_files)) {
$existing = reset($existing_files);
$delete_source = TRUE;
@@ -617,12 +721,15 @@ function file_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
}
/**
- * Move a file to a new location without calling any hooks or making any
+ * Moves a file to a new location without calling any hooks or making any
* changes to the database.
*
- * @param $source
+ * Compatibility: only stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string $source
* A string specifying the file location of the original file.
- * @param $destination
+ * @param string $destination
* A string containing the destination that $source should be moved to. This
* can be a complete file path, a directory name or, if this value is omitted,
* Drupal's 'files' directory will be used.
@@ -632,8 +739,8 @@ function file_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
* - 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.
+ * @return mixed
+ * Returns the file path of the moved file, or FALSE in the event of an error.
*
* @see file_move()
*/
@@ -646,18 +753,18 @@ function file_unmanaged_move($source, $destination = NULL, $replace = FILE_EXIST
}
/**
- * Munge the filename as needed for security purposes.
+ * Munges the filename as needed for security purposes.
*
- * For instance the file name "exploit.php.pps" would become "exploit.php_.pps".
+ * For example, the file name "exploit.php.pps" would become "exploit.php_.pps".
*
- * @param $filename
+ * @param string $filename
* The name of a file to modify.
- * @param $extensions
+ * @param string $extensions
* A space separated list of extensions that should not be altered.
- * @param $alerts
+ * @param bool $alerts
* Whether alerts (watchdog, drupal_set_message()) should be displayed.
- * @return
- * $filename The potentially modified $filename.
+ * @return string
+ * Returns the potentially modified file name.
*/
function file_munge_filename($filename, $extensions, $alerts = TRUE) {
$original = $filename;
@@ -692,33 +799,45 @@ function file_munge_filename($filename, $extensions, $alerts = TRUE) {
}
/**
- * Undo the effect of upload_munge_filename().
+ * Reverses the effect of file_munge_filename().
*
- * @param $filename
+ * @param string $filename
* String with the filename to be unmunged.
- * @return
- * An unmunged filename string.
+ * @return string
+ * Returns the unmunged file name.
*/
function file_unmunge_filename($filename) {
return str_replace('_.', '.', $filename);
}
/**
- * Create a full file path from a directory and filename.
+ * Creates a full filepath from a directory and filename.
*
* If a file with the specified name already exists, an alternative will be
* used.
*
- * @param $basename
- * String filename
- * @param $directory
- * String directory
- * @return
- * File path consisting of $directory and a unique filename based off
- * of $basename.
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string $basename
+ * The filename.
+ * @param string $directory
+ * The directory.
+ * @return string
+ * Returns the filepath consisting of $directory and a unique filename
+ * based off of $basename.
*/
function file_create_filename($basename, $directory) {
- $destination = $directory . '/' . $basename;
+
+ // Are we dealing with a stream?
+ if (DrupalStreamWrapperRegistry::getValidStreamScheme($directory)) {
+ $separator = '';
+ }
+ else {
+ $separator = '/';
+ }
+
+ $destination = $directory . $separator . $basename;
if (file_exists($destination)) {
// Destination file already exists, generate an alternative.
@@ -734,7 +853,7 @@ function file_create_filename($basename, $directory) {
$counter = 0;
do {
- $destination = $directory . '/' . $name . '_' . $counter++ . $ext;
+ $destination = $directory . $separator . $name . '_' . $counter++ . $ext;
} while (file_exists($destination));
}
@@ -742,19 +861,19 @@ function file_create_filename($basename, $directory) {
}
/**
- * Delete a file and its database record.
+ * Deletes a file and its database record.
*
* If the $force parameter is not TRUE hook_file_references() will be called
* to determine if the file is being used by any modules. If the file is being
* used is the delete will be canceled.
*
- * @param $file
+ * @param object $file
* A file object.
- * @param $force
+ * @param bool $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, FALSE in the event of an error, or an array if the file
+ * Returns TRUE for success, FALSE in the event of an error, or an array if the file
* is being used by another module. The array keys are the module's name and
* the values are the number of references.
*
@@ -777,25 +896,28 @@ function file_delete($file, $force = FALSE) {
// 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_unmanaged_delete($file->filepath)) {
- db_delete('files')->condition('fid', $file->fid)->execute();
+ if (file_unmanaged_delete($file->uri)) {
+ db_delete('file')->condition('fid', $file->fid)->execute();
return TRUE;
}
return FALSE;
}
/**
- * Delete a file without calling any hooks or making any changes to the
+ * Deletes a file without calling any hooks or making any changes to the
* database.
*
* This function should be used when the file to be deleted does not have an
* entry recorded in the files table.
*
- * @param $path
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string$path
* A string containing a file path.
- * @return
- * TRUE for success or path does not exist, or FALSE in the event of an
- * error.
+ * @return bool
+ * Returns TRUE for success or the path does not exists, or FALSE in the
+ * event of an error.
*
* @see file_delete()
* @see file_unmanaged_delete_recursive()
@@ -821,7 +943,7 @@ function file_unmanaged_delete($path) {
}
/**
- * Recursively delete all files and directories in the specified filepath.
+ * Recursively deletes all files and directories in the specified filepath.
*
* If the specified path is a directory then the function will call itself
* recursively to process the contents. Once the contents have been removed the
@@ -832,11 +954,14 @@ function file_unmanaged_delete($path) {
*
* Note that this only deletes visible files with write permission.
*
- * @param $path
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string $path
* A string containing a file or directory path.
- * @return
- * TRUE for success or path does not exist, or FALSE in the event of an
- * error.
+ * @return bool
+ * Returns TRUE for success or path does not exist, or FALSE in the event
+ * of an error.
*
* @see file_unmanaged_delete()
*/
@@ -857,19 +982,19 @@ function file_unmanaged_delete_recursive($path) {
}
/**
- * Determine total disk space used by a single user or the whole filesystem.
+ * Determines total disk space used by a single user or the whole filesystem.
*
- * @param $uid
+ * @param int $uid
* 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.
+ * @return int
+ * Returns an integer containing the number of bytes used.
*/
function file_space_used($uid = NULL, $status = FILE_STATUS_PERMANENT) {
- $query = db_select('files', 'f');
+ $query = db_select('file', 'f');
// Use separate placeholders for the status to avoid a bug in some versions
// of PHP. @see http://drupal.org/node/352956
$query->where('f.status & :status1 = :status2', array(':status1' => $status, ':status2' => $status));
@@ -883,25 +1008,31 @@ function file_space_used($uid = NULL, $status = FILE_STATUS_PERMANENT) {
/**
* Saves a file upload to a new location.
*
- * The file will be added to the files table as a temporary file. Temporary
- * files are periodically cleaned. To make the file a permanent file call
- * assign the status and use file_save() to save it.
+ * The file will be added to the {file} table as a temporary file. Temporary
+ * files are periodically cleaned. To make the file a permanent file, assign
+ * the status and use file_save() to save the changes.
+ *
+ * Compatibility: source may be a normal path or stream, but the destination must
+ * always be a stream.
+ * @see http://drupal.org/node/515192
*
- * @param $source
+ * @param string $source
* A string specifying the name of the upload field to save.
* @param $validators
* An optional, associative array of callback functions used to validate the
* file. See file_validate() for a full discussion of the array format.
- * @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
+ * @param string $destination
+ * A string containing the location $source should be copied to within the temp directory.
+ * $destination can be a directory or directory and filename within the temp directory.
+ * If not provided, the temporary directory will be used, and the $replace flag will
+ * will be honored.
+ * @param bool $replace
* A boolean indicating whether an existing file of the same name in the
* destination directory should overwritten. A false value will generate a
* new, unique filename in the destination directory.
- * @return
- * An object containing the file information if the upload succeeded, FALSE
- * in the event of an error, or NULL if no file was uploaded.
+ * @return mixed
+ * Returns an object containing the file information if the upload succeeded,
+ * or FALSE in the event of an error, or NULL if no file was upload.
*/
function file_save_upload($source, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME) {
global $user;
@@ -958,14 +1089,14 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
$file->uid = $user->uid;
$file->status = 0;
$file->filename = file_munge_filename(trim(basename($_FILES['files']['name'][$source]), '.'), $extensions);
- $file->filepath = $_FILES['files']['tmp_name'][$source];
+ $file->uri = $_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')) {
$file->filemime = 'text/plain';
- $file->filepath .= '.txt';
+ $file->uri .= '.txt';
$file->filename .= '.txt';
}
@@ -976,7 +1107,7 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
}
$file->source = $source;
- $file->destination = file_destination(file_create_path($destination . '/' . $file->filename), $replace);
+ $file->destination = file_destination(file_create_path($destination . $file->filename), $replace);
// If file_destination() returns FALSE then $replace == FILE_EXISTS_ERROR and
// there's an existing file so we need to bail.
if ($file->destination === FALSE) {
@@ -1005,19 +1136,19 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
// 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)) {
+ $file->uri = $file->destination;
+ if (!move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->uri)) {
form_set_error($source, t('File upload error. Could not move uploaded file.'));
- watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->filepath));
+ watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->uri));
return FALSE;
}
// Set the permissions on the new file.
- drupal_chmod($file->filepath);
+ drupal_chmod($file->uri);
// If we are replacing an existing file re-use its database record.
if ($replace == FILE_EXISTS_REPLACE) {
- $existing_files = file_load_multiple(array(), array('filepath' => $file->filepath));
+ $existing_files = file_load_multiple(array(), array('uri' => $file->uri));
if (count($existing_files)) {
$existing = reset($existing_files);
$file->fid = $existing->fid;
@@ -1033,24 +1164,23 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
return FALSE;
}
-
/**
- * Check that a file meets the criteria specified by the validators.
+ * Checks that a file meets the criteria specified by the validators.
*
* After executing the validator callbacks specified hook_file_validate() will
* also be called to allow other modules to report errors about the file.
*
- * @param $file
+ * @param object $file
* A Drupal file object.
- * @param $validators
+ * @param array $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 file object. 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.
+ * @return string
+ * Returns an array containing validation error messages.
*
* @see hook_file_validate()
*/
@@ -1069,12 +1199,12 @@ function file_validate(&$file, $validators = array()) {
}
/**
- * Check for files with names longer than we can store in the database.
+ * Asserts that a filename is short enough to store in the database.
*
- * @param $file
+ * @param object $file
* A Drupal file object.
- * @return
- * An array. If the file name is too long, it will contain an error message.
+ * @return array
+ * Returns an array containing an error message if the filename is too long.
*/
function file_validate_name_length($file) {
$errors = array();
@@ -1089,15 +1219,15 @@ function file_validate_name_length($file) {
}
/**
- * Check that the filename ends with an allowed extension.
+ * Asserts that the filename ends with an allowed extension.
*
- * @param $file
+ * @param object $file
* A Drupal file object.
- * @param $extensions
+ * @param string $extensions
* A string with a space separated list of allowed extensions.
- * @return
- * An array. If the file extension is not allowed, it will contain an error
- * message.
+ * @return array
+ * Returns an array containing an error message if the file extension
+ * is not allowed.
*
* @see hook_file_validate()
*/
@@ -1112,21 +1242,21 @@ function file_validate_extensions($file, $extensions) {
}
/**
- * Check that the file's size is below certain limits.
+ * Asserts that the file's size is below certain limits.
*
* This check is not enforced for the user #1.
*
- * @param $file
+ * @param object $file
* A Drupal file object.
- * @param $file_limit
+ * @param int $file_limit
* An integer specifying the maximum file size in bytes. Zero indicates that
* no limit should be enforced.
- * @param $user_limit
+ * @param int $user_limit
* 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.
+ * @return array
+ * Returns an array containing an error message if the file size exceeds
+ * limits.
*
* @see hook_file_validate()
*/
@@ -1150,19 +1280,19 @@ function file_validate_size($file, $file_limit = 0, $user_limit = 0) {
}
/**
- * Check that the file is recognized by image_get_info() as an image.
+ * Checks that the file is recognized by image_get_info() as an image.
*
- * @param $file
+ * @param object $file
* A Drupal file object.
- * @return
- * An array. If the file is not an image, it will contain an error message.
+ * @return array
+ * Returns an array containing an error message if the file is not an image.
*
* @see hook_file_validate()
*/
function file_validate_is_image($file) {
$errors = array();
- $info = image_get_info($file->filepath);
+ $info = image_get_info($file->uri);
if (!$info || empty($info['extension'])) {
$errors[] = t('Only JPEG, PNG and GIF images are allowed.');
}
@@ -1171,26 +1301,25 @@ function file_validate_is_image($file) {
}
/**
- * If the file is an image verify that its dimensions are within the specified
- * maximum and minimum dimensions.
+ * Asserts that the dimensions of an image are within the specified parameters.
*
- * Non-image files will be ignored. If a image toolkit is available the image
+ * Non-image files will be ignored. If an image toolkit is available the image
* will be scalled to fit within the desired maximum dimensions.
*
- * @param $file
+ * @param object $file
* A Drupal file object. This function may resize the file affecting its
* size.
- * @param $maximum_dimensions
+ * @param string $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
+ * @param string $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.
- * @return
- * An array. If the file is an image and did not meet the requirements, it
- * will contain an error message.
+ * @return array
+ * Returns an array containing an error message if the file is an image and
+ * exceeded the specified paramaters.
*
* @see hook_file_validate()
*/
@@ -1198,13 +1327,13 @@ function file_validate_image_resolution($file, $maximum_dimensions = 0, $minimum
$errors = array();
// Check first that the file is an image.
- if ($info = image_get_info($file->filepath)) {
+ if ($info = image_get_info($file->uri)) {
if ($maximum_dimensions) {
// Check that it is smaller than the given dimensions.
list($width, $height) = explode('x', $maximum_dimensions);
if ($info['width'] > $width || $info['height'] > $height) {
// Try to resize the image to fit the dimensions.
- if ($image = image_load($file->filepath)) {
+ if ($image = image_load($file->uri)) {
image_scale($image, $width, $height);
image_save($image);
$file->filesize = $image->info['file_size'];
@@ -1229,11 +1358,14 @@ function file_validate_image_resolution($file, $maximum_dimensions = 0, $minimum
}
/**
- * Save a string to the specified destination and create a database file entry.
+ * Saves a string to the specified destination and creates a database file entry.
*
- * @param $data
+ * Compatibility: only stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string $data
* A string containing the contents of the file.
- * @param $destination
+ * @param string $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.
@@ -1245,26 +1377,26 @@ function file_validate_image_resolution($file, $maximum_dimensions = 0, $minimum
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
* unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
- * @return
- * A file object, or FALSE on error.
+ * @return mixed
+ * Returns a file object, or FALSE on error.
*
* @see file_unmanaged_save_data()
*/
function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
global $user;
- if ($filepath = file_unmanaged_save_data($data, $destination, $replace)) {
+ if ($uri = file_unmanaged_save_data($data, $destination, $replace)) {
// Create a file object.
$file = new stdClass();
$file->fid = NULL;
- $file->filepath = $filepath;
- $file->filename = basename($filepath);
- $file->filemime = file_get_mimetype($file->filepath);
+ $file->uri = $uri;
+ $file->filename = basename($uri);
+ $file->filemime = file_get_mimetype($file->uri);
$file->uid = $user->uid;
$file->status |= FILE_STATUS_PERMANENT;
// If we are replacing an existing file re-use its database record.
if ($replace == FILE_EXISTS_REPLACE) {
- $existing_files = file_load_multiple(array(), array('filepath' => $filepath));
+ $existing_files = file_load_multiple(array(), array('uri' => $uri));
if (count($existing_files)) {
$existing = reset($existing_files);
$file->fid = $existing->fid;
@@ -1283,15 +1415,15 @@ function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAM
}
/**
- * Save a string to the specified destination without calling any hooks or
+ * Saves a string to the specified destination without calling any hooks or
* making any changes to the database.
*
* This function is identical to file_save_data() except the file will not be
- * saved to the files table and none of the file_* hooks will be called.
+ * saved to the {file} table and none of the file_* hooks will be called.
*
- * @param $data
+ * @param string $data
* A string containing the contents of the file.
- * @param $destination
+ * @param string $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.
@@ -1301,8 +1433,8 @@ function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAM
* - 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.
+ * @return mixed
+ * Returns a string with the path of the resulting file, or FALSE on error.
*
* @see file_save_data()
*/
@@ -1319,13 +1451,12 @@ function file_unmanaged_save_data($data, $destination = NULL, $replace = FILE_EX
}
/**
- * Transfer file using HTTP to client. Pipes a file through Drupal to the
- * client.
+ * Pipes a file through Drupal to the client using HTTP.
*
- * @param $source
+ * @param string $source
* String specifying the file path to transfer.
- * @param $headers
- * An array of HTTP headers to send along with file.
+ * @param array
+ * Returns an array of HTTP headers to send along with the file.
*/
function file_transfer($source, $headers) {
if (ob_get_level()) {
@@ -1353,7 +1484,7 @@ function file_transfer($source, $headers) {
}
/**
- * Menu handler for private file transfers.
+ * Menu handler for private file transfers [private://].
*
* Call modules that implement hook_file_download() to find out if a file is
* accessible and what headers it should be transferred with. If a module
@@ -1361,16 +1492,18 @@ function file_transfer($source, $headers) {
* returned headers the download will start with the returned headers. If no
* modules respond drupal_not_found() will be returned.
*
+ * @see http://drupal.org/node/515192
+ *
* @see hook_file_download()
*/
function file_download() {
// Merge remainder of arguments from GET['q'], into relative file path.
- $args = func_get_args();
- $filepath = implode('/', $args);
+ $args = func_get_args();
+ $filepath = SCHEME_PRIVATE . implode('/', $args);
// Maintain compatibility with old ?file=paths saved in node bodies.
if (isset($_GET['file'])) {
- $filepath = $_GET['file'];
+ $filepath = SCHEME_PRIVATE . $_GET['file'];
}
if (file_exists(file_create_path($filepath))) {
@@ -1394,11 +1527,14 @@ function file_download() {
* prevents hidden files and directories (such as SVN working directories)
* from being scanned.
*
- * @param $dir
+ * Compatibility: only stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param string $dir
* The base directory for the scan, without trailing slash.
* @param $mask
* The preg_match() regular expression of the files to find.
- * @param $options
+ * @param array $options
* An associative array of additional options, with the following keys:
* - 'nomask'
* The preg_match() regular expression of the files to ignore. Defaults to
@@ -1416,11 +1552,11 @@ function file_download() {
* extension. Defaults to 'filepath'.
* - 'min_depth'
* Minimum depth of directories to return files from. Defaults to 0.
- * @param $depth
+ * @param int $depth
* 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
+ * @return array
+ * Returns an associative array (keyed on the provided key) of objects with
* 'filepath', 'filename', and 'name' members corresponding to the
* matching files.
*/
@@ -1430,32 +1566,33 @@ function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
'nomask' => '/(\.\.?|CVS)$/',
'callback' => 0,
'recurse' => TRUE,
- 'key' => 'filepath',
+ 'key' => 'uri',
'min_depth' => 0,
);
- $options['key'] = in_array($options['key'], array('filepath', 'filename', 'name')) ? $options['key'] : 'filepath';
+ $options['key'] = in_array($options['key'], array('uri', 'filename', 'name')) ? $options['key'] : 'uri';
$files = array();
if (is_dir($dir) && $handle = opendir($dir)) {
while (FALSE !== ($filename = readdir($handle))) {
if (!preg_match($options['nomask'], $filename) && $filename[0] != '.') {
- $filepath = "$dir/$filename";
- if (is_dir($filepath) && $options['recurse']) {
+ $uri = "$dir/$filename";
+ DrupalStreamWrapperRegistry::normalizeUri($uri);
+ if (is_dir($uri) && $options['recurse']) {
// Give priority to files in this folder by merging them in after any subdirectory files.
- $files = array_merge(file_scan_directory($filepath, $mask, $options, $depth + 1), $files);
+ $files = array_merge(file_scan_directory($uri, $mask, $options, $depth + 1), $files);
}
elseif ($depth >= $options['min_depth'] && preg_match($mask, $filename)) {
// Always use this match over anything already set in $files with the
// same $$options['key'].
$file = (object) array(
- 'filepath' => $filepath,
+ 'uri' => $uri,
'filename' => $filename,
'name' => pathinfo($filename, PATHINFO_FILENAME),
);
$key = $options['key'];
$files[$file->$key] = $file;
if ($options['callback']) {
- $options['callback']($filepath);
+ $options['callback']($uri);
}
}
}
@@ -1470,51 +1607,42 @@ function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
/**
* Determine the default temporary directory.
*
+ * Warning! This function will be deprecated in the near future.
+ * Please use file_directory_path('temp') when possible.
+ *
* @return
* A string containing a temp directory.
*/
function file_directory_temp() {
- $temporary_directory = variable_get('file_directory_temp');
-
- if (is_null($temporary_directory)) {
- $directories = array();
-
- // Has PHP been set with an upload_tmp_dir?
- if (ini_get('upload_tmp_dir')) {
- $directories[] = ini_get('upload_tmp_dir');
- }
-
- // Operating system specific dirs.
- if (substr(PHP_OS, 0, 3) == 'WIN') {
- $directories[] = 'c:/windows/temp';
- $directories[] = 'c:/winnt/temp';
- }
- else {
- $directories[] = '/tmp';
- }
-
- foreach ($directories as $directory) {
- if (!$temporary_directory && is_dir($directory)) {
- $temporary_directory = $directory;
- }
- }
-
- // 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);
- }
-
- return $temporary_directory;
+ return file_directory_path('temp');
}
/**
- * Determine the default 'files' directory.
+ * Determines the base path of a given wrapper.
+ *
+ * This function will return the base path of a stream by providing a scheme.
+ * A stream is referenced as: scheme://target.
+ * For example, a scheme of public might return sites/all/default/files
+ * or temp might return /tmp.
+ *
+ * Compatibility: only stream wrappers.
+ * @see http://drupal.org/node/515192
*
+ * @param string $scheme
+ * A string representing the scheme of a stream. For legacy code, the public
+ * wrapper is assumed if this is not provided.
+ * A stream is referenced as: scheme://target.
* @return
- * A string containing the path to Drupal's 'files' directory.
+ * A string containing the base path of a stream. FALSE is returned if the scheme
+ * is invalid or a wrapper could not be instantiated.
*/
-function file_directory_path() {
- return variable_get('file_directory_path', conf_path() . '/files');
+function file_directory_path($scheme = SCHEME_PUBLIC) {
+ if (isset($scheme) && $wrapper = DrupalStreamWrapperRegistry::getInstanceByScheme($scheme)) {
+ return $wrapper->getDirectoryPath();
+ }
+ else {
+ return FALSE;
+ }
}
/**
@@ -1535,11 +1663,11 @@ function file_directory_strip($path) {
}
/**
- * Determine the maximum file upload size by querying the PHP settings.
+ * Determines 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
+ * @return int
+ * Returns file size limit in bytes based on the PHP upload_max_filesize
+ * and post_max_size directives.
*/
function file_upload_max_size() {
static $max_size = -1;
diff --git includes/install.inc includes/install.inc
index 6b19741..3438a4b 100644
--- includes/install.inc
+++ includes/install.inc
@@ -216,9 +216,9 @@ function drupal_detect_database_types() {
// file for the driver explicitly.
foreach (file_scan_directory(DRUPAL_ROOT . '/includes/database', '/^[a-z]*$/i', array('recurse' => FALSE)) as $file) {
- include_once "{$file->filepath}/install.inc";
- include_once "{$file->filepath}/database.inc";
- $drivers[$file->filename] = $file->filepath;
+ include_once "{$file->uri}/install.inc";
+ include_once "{$file->uri}/database.inc";
+ $drivers[$file->filename] = $file->uri;
}
foreach ($drivers as $driver => $file) {
@@ -863,7 +863,7 @@ function st($string, $args = array()) {
$filename = 'profiles/' . $profile . '/translations/' . $install_locale . '.po';
if (file_exists(DRUPAL_ROOT . '/' . $filename)) {
require_once DRUPAL_ROOT . '/includes/locale.inc';
- $file = (object) array('filepath' => $filename);
+ $file = (object) array('uri' => $filename);
_locale_import_read_po('mem-store', $file);
$locale_strings = _locale_import_one_string('mem-report');
}
@@ -914,7 +914,7 @@ function drupal_check_profile($profile) {
// Collect requirement testing results
$requirements = array();
foreach ($installs as $install) {
- require_once DRUPAL_ROOT . '/' . $install->filepath;
+ require_once DRUPAL_ROOT . '/' . $install->uri;
$function = $install->name . '_requirements';
if (function_exists($function)) {
$requirements = array_merge($requirements, $function('install'));
@@ -954,7 +954,7 @@ function drupal_check_module($module) {
// Include install file
$install = drupal_get_install_files(array($module));
if (isset($install[$module])) {
- require_once DRUPAL_ROOT . '/' . $install[$module]->filepath;
+ require_once DRUPAL_ROOT . '/' . $install[$module]->uri;
// Check requirements
$requirements = module_invoke($module, 'requirements', 'install');
diff --git includes/locale.inc includes/locale.inc
index f756ea9..eaf32cf 100644
--- includes/locale.inc
+++ includes/locale.inc
@@ -1225,7 +1225,7 @@ function _locale_import_po($file, $langcode, $mode, $group = NULL) {
*/
function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL, $group = 'default') {
- $fd = fopen($file->filepath, "rb"); // File will get closed by PHP on return
+ $fd = fopen($file->uri, "rb"); // File will get closed by PHP on return
if (!$fd) {
_locale_import_message('The translation import failed, because the file %filename could not be read.', $file);
return FALSE;
@@ -2652,7 +2652,7 @@ function _locale_batch_build($files, $finished = NULL, $components = array()) {
$operations = array();
foreach ($files as $file) {
// We call _locale_batch_import for every batch operation.
- $operations[] = array('_locale_batch_import', array($file->filepath));
+ $operations[] = array('_locale_batch_import', array($file->uri));
}
$batch = array(
'operations' => $operations,
@@ -2684,7 +2684,7 @@ function _locale_batch_import($filepath, &$context) {
// The filename is either {langcode}.po or {prefix}.{langcode}.po, so
// we can extract the language code to use for the import from the end.
if (preg_match('!(/|\.)([^\./]+)\.po$!', $filepath, $langcode)) {
- $file = (object) array('filename' => basename($filepath), 'filepath' => $filepath);
+ $file = (object) array('filename' => basename($filepath), 'uri' => $filepath);
_locale_import_read_po('db-store', $file, LOCALE_IMPORT_KEEP, $langcode[2]);
$context['results'][] = $filepath;
}
diff --git includes/module.inc includes/module.inc
index 1ffdf2f..a7da6e5 100644
--- includes/module.inc
+++ includes/module.inc
@@ -501,7 +501,7 @@ function drupal_required_modules() {
$files = drupal_system_listing('/\.info$/', 'modules', 'name', 0);
$required = array();
foreach ($files as $name => $file) {
- $info = drupal_parse_info_file($file->filepath);
+ $info = drupal_parse_info_file($file->uri);
if (!empty($info) && !empty($info['required']) && $info['required']) {
$required[] = $name;
}
diff --git includes/registry.inc includes/registry.inc
index 77948d4..e0820ea 100644
--- includes/registry.inc
+++ includes/registry.inc
@@ -43,7 +43,7 @@ function _registry_rebuild() {
// Get the list of files we are going to parse.
$files = array();
foreach ($modules as &$module) {
- $dir = dirname($module->filepath);
+ $dir = dirname($module->uri);
// Store the module directory for use in hook_registry_files_alter().
$module->dir = $dir;
diff --git includes/theme.inc includes/theme.inc
index 02779ff..4467a05 100644
--- includes/theme.inc
+++ includes/theme.inc
@@ -967,7 +967,7 @@ function drupal_find_theme_templates($cache, $extension, $path) {
$files = drupal_system_listing($regex, $path, 'name', 0);
foreach ($files as $template => $file) {
// Ignore sub-theme templates for the current theme.
- if (strpos($file->filepath, str_replace($subtheme_paths, '', $file->filepath)) !== 0) {
+ if (strpos($file->uri, str_replace($subtheme_paths, '', $file->uri)) !== 0) {
continue;
}
// Chop off the remaining extensions if there are any. $template already
@@ -982,7 +982,7 @@ function drupal_find_theme_templates($cache, $extension, $path) {
if (isset($cache[$hook])) {
$templates[$hook] = array(
'template' => $template,
- 'path' => dirname($file->filepath),
+ 'path' => dirname($file->uri),
);
}
// Ensure that the pattern is maintained from base themes to its sub-themes.
@@ -1008,7 +1008,7 @@ function drupal_find_theme_templates($cache, $extension, $path) {
// Put the underscores back in for the hook name and register this pattern.
$templates[strtr($file, '-', '_')] = array(
'template' => $file,
- 'path' => dirname($files[$match]->filepath),
+ 'path' => dirname($files[$match]->uri),
'arguments' => $info['arguments'],
);
}
diff --git install.php install.php
index 472edfc..35381c1 100644
--- install.php
+++ install.php
@@ -421,7 +421,7 @@ function install_select_profile() {
// Don't need to choose profile if only one available.
if (sizeof($profiles) == 1) {
$profile = array_pop($profiles);
- require_once $profile->filepath;
+ require_once $profile->uri;
return $profile->name;
}
elseif (sizeof($profiles) > 1) {
@@ -453,7 +453,7 @@ function install_select_profile_form(&$form_state, $profile_files) {
$names = array();
foreach ($profile_files as $profile) {
- include_once DRUPAL_ROOT . '/' . $profile->filepath;
+ include_once DRUPAL_ROOT . '/' . $profile->uri;
$details = install_profile_info($profile->name);
$profiles[$profile->name] = $details;
diff --git modules/aggregator/aggregator.admin.inc modules/aggregator/aggregator.admin.inc
index 7397c5d..6165ffb 100644
--- modules/aggregator/aggregator.admin.inc
+++ modules/aggregator/aggregator.admin.inc
@@ -297,7 +297,7 @@ function aggregator_form_opml_validate($form, &$form_state) {
function aggregator_form_opml_submit($form, &$form_state) {
$data = '';
if ($file = file_save_upload('upload')) {
- $data = file_get_contents($file->filepath);
+ $data = file_get_contents($file->uri);
}
else {
$response = drupal_http_request($form_state['values']['remote']);
diff --git modules/aggregator/aggregator.test modules/aggregator/aggregator.test
index 820357e..a2a151c 100644
--- modules/aggregator/aggregator.test
+++ modules/aggregator/aggregator.test
@@ -228,7 +228,8 @@ EOF;
* Path to empty OPML file.
*/
function getEmptyOpml() {
- $opml = <<
@@ -236,10 +237,9 @@ EOF;