diff --git includes/bootstrap.inc includes/bootstrap.inc
index be24c2e..c75096f 100644
--- includes/bootstrap.inc
+++ includes/bootstrap.inc
@@ -656,8 +656,8 @@ function drupal_get_filename($type, $name, $filename = NULL) {
if (drupal_function_exists('drupal_system_listing')) {
$matches = drupal_system_listing($mask, $dir, 'name', 0);
- if (!empty($matches[$name]->filepath)) {
- $files[$type][$name] = $matches[$name]->filepath;
+ if (!empty($matches[$name]->uri)) {
+ $files[$type][$name] = $matches[$name]->uri;
}
}
}
diff --git includes/common.inc includes/common.inc
index 116c947..0b9b566 100644
--- includes/common.inc
+++ includes/common.inc
@@ -2560,8 +2560,8 @@ function drupal_get_css($css = NULL) {
}
$preprocess_css = (variable_get('preprocess_css', FALSE) && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update'));
- $directory = file_directory_path();
- $is_writable = is_dir($directory) && is_writable($directory) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC);
+ $directory = file_directory_path('public');
+ $is_writable = is_dir($directory) && is_writable($directory);
// A dummy query-string is added to filenames, to gain control over
// browser-caching. The string changes on every update or full cache
@@ -2601,7 +2601,7 @@ function drupal_get_css($css = NULL) {
case 'file':
// Depending on whether aggregation is desired, include the file.
if (!$item['preprocess'] || !($is_writable && $preprocess_css)) {
- $rendered_css[] = '';
+ $rendered_css[] = '';
}
else {
$preprocess_items[$item['media']][] = $item;
@@ -2626,8 +2626,8 @@ function drupal_get_css($css = NULL) {
// Prefix filename to prevent blocking by firewalls which reject files
// starting with "ad*".
$filename = 'css_' . md5(serialize($items) . $query_string) . '.css';
- $preprocess_file = drupal_build_css_cache($items, $filename);
- $rendered_css['preprocess'] .= '' . "\n";
+ $preprocess_file = file_external_url(drupal_build_css_cache($items, $filename));
+ $rendered_css['preprocess'] .= '' . "\n";
}
}
// Enclose the inline CSS with the style tag if required.
@@ -2653,9 +2653,8 @@ function drupal_build_css_cache($css, $filename) {
$data = '';
// Create the css/ within the files folder.
- $csspath = file_create_path('css');
- file_check_directory($csspath, FILE_CREATE_DIRECTORY);
-
+ $csspath = 'public://css';
+ file_prepare_directory($csspath, FILE_CREATE_DIRECTORY);
if (!file_exists($csspath . '/' . $filename)) {
// Build aggregate CSS file.
foreach ($css as $stylesheet) {
@@ -2797,7 +2796,7 @@ function _drupal_load_stylesheet($matches) {
* Delete all cached CSS files.
*/
function drupal_clear_css_cache() {
- file_scan_directory(file_create_path('css'), '/.*/', array('callback' => 'file_unmanaged_delete'));
+ file_scan_directory('public://css', '/.*/', array('callback' => 'file_unmanaged_delete'));
}
/**
@@ -3039,8 +3038,8 @@ function drupal_get_js($scope = 'header', $javascript = NULL) {
$no_preprocess = '';
$files = array();
$preprocess_js = (variable_get('preprocess_js', FALSE) && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update'));
- $directory = file_directory_path();
- $is_writable = is_dir($directory) && is_writable($directory) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC);
+ $directory = file_directory_path('public');
+ $is_writable = is_dir($directory) && is_writable($directory);
// A dummy query-string is added to filenames, to gain control over
// browser-caching. The string changes on every update or full cache
@@ -3072,7 +3071,7 @@ function drupal_get_js($scope = 'header', $javascript = NULL) {
case 'file':
if (!$item['preprocess'] || !$is_writable || !$preprocess_js) {
- $no_preprocess .= '\n";
+ $no_preprocess .= '\n";
}
else {
$files[$item['data']] = $item;
@@ -3091,8 +3090,8 @@ function drupal_get_js($scope = 'header', $javascript = NULL) {
// Prefix filename to prevent blocking by firewalls which reject files
// starting with "ad*".
$filename = 'js_' . md5(serialize($files) . $query_string) . '.js';
- $preprocess_file = drupal_build_js_cache($files, $filename);
- $preprocessed .= '' . "\n";
+ $preprocess_file = file_external_url(drupal_build_js_cache($files, $filename));
+ $preprocessed .= '' . "\n";
}
// Keep the order of JS files consistent as some are preprocessed and others are not.
@@ -3363,8 +3362,8 @@ function drupal_build_js_cache($files, $filename) {
$contents = '';
// Create the js/ within the files folder.
- $jspath = file_create_path('js');
- file_check_directory($jspath, FILE_CREATE_DIRECTORY);
+ $jspath = 'public://js';
+ file_prepare_directory($jspath, FILE_CREATE_DIRECTORY);
if (!file_exists($jspath . '/' . $filename)) {
// Build aggregate JS file.
@@ -3386,7 +3385,7 @@ function drupal_build_js_cache($files, $filename) {
* Delete all cached JS files.
*/
function drupal_clear_js_cache() {
- file_scan_directory(file_create_path('js'), '/.*/', array('callback' => 'file_unmanaged_delete'));
+ file_scan_directory('public://js', '/.*/', array('callback' => 'file_unmanaged_delete'));
variable_set('javascript_parsed', array());
}
diff --git includes/file.inc includes/file.inc
index fc568a8..b686c68 100644
--- includes/file.inc
+++ includes/file.inc
@@ -24,7 +24,7 @@ require_once DRUPAL_ROOT . '/includes/stream_wrappers.inc';
* - 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
@@ -35,28 +35,12 @@ require_once DRUPAL_ROOT . '/includes/stream_wrappers.inc';
*/
/**
- * Flag to indicate that the 'public' file download method is enabled.
- *
- * When using this method, files are available from a regular HTTP request,
- * which provides no additional access restrictions.
- */
-define('FILE_DOWNLOADS_PUBLIC', 1);
-
-/**
- * Flag to indicate that the 'private' file download method is enabled.
- *
- * When using this method, all file requests are served by Drupal, during which
- * access-control checking can be performed.
- */
-define('FILE_DOWNLOADS_PRIVATE', 2);
-
-/**
- * Flag used by file_check_directory() -- create directory if not present.
+ * Flag used by file_prepare_directory() -- create directory if not present.
*/
define('FILE_CREATE_DIRECTORY', 1);
/**
- * Flag used by file_check_directory() -- file permissions may be changed.
+ * Flag used by file_prepare_directory() -- file permissions may be changed.
*/
define('FILE_MODIFY_PERMISSIONS', 2);
@@ -220,6 +204,8 @@ function file_uri_target($uri) {
*
* @param $uri
* String reference containing the URI to normalize.
+ * @return
+ * The normalized URI.
*/
function file_stream_wrapper_uri_normalize($uri) {
$scheme = file_uri_scheme($uri);
@@ -299,56 +285,42 @@ function file_stream_wrapper_get_instance_by_scheme($scheme) {
}
/**
- * 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.
- */
-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));
- }
-}
-
-/**
- * Make sure the destination is a complete path and resides in the file system
- * directory, if it is not prepend the file system directory.
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
*
- * @param $destination
- * A string containing the path to verify. If this value is omitted, Drupal's
- * 'files' directory will be used.
+ * @param $uri
+ * The URI to for which we need an external URL.
* @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).
+ * Returns a string containing a URL that may be used to access the file.
+ * 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_path($destination = NULL) {
- $file_path = file_directory_path();
- if (is_null($destination)) {
- return $file_path;
- }
- // 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.
- elseif (file_check_location($destination, file_directory_temp())) {
- return $destination;
- }
- // Not found, try again with prefixed directory path.
- elseif (file_check_location($file_path . '/' . $destination, $file_path)) {
- return $file_path . '/' . $destination;
- }
- // File not found.
- return FALSE;
+function file_external_url($uri) {
+ $scheme = file_uri_scheme($uri);
+
+ if (!$scheme) {
+ // If this is not a properly formatted stream return the URI with the base url prepended.
+ return $GLOBALS['base_url'] . '/' . $uri;
+ }
+ elseif ($scheme == 'http' || $scheme == 'https') {
+ // Check for http so that we don't have to implement getExternalUrl() for the http wrapper.
+ return $uri;
+ }
+ else {
+ // Attempt to return an external URL using the appropriate wrapper.
+ if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {
+ return $wrapper->getExternalUrl();
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ // @todo Implement CDN integration hook stuff in this function.
+ // @see http://drupal.org/node/499156
}
/**
@@ -357,126 +329,90 @@ function file_create_path($destination = NULL) {
* 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.
- * @param $mode
+ * @param &$directory
+ * A string reference containing the name of a directory path or URI. A
+ * trailing slash will be trimmed from a path.
+ * @param $options
* 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.
+ * TRUE if the directory exists (or was created) and is writable. FALSE
+ * otherwise.
*/
-function file_check_directory(&$directory, $mode = 0, $form_item = NULL) {
- $directory = rtrim($directory, '/\\');
+function file_prepare_directory(&$directory, $options = FILE_MODIFY_PERMISSIONS) {
+ if (!file_stream_wrapper_valid_scheme(file_uri_scheme($directory))) {
+ // Only trim if we're not dealing with a stream.
+ $directory = rtrim($directory, '/\\');
+ }
// Check if directory exists.
if (!is_dir($directory)) {
// Let mkdir() recursively create directories and use the default directory
// permissions.
- if (($mode & FILE_CREATE_DIRECTORY) && @mkdir($directory, variable_get('file_chmod_directory', 0775), TRUE)) {
- drupal_chmod($directory);
- }
- else {
- if ($form_item) {
- form_set_error($form_item, t('The directory %directory does not exist.', array('%directory' => $directory)));
- watchdog('file system', 'The directory %directory does not exist.', array('%directory' => $directory), WATCHDOG_ERROR);
- }
- return FALSE;
+ if (($options & FILE_CREATE_DIRECTORY) && @drupal_mkdir($directory, NULL, TRUE)) {
+ return drupal_chmod($directory);
}
+ return FALSE;
}
-
- // Check to see if the directory is writable.
- if (!is_writable($directory)) {
- // If not able to modify permissions, or if able to, but chmod
- // fails, return false.
- if (!$mode || (($mode & FILE_MODIFY_PERMISSIONS) && !drupal_chmod($directory))) {
- 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;
- }
+ // The directory exists, so check to see if it is writable.
+ $writable = is_writable($directory);
+ if (!$writable && ($options & FILE_MODIFY_PERMISSIONS)) {
+ return drupal_chmod($directory);
}
- if ((file_directory_path() == $directory || file_directory_temp() == $directory) && !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");
- }
- else {
- $variables = array('%directory' => $directory, '!htaccess' => ' ' . nl2br(check_plain($htaccess_lines)));
- form_set_error($form_item, t("Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: !htaccess", $variables));
- watchdog('security', "Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: !htaccess", $variables, WATCHDOG_ERROR);
- }
- }
-
- return TRUE;
+ return $writable;
}
/**
- * Checks path to see if it 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.
+ * If missing, create a .htaccess file in each Drupal files directory.
*/
-function file_check_path(&$path) {
- // Check if path is a directory.
- if (file_check_directory($path)) {
- return '';
- }
-
- // Check if path is a possible dir/file.
- $filename = basename($path);
- $path = dirname($path);
- if (file_check_directory($path)) {
- return $filename;
- }
-
- return FALSE;
+function file_ensure_htaccess() {
+ file_create_htaccess('public://', FALSE);
+ file_create_htaccess('private://', TRUE);
+ file_create_htaccess('temporary://', TRUE);
}
/**
- * Check if a file is really located inside $directory.
+ * Creates an .htaccess file in the given directory.
*
- * This should be used to make sure a file specified 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');
- * @endcode
- *
- * @param $source
- * A string set to the file to check.
* @param $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.
+ * The directory.
+ * @param $private
+ * FALSE indicates that $directory should be an open and public directory.
+ * The default is TRUE which indicates a private and protected directory.
*/
-function file_check_location($source, $directory = '') {
- $check = realpath($source);
- if ($check) {
- $source = $check;
+function file_create_htaccess($directory, $private = TRUE) {
+ if (file_uri_scheme($directory)) {
+ $directory = file_stream_wrapper_uri_normalize($directory);
}
else {
- // This file does not yet exist.
- $source = realpath(dirname($source)) . '/' . basename($source);
+ $directory = rtrim($directory, '/\\');
}
- $directory = realpath($directory);
- if ($directory && strpos($source, $directory) !== 0) {
- return FALSE;
+ $htaccess_path = $directory . '/.htaccess';
+
+ if (file_exists($htaccess_path)) {
+ // Short circuit if the .htaccess file already exists.
+ return;
+ }
+
+ if ($private) {
+ // Private .htaccess file.
+ $htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nDeny from all\nOptions None\nOptions +FollowSymLinks";
+ }
+ else {
+ // Public .htaccess file.
+ $htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks";
+ }
+
+ // Write the .htaccess file.
+ if (file_put_contents($htaccess_path, $htaccess_lines)) {
+ drupal_chmod($htaccess_path, 0444);
+ }
+ else {
+ $variables = array('%directory' => $directory, '!htaccess' => ' ' . nl2br(check_plain($htaccess_lines)));
+ watchdog('security', "Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: !htaccess", $variables, WATCHDOG_ERROR);
}
- return $source;
}
/**
@@ -494,7 +430,7 @@ function file_check_location($source, $directory = '') {
* @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) {
@@ -553,15 +489,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);
}
@@ -587,9 +523,9 @@ function file_save($file) {
* @param $source
* A file object.
* @param $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.
+ * 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 scheme will be used, "public://".
* @param $replace
* Replace behavior when the destination file already exists:
* - FILE_EXISTS_REPLACE - Replace the existing file. If a managed file with
@@ -607,14 +543,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;
@@ -623,7 +559,7 @@ function file_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
}
// If we are renaming around an existing file (rather than a directory),
// use its basename for the filename.
- else if ($replace == FILE_EXISTS_RENAME && is_file(file_create_path($destination))) {
+ elseif ($replace == FILE_EXISTS_RENAME && is_file($destination)) {
$file->filename = basename($destination);
}
@@ -650,11 +586,10 @@ function file_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
* replace the file or rename the file based on the $replace parameter.
*
* @param $source
- * A string specifying the file location of the original file.
+ * A string specifying the filepath or URI of the original file.
* @param $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.
+ * A URI containing the destination that $source should be copied to. If
+ * NULL the default scheme will be used as the destination.
* @param $replace
* Replace behavior when the destination file already exists:
* - FILE_EXISTS_REPLACE - Replace the existing file.
@@ -670,38 +605,55 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
$original_source = $source;
$original_destination = $destination;
- $source = realpath($source);
+ // Assert that the source file actually exists.
+ $source = drupal_realpath($source);
if (!file_exists($source)) {
+ // @todo Replace drupal_set_message() calls with exceptions instead.
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' => $original_source)), 'error');
return FALSE;
}
- $proposed_destination = file_create_path($destination);
- $directory = $proposed_destination;
- $basename = file_check_path($directory);
+ // Build a destination URI if necessary.
+ if (!isset($destination)) {
+ $destination = file_build_uri(basename($source));
+ }
- // 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. This is often caused by a problem with file or directory permissions.', array('%file' => $original_source, '%directory' => empty($original_destination) ? $proposed_destination : $original_destination)), 'error');
- return FALSE;
+ // Assert that the destination contains a valid stream.
+ $destination_scheme = file_uri_scheme($destination);
+ if (!$destination_scheme || !file_stream_wrapper_valid_scheme($destination_scheme)) {
+ drupal_set_message(t('The specified file %file could not be copied, because the destination %destination is invalid. This is often caused by improper use of file_unmanaged_copy() or a missing stream wrapper.', array('%file' => $original_source, '%destination' => $destination)), 'error');
}
- // 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);
+ // Prepare the destination directory.
+ if (file_prepare_directory($destination)) {
+ // The destination is already a directory, so append the source basename.
+ $destination = file_stream_wrapper_uri_normalize($destination . '/' . basename($source));
+ }
+ else {
+ // Perhaps $destination is a dir/file?
+ $dirname = drupal_dirname($destination);
+ if (!file_prepare_directory($dirname)) {
+ // The destination is not valid.
+ drupal_set_message(t('The specified file %file could not be copied, because the destination %directory is not properly configured. This is often caused by a problem with file or directory permissions.', array('%file' => $original_source, '%directory' => $destination)), 'error');
+ return FALSE;
+ }
+ }
+ // Determine whether or not we can perform this operation based on overwrite rules.
+ $destination = file_destination($destination, $replace);
if ($destination === FALSE) {
- drupal_set_message(t('The file %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $source, '%directory' => $proposed_destination)), 'error');
+ drupal_set_message(t('The file %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $source, '%directory' => $destination)), 'error');
return FALSE;
}
- // 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)) {
+
+ // Assert that the source and destination filenames are not the same.
+ 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;
}
+ // Make sure the .htaccess files are present.
+ file_ensure_htaccess();
+ // Perform the copy operation.
if (!@copy($source, $destination)) {
drupal_set_message(t('The specified file %file could not be copied.', array('%file' => $source)), 'error');
return FALSE;
@@ -714,11 +666,19 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
}
/**
+ * Given a relative path, construct a uri into Drupal's default files location.
+ */
+function file_build_uri($path) {
+ $uri = variable_get('file_scheme_default', 'public') . '://' . $path;
+ return file_stream_wrapper_uri_normalize($uri);
+}
+
+/**
* Determines the destination path for a file depending on how replacement of
* existing files should be handled.
*
* @param $destination
- * A string specifying the desired path.
+ * A string specifying the desired final URI or filepath.
* @param $replace
* Replace behavior when the destination file already exists.
* - FILE_EXISTS_REPLACE - Replace the existing file.
@@ -726,8 +686,8 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
* 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.
+ * Returns the destination file path, or FALSE if the file already exists
+ * and FILE_EXISTS_ERROR is specified.
*/
function file_destination($destination, $replace) {
if (file_exists($destination)) {
@@ -738,7 +698,7 @@ function file_destination($destination, $replace) {
case FILE_EXISTS_RENAME:
$basename = basename($destination);
- $directory = dirname($destination);
+ $directory = drupal_dirname($destination);
$destination = file_create_filename($basename, $directory);
break;
@@ -765,7 +725,7 @@ function file_destination($destination, $replace) {
* A file object.
* @param $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,
+ * must be a URI matching a Drupal stream wrapper. If this value is omitted,
* Drupal's 'files' directory will be used.
* @param $replace
* Replace behavior when the destination file already exists:
@@ -786,14 +746,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;
@@ -802,7 +762,7 @@ function file_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
}
// If we are renaming around an existing file (rather than a directory),
// use its basename for the filename.
- else if ($replace == FILE_EXISTS_RENAME && is_file(file_create_path($destination))) {
+ elseif ($replace == FILE_EXISTS_RENAME && is_file($destination)) {
$file->filename = basename($destination);
}
@@ -826,10 +786,10 @@ function file_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
* changes to the database.
*
* @param $source
- * A string specifying the file location of the original file.
+ * A string specifying the filepath or URI of the original file.
* @param $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,
+ * must be a URI matching a Drupal stream wrapper. If this value is omitted,
* Drupal's 'files' directory will be used.
* @param $replace
* Replace behavior when the destination file already exists:
@@ -838,7 +798,7 @@ function file_move($source, $destination = NULL, $replace = FILE_EXISTS_RENAME)
* unique.
* - FILE_EXISTS_ERROR - Do nothing and return FALSE.
* @return
- * The filepath of the moved file, or FALSE in the event of an error.
+ * The URI of the moved file, or FALSE in the event of an error.
*
* @see file_move()
*/
@@ -917,13 +877,21 @@ function file_unmunge_filename($filename) {
* @param $basename
* String filename
* @param $directory
- * String directory
+ * String containing the directory or parent URI.
* @return
* File path consisting of $directory and a unique filename based off
* of $basename.
*/
function file_create_filename($basename, $directory) {
- $destination = $directory . '/' . $basename;
+ // A URI or path may already have a trailing slash or look like "public://".
+ if (substr($directory, -1) == '/') {
+ $separator = '';
+ }
+ else {
+ $separator = '/';
+ }
+
+ $destination = $directory . $separator . $basename;
if (file_exists($destination)) {
// Destination file already exists, generate an alternative.
@@ -939,7 +907,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));
}
@@ -982,8 +950,8 @@ 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;
@@ -997,7 +965,7 @@ function file_delete($file, $force = FALSE) {
* entry recorded in the files table.
*
* @param $path
- * A string containing a file path.
+ * A string containing a filepath or URI.
* @return
* TRUE for success or path does not exist, or FALSE in the event of an
* error.
@@ -1038,7 +1006,7 @@ function file_unmanaged_delete($path) {
* Note that this only deletes visible files with write permission.
*
* @param $path
- * A string containing a file or directory path.
+ * A string containing a URI, filepath. or directory path.
* @return
* TRUE for success or path does not exist, or FALSE in the event of an
* error.
@@ -1074,7 +1042,7 @@ function file_unmanaged_delete_recursive($path) {
* 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));
@@ -1088,18 +1056,18 @@ 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.
*
* @param $source
- * A string specifying the name of the upload field to save.
+ * A string specifying the filepath or URI 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.
+ * A string containing the URI $source should be copied to. Defaults to
+ * "temporary://".
* @param $replace
* Replace behavior when the destination file already exists:
* - FILE_EXISTS_REPLACE: Replace the existing file.
@@ -1165,25 +1133,31 @@ 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';
}
- // If the destination is not provided, or is not writable, then use the
- // temporary directory.
- if (empty($destination) || file_check_path($destination) === FALSE) {
- $destination = file_directory_temp();
+ // If the destination is not provided, use the temporary directory.
+ if (empty($destination)) {
+ $destination = 'temporary://';
+ }
+
+ // Assert that the destination contains a valid stream.
+ $destination_scheme = file_uri_scheme($destination);
+ if (!$destination_scheme || !file_stream_wrapper_valid_scheme($destination_scheme)) {
+ drupal_set_message(t('The file could not be uploaded, because the destination %destination is invalid.', array('%destination' => $destination)), 'error');
+ return FALSE;
}
$file->source = $source;
- $file->destination = file_destination(file_create_path($destination . '/' . $file->filename), $replace);
+ $file->destination = file_destination($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) {
@@ -1213,19 +1187,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;
@@ -1290,8 +1264,8 @@ function file_validate_name_length($file) {
if (empty($file->filename)) {
$errors[] = t("The file's name is empty. Please give a name to the file.");
}
- if (strlen($file->filename) > 255) {
- $errors[] = t("The file's name exceeds the 255 characters limit. Please rename the file and try again.");
+ if (strlen($file->filename) > 240) {
+ $errors[] = t("The file's name exceeds the 240 characters limit. Please rename the file and try again.");
}
return $errors;
}
@@ -1370,7 +1344,7 @@ function file_validate_size($file, $file_limit = 0, $user_limit = 0) {
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.');
}
@@ -1406,13 +1380,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'];
@@ -1442,9 +1416,9 @@ function file_validate_image_resolution($file, $maximum_dimensions = 0, $minimum
* @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.
+ * A string containing the destination URI. 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. If a managed file with
@@ -1461,18 +1435,18 @@ function file_validate_image_resolution($file, $maximum_dimensions = 0, $minimum
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;
@@ -1481,7 +1455,7 @@ function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAM
}
// If we are renaming around an existing file (rather than a directory),
// use its basename for the filename.
- else if ($replace == FILE_EXISTS_RENAME && is_file(file_create_path($destination))) {
+ elseif ($replace == FILE_EXISTS_RENAME && is_file($destination)) {
$file->filename = basename($destination);
}
@@ -1495,7 +1469,7 @@ function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAM
* 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
* A string containing the contents of the file.
@@ -1516,7 +1490,7 @@ function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAM
*/
function file_unmanaged_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
// Write the data to a temporary file.
- $temp_name = tempnam(file_directory_temp(), 'file');
+ $temp_name = drupal_tempnam('temporary://', 'file');
if (file_put_contents($temp_name, $data) === FALSE) {
drupal_set_message(t('The file could not be created.'), 'error');
return FALSE;
@@ -1530,12 +1504,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.
*
- * @param $source
- * String specifying the file path to transfer.
+ * @param $uri
+ * String specifying the file URI to transfer.
* @param $headers
* An array of HTTP headers to send along with file.
*/
-function file_transfer($source, $headers) {
+function file_transfer($uri, $headers) {
if (ob_get_level()) {
ob_end_clean();
}
@@ -1544,11 +1518,9 @@ function file_transfer($source, $headers) {
drupal_set_header($name, $value);
}
drupal_send_headers();
-
- $source = file_create_path($source);
-
+ $scheme = file_uri_scheme($uri);
// Transfer file in 1024 byte chunks to save memory usage.
- if ($fd = fopen($source, 'rb')) {
+ if ($scheme && file_stream_wrapper_valid_scheme($scheme) && $fd = fopen($uri, 'rb')) {
while (!feof($fd)) {
print fread($fd, 1024);
}
@@ -1574,21 +1546,18 @@ function file_transfer($source, $headers) {
function file_download() {
// Merge remainder of arguments from GET['q'], into relative file path.
$args = func_get_args();
- $filepath = implode('/', $args);
+ $scheme = array_shift($args);
+ $target = implode('/', $args);
+ $uri = $scheme . '://' . $target;
- // Maintain compatibility with old ?file=paths saved in node bodies.
- if (isset($_GET['file'])) {
- $filepath = $_GET['file'];
- }
-
- if (file_exists(file_create_path($filepath))) {
+ if (file_exists($uri)) {
// Let other modules provide headers and controls access to the file.
- $headers = module_invoke_all('file_download', $filepath);
+ $headers = module_invoke_all('file_download', $uri);
if (in_array(-1, $headers)) {
return drupal_access_denied();
}
if (count($headers)) {
- file_transfer($filepath, $headers);
+ file_transfer($uri, $headers);
}
}
return drupal_not_found();
@@ -1603,7 +1572,7 @@ function file_download() {
* from being scanned.
*
* @param $dir
- * The base directory for the scan, without trailing slash.
+ * The base directory or URI for the scan, without trailing slash.
* @param $mask
* The preg_match() regular expression of the files to find.
* @param $options
@@ -1629,7 +1598,7 @@ function file_download() {
* should not be passed.
* @return
* An associative array (keyed on the provided key) of objects with
- * 'filepath', 'filename', and 'name' members corresponding to the
+ * 'uri', 'filename', and 'name' members corresponding to the
* matching files.
*/
function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
@@ -1638,32 +1607,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";
+ $uri = file_stream_wrapper_uri_normalize($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);
}
}
}
@@ -1676,70 +1646,29 @@ function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
}
/**
- * Determine the default temporary directory.
- *
- * @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;
-}
-
-/**
- * Determine the default 'files' directory.
+ * Determines the local directory path of a given wrapper.
*
- * @return
- * A string containing the path to Drupal's 'files' directory.
- */
-function file_directory_path() {
- return variable_get('file_directory_path', conf_path() . '/files');
-}
-
-/**
- * Remove a possible leading file directory path from the given path.
+ * This function will return the directory path of a stream wrapper. A stream
+ * is referenced as: "scheme://target". For example, a scheme of "public"
+ * might return "sites/default/files" or "temporary" might return "/tmp".
*
- * @param $path
- * Path to a file that may be in Drupal's files directory.
+ * @param $scheme
+ * A string representing the scheme of a stream. The default wrapper is
+ * is assumed if this is not provided.
* @return
- * String with Drupal's files directory removed from it.
+ * A string containing the directory path of a stream. FALSE is returned if
+ * the scheme is invalid or a wrapper could not be instantiated.
*/
-function file_directory_strip($path) {
- // 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())), '\\/');
+function file_directory_path($scheme = NULL) {
+ if (empty($scheme)) {
+ $scheme = variable_get('file_default_scheme', 'public');
+ }
+ if ($wrapper = file_stream_wrapper_get_instance_by_scheme($scheme)) {
+ return $wrapper->getDirectoryPath();
+ }
+ else {
+ return FALSE;
}
- return $path;
}
/**
@@ -1763,8 +1692,8 @@ function file_upload_max_size() {
/**
* Determine an Internet Media Type, or MIME type from a filename.
*
- * @param $filename
- * Name of the file, including extension.
+ * @param $uri
+ * A string containing the URI, path, or filename.
* @param $mapping
* An optional map of extensions to their mimetypes, in the form:
* - 'mimetypes': a list of mimetypes, keyed by an identifier,
@@ -1778,35 +1707,15 @@ function file_upload_max_size() {
* @see
* file_default_mimetype_mapping()
*/
-function file_get_mimetype($filename, $mapping = NULL) {
- if (!isset($mapping)) {
- $mapping = variable_get('mime_extension_mapping', NULL);
- if (!isset($mapping) && drupal_function_exists('file_default_mimetype_mapping')) {
- // The default file map, defined in file.mimetypes.inc is quite big.
- // We only load it when necessary.
- $mapping = file_default_mimetype_mapping();
- }
+function file_get_mimetype($uri, $mapping = NULL) {
+ if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {
+ return $wrapper->getMimeType($uri, $mapping);
}
-
- $extension = '';
- $file_parts = explode('.', $filename);
-
- // Remove the first part: a full filename should not match an extension.
- array_shift($file_parts);
-
- // Iterate over the file parts, trying to find a match.
- // For my.awesome.image.jpeg, we try:
- // - jpeg
- // - image.jpeg, and
- // - awesome.image.jpeg
- while ($additional_part = array_pop($file_parts)) {
- $extension = strtolower($additional_part . ($extension ? '.' . $extension : ''));
- if (isset($mapping['extensions'][$extension])) {
- return $mapping['mimetypes'][$mapping['extensions'][$extension]];
- }
+ else {
+ // getMimeType() is not implementation specific, so we can directly
+ // call it without an instance.
+ return DrupalLocalStreamWrapper::getMimeType($uri, $mapping);
}
-
- return 'application/octet-stream';
}
/**
@@ -1819,17 +1728,21 @@ function file_get_mimetype($filename, $mapping = NULL) {
* these files, and give group write permissions so webserver group members
* (e.g. a vhost account) can alter files uploaded and owned by the webserver.
*
- * @param $path
- * String containing the path to a file or directory.
+ * PHP's chmod does not support stream wrappers so we use our wrapper implementation
+ * which interfaces with chmod() by default. Contrib wrappers may override this
+ * bahavior in their implementations as needed.
+ *
+ * @param $uri
+ * A string containing a URI file, or directory path.
* @param $mode
* Integer value for the permissions. Consult PHP chmod() documentation for
* more information.
* @return
* TRUE for success, FALSE in the event of an error.
*/
-function drupal_chmod($path, $mode = NULL) {
+function drupal_chmod($uri, $mode = NULL) {
if (!isset($mode)) {
- if (is_dir($path)) {
+ if (is_dir($uri)) {
$mode = variable_get('file_chmod_directory', 0775);
}
else {
@@ -1837,14 +1750,168 @@ function drupal_chmod($path, $mode = NULL) {
}
}
- if (@chmod($path, $mode)) {
- return TRUE;
+ // If this URI is a stream, pass it off to the appropriate stream wrapper.
+ // Otherwise, attempt PHP's chmod. This allows use of drupal_chmod even
+ // for unmanaged files outside of the stream wrapper interface.
+ if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {
+ if ($wrapper->chmod($mode)) {
+ return TRUE;
+ }
+ }
+ else {
+ if (@chmod($uri, $mode)) {
+ return TRUE;
+ }
}
- watchdog('file', 'The file permissions could not be set on %path.', array('%path' => $path), WATCHDOG_ERROR);
+ watchdog('file', 'The file permissions could not be set on %uri.', array('%uri' => $uri), WATCHDOG_ERROR);
return FALSE;
}
/**
+ * Returns the absolute path of a file or directory
+ *
+ * PHP's realpath() does not properly support streams, so this function
+ * fills that gap. If a stream wrapped URI is provided, it will be passed
+ * to the registered wrapper for handling. If the URI does not contain a
+ * scheme or the wrapper implementation does not implement realpath, then
+ * FALSE will be returned.
+ *
+ * @see http://php.net/manual/en/function.realpath.php
+ *
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param $uri
+ * A string containing the URI to verify. If this value is omitted,
+ * Drupal's public files directory will be used [public://].
+ * @return
+ * The absolute pathname, or FALSE on failure.
+ *
+ * @see realpath()
+ */
+function drupal_realpath($uri) {
+ // If this URI is a stream, pass it off to the appropriate stream wrapper.
+ // Otherwise, attempt PHP's realpath. This allows use of drupal_realpath even
+ // for unmanaged files outside of the stream wrapper interface.
+ if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {
+ return $wrapper->realpath();
+ }
+ else {
+ return realpath($uri);
+ }
+}
+
+/**
+ * Gets the name of the directory from a given path.
+ *
+ * PHP's dirname() does not properly pass streams, so this function fills
+ * that gap. It is backwards compatible with normal paths and will use
+ * PHP's dirname() as a fallback.
+ *
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param $uri
+ * A URI or path.
+ * @return
+ * A string containing the directory name.
+ *
+ * @see dirname()
+ */
+function drupal_dirname($uri) {
+ $scheme = file_uri_scheme($uri);
+
+ if ($scheme && file_stream_wrapper_valid_scheme($scheme)) {
+ $target = file_uri_target($uri);
+ $dirname = dirname($target);
+
+ if ($dirname == '.') {
+ $dirname = '';
+ }
+
+ return $scheme . '://' . $dirname;
+ }
+ else {
+ return dirname($uri);
+ }
+}
+
+/**
+ * Creates a directory using Drupal's default mode.
+ *
+ * PHP's mkdir() does not respect Drupal's default permissions mode. If a mode
+ * is not provided, this function will make sure that Drupal's is used.
+ *
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param $uri
+ * A URI or pathname.
+ * @param $mode
+ * By default the Drupal mode is used.
+ * @param $recursive
+ * Default to FALSE.
+ * @param $context
+ * Refer to http://php.net/manual/en/ref.stream.php
+ * @return
+ * Boolean TRUE on success, or FALSE on failure.
+ *
+ * @see mkdir()
+ */
+function drupal_mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL) {
+
+ if (is_null($mode)) {
+ $mode = variable_get('file_chmod_directory', 0775);
+ }
+
+ if (is_null($context)) {
+ return mkdir($uri, $mode, $recursive);
+ }
+ else {
+ return mkdir($uri, $mode, $recursive, $context);
+ }
+}
+
+/**
+ * Creates a file with a unique filename in the specified directory.
+ *
+ * PHP's tempnam() does not return a URI like we want. This function
+ * will return a URI if given a URI, or it will return a filepath if
+ * given a filepath.
+ *
+ * Compatibility: normal paths and stream wrappers.
+ * @see http://drupal.org/node/515192
+ *
+ * @param $directory
+ * The directory where the temporary filename will be created.
+ * @param $prefix
+ * The prefix of the generated temporary filename.
+ * Note: Windows uses only the first three characters of prefix.
+ * @return
+ * The new temporary fillename, or FALSE on failure.
+ *
+ * @see tempnam()
+ */
+function drupal_tempnam($directory, $prefix) {
+ $scheme = file_uri_scheme($directory);
+
+ if ($scheme && file_stream_wrapper_valid_scheme($scheme)) {
+ $wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
+
+ if ($filename = tempnam($wrapper->getDirectoryPath(), $prefix)) {
+ return $scheme . '://' . basename($filename);
+ }
+ else {
+ return FALSE;
+ }
+ }
+ else {
+ // Handle as a normal tempnam() call.
+ return tempnam($directory, $prefix);
+ }
+}
+
+/**
* @} End of "defgroup file".
*/
diff --git includes/filetransfer/filetransfer.inc includes/filetransfer/filetransfer.inc
index 588526c..e5c9ff8 100644
--- includes/filetransfer/filetransfer.inc
+++ includes/filetransfer/filetransfer.inc
@@ -114,7 +114,7 @@ abstract class FileTransfer {
* A path to check against the jail.
*/
protected final function checkPath($path) {
- if (realpath(substr($path, 0, strlen($this->jail))) !== $this->jail) {
+ if (drupal_realpath(substr($path, 0, strlen($this->jail))) !== $this->jail) {
throw new FileTransferException('@directory is outside of the @jail', NULL, array('@directory' => $path, '@jail' => $this->jail));
}
}
diff --git includes/filetransfer/ftp.inc includes/filetransfer/ftp.inc
index 51a2e66..45a3a3f 100644
--- includes/filetransfer/ftp.inc
+++ includes/filetransfer/ftp.inc
@@ -19,7 +19,7 @@ class FileTransferFTPWrapper extends FileTransfer {
}
function createDirectoryJailed($directory) {
- if (!@mkdir($directory)) {
+ if (!@drupal_mkdir($directory)) {
$exception = new FileTransferException('Cannot create directory @directory.', NULL, array('@directory' => $directory));
throw $exception;
}
diff --git includes/form.inc includes/form.inc
index db9af87..53a9464 100644
--- includes/form.inc
+++ includes/form.inc
@@ -2452,7 +2452,7 @@ function theme_image_button($element) {
(!empty($element['#value']) ? ('value="' . check_plain($element['#value']) . '" ') : '') .
'id="' . $element['#id'] . '" ' .
drupal_attributes($element['#attributes']) .
- ' src="' . base_path() . $element['#src'] . '" ' .
+ ' src="' . file_external_url($element['#src']) . '" ' .
(!empty($element['#title']) ? 'alt="' . check_plain($element['#title']) . '" title="' . check_plain($element['#title']) . '" ' : '' ) .
"/>\n";
}
diff --git includes/install.inc includes/install.inc
index fff03e8..fe92d1f 100644
--- includes/install.inc
+++ includes/install.inc
@@ -216,9 +216,9 @@ function drupal_detect_database_types() {
// file for the driver explicitly.
require_once DRUPAL_ROOT . '/includes/database/database.inc';
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) {
@@ -810,7 +810,7 @@ function drupal_install_mkdir($file, $mask, $message = TRUE) {
}
}
- if (@mkdir($file, intval("0$mod", 8))) {
+ if (@drupal_mkdir($file, intval("0$mod", 8))) {
return TRUE;
}
else {
@@ -934,7 +934,7 @@ function st($string, $args = array()) {
$filename = 'profiles/' . $install_state['parameters']['profile'] . '/translations/' . $install_state['parameters']['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');
}
@@ -986,7 +986,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'));
@@ -1026,7 +1026,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 4e76e96..f540b2f 100644
--- includes/locale.inc
+++ includes/locale.inc
@@ -1223,7 +1223,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;
@@ -1439,7 +1439,7 @@ function _locale_import_one_string($op, $value = NULL, $mode = NULL, $lang = NUL
$header = _locale_import_parse_header($value['msgstr']);
// Get the plural formula and update in database.
- if (isset($header["Plural-Forms"]) && $p = _locale_import_parse_plural_forms($header["Plural-Forms"], $file->filepath)) {
+ if (isset($header["Plural-Forms"]) && $p = _locale_import_parse_plural_forms($header["Plural-Forms"], $file->uri)) {
list($nplurals, $plural) = $p;
db_update('languages')
->fields(array(
@@ -2435,11 +2435,11 @@ function _locale_rebuild_js($langcode = NULL) {
// Construct the filepath where JS translation files are stored.
// There is (on purpose) no front end to edit that variable.
- $dir = file_create_path(variable_get('locale_js_directory', 'languages'));
+ $dir = 'public://' . variable_get('locale_js_directory', 'languages');
// Delete old file, if we have no translations anymore, or a different file to be saved.
if (!empty($language->javascript) && (!$data || $language->javascript != $data_hash)) {
- file_unmanaged_delete(file_create_path($dir . '/' . $language->language . '_' . $language->javascript . '.js'));
+ file_unmanaged_delete($dir . '/' . $language->language . '_' . $language->javascript . '.js');
$language->javascript = '';
$status = 'deleted';
}
@@ -2447,7 +2447,7 @@ function _locale_rebuild_js($langcode = NULL) {
// Only create a new file if the content has changed.
if ($data && $language->javascript != $data_hash) {
// Ensure that the directory exists and is writable, if possible.
- file_check_directory($dir, TRUE);
+ file_prepare_directory($dir, FILE_CREATE_DIRECTORY);
// Save the file.
$dest = $dir . '/' . $language->language . '_' . $data_hash . '.js';
@@ -2650,7 +2650,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,
@@ -2682,7 +2682,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 83a421d..2594b0e 100644
--- includes/module.inc
+++ includes/module.inc
@@ -503,7 +503,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 7243ff2..6ec637b 100644
--- includes/registry.inc
+++ includes/registry.inc
@@ -42,7 +42,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/stream_wrappers.inc includes/stream_wrappers.inc
index 75a1f8f..f455db3 100644
--- includes/stream_wrappers.inc
+++ includes/stream_wrappers.inc
@@ -226,14 +226,14 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
* Base implementation of chmod().
*/
function chmod($mode) {
- return @chmod($this->realpath(), $mode);
+ return @chmod($this->getLocalPath(), $mode);
}
/**
- * Base implementaiton of realpath().
+ * Base implementation of realpath().
*/
function realpath() {
- return @realpath($this->getDirectoryPath() . '/' . file_uri_target($this->uri));
+ return $this->getLocalPath();
}
/**
@@ -246,14 +246,24 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
if (!isset($uri)) {
$uri = $this->uri;
}
- return $this->getDirectoryPath() . '/' . file_uri_target($uri);
+ $path = $this->getDirectoryPath() . '/' . file_uri_target($uri);
+ $realpath = realpath($path);
+ if (!$realpath) {
+ // This file does not yet exist.
+ $realpath = realpath(dirname($path)) . '/' . basename($path);
+ }
+ $directory = realpath($this->getDirectoryPath());
+ if (!$realpath || !$directory || strpos($realpath, $directory) !== 0) {
+ return FALSE;
+ }
+ return $realpath;
}
/**
* Support for fopen(), file_get_contents(), file_put_contents() etc.
*
* @param $uri
- * A string containing the path to the file to open.
+ * A string containing the URI to the file to open.
* @param $mode
* The file mode ("r", "wb" etc.).
* @param $options
@@ -428,7 +438,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
* Support for mkdir().
*
* @param $uri
- * A string containing the url to the directory to create.
+ * A string containing the URI to the directory to create.
* @param $mode
* Permission flags - see mkdir().
* @param $options
@@ -440,11 +450,19 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
public function mkdir($uri, $mode, $options) {
$this->uri = $uri;
$recursive = (bool)($options & STREAM_MKDIR_RECURSIVE);
+ if ($recursive) {
+ // $this->getLocalPath() fails if $uri has multiple levels of directories
+ // that do not yet exist.
+ $localpath = $this->getDirectoryPath() . '/' . file_uri_target($uri);
+ }
+ else {
+ $localpath = $this->getLocalPath($uri);
+ }
if ($options & STREAM_REPORT_ERRORS) {
- return mkdir($this->getLocalPath(), $mode, $recursive);
+ return mkdir($localpath, $mode, $recursive);
}
else {
- return @mkdir($this->getLocalPath(), $mode, $recursive);
+ return @mkdir($localpath, $mode, $recursive);
}
}
@@ -452,7 +470,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
* Support for rmdir().
*
* @param $uri
- * A string containing the url to the directory to delete.
+ * A string containing the URI to the directory to delete.
* @param $options
* A bit mask of STREAM_REPORT_ERRORS.
* @return
@@ -473,7 +491,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
* Support for stat().
*
* @param $uri
- * A string containing the url to get information about.
+ * A string containing the URI to get information about.
* @param $flags
* A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET.
* @return
@@ -495,7 +513,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
* Support for opendir().
*
* @param $uri
- * A string containing the url to the directory to open.
+ * A string containing the URI to the directory to open.
* @param $options
* Unknown (parameter is not documented in PHP Manual).
* @return
@@ -554,7 +572,7 @@ class DrupalPublicStreamWrapper extends DrupalLocalStreamWrapper {
* Implements abstract public function getDirectoryPath()
*/
public function getDirectoryPath() {
- return variable_get('file_public_path', 'sites/default/files');
+ return variable_get('file_public_path', conf_path() . '/files');
}
/**
@@ -582,7 +600,7 @@ class DrupalPrivateStreamWrapper extends DrupalLocalStreamWrapper {
* Implements abstract public function getDirectoryPath()
*/
public function getDirectoryPath() {
- return variable_get('file_private_path', 'sites/default/files-private');
+ return variable_get('file_private_path', conf_path() . '/private/files');
}
/**
@@ -609,13 +627,14 @@ class DrupalTemporaryStreamWrapper extends DrupalLocalStreamWrapper {
* Implements abstract public function getDirectoryPath()
*/
public function getDirectoryPath() {
- return variable_get('file_temporary_path', '/tmp');
+ return variable_get('file_temporary_path', conf_path() . '/private/temp');
}
/**
* Overrides getExternalUrl().
*/
public function getExternalUrl() {
- return '';
+ $path = str_replace('\\', '/', file_uri_target($this->uri));
+ return url('system/temporary/' . $path, array('absolute' => TRUE));
}
}
diff --git includes/theme.inc includes/theme.inc
index 6cb7ab0..ecc4c67 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'],
);
}
@@ -1099,24 +1099,24 @@ function theme_get_setting($setting_name, $refresh = FALSE) {
if ($settings['toggle_logo']) {
if ($settings['default_logo']) {
- $settings['logo'] = base_path() . dirname($theme_object->filename) . '/logo.png';
+ $settings['logo'] = file_external_url(dirname($theme_object->filename) . '/logo.png');
}
elseif ($settings['logo_path']) {
- $settings['logo'] = base_path() . $settings['logo_path'];
+ $settings['logo'] = file_external_url($settings['logo_path']);
}
}
if ($settings['toggle_favicon']) {
if ($settings['default_favicon']) {
if (file_exists($favicon = dirname($theme_object->filename) . '/favicon.ico')) {
- $settings['favicon'] = base_path() . $favicon;
+ $settings['favicon'] = file_external_url($favicon);
}
else {
- $settings['favicon'] = base_path() . 'misc/favicon.ico';
+ $settings['favicon'] = file_external_url('misc/favicon.ico');
}
}
elseif ($settings['favicon_path']) {
- $settings['favicon'] = base_path() . $settings['favicon_path'];
+ $settings['favicon'] = file_external_url($settings['favicon_path']);
}
else {
$settings['toggle_favicon'] = FALSE;
@@ -1340,7 +1340,7 @@ function theme_links($links, $attributes = array('class' => 'links')) {
function theme_image($path, $alt = '', $title = '', $attributes = array(), $getsize = TRUE) {
if (!$getsize || (is_file($path) && (list($width, $height, $type, $image_attributes) = @getimagesize($path)))) {
$attributes = drupal_attributes($attributes);
- $url = (url($path) == $path) ? $path : (base_path() . $path);
+ $url = file_external_url($path);
return '';
}
}
diff --git install.php install.php
index 4d7f98d..26cbac1 100644
--- install.php
+++ install.php
@@ -1039,6 +1039,8 @@ function _install_select_profile($profiles) {
// Don't need to choose profile if only one available.
if (sizeof($profiles) == 1) {
$profile = array_pop($profiles);
+ // TODO: is this right?
+ require_once $profile->uri;
return $profile->name;
}
else {
@@ -1063,7 +1065,8 @@ function install_select_profile_form(&$form_state, $profile_files) {
$names = array();
foreach ($profile_files as $profile) {
- include_once DRUPAL_ROOT . '/' . $profile->filepath;
+ // TODO: is this right?
+ 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 c9260a3..da1d0e4 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 8088eec..0514f47 100644
--- modules/aggregator/aggregator.test
+++ modules/aggregator/aggregator.test
@@ -200,7 +200,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
EOF;
- $path = file_directory_path() . '/valid-opml.xml';
+ $path = 'public://valid-opml.xml';
return file_unmanaged_save_data($opml, $path);
}
@@ -217,7 +217,7 @@ EOF;
EOF;
- $path = file_directory_path() . '/invalid-opml.xml';
+ $path = 'public://invalid-opml.xml';
return file_unmanaged_save_data($opml, $path);
}
@@ -239,7 +239,7 @@ EOF;
EOF;
- $path = file_directory_path() . '/empty-opml.xml';
+ $path = 'public://empty-opml.xml';
return file_unmanaged_save_data($opml, $path);
}
@@ -557,7 +557,7 @@ class ImportOPMLTestCase extends AggregatorTestCase {
$path = $this->getEmptyOpml();
$form = array(
'files[upload]' => $path,
- 'remote' => file_create_url($path),
+ 'remote' => file_external_url($path),
);
$this->drupalPost('admin/settings/aggregator/add/opml', $form, t('Import'));
$this->assertRaw(t('You must either upload a file or enter a URL.'), t('Error if both fields are filled.'));
@@ -580,7 +580,7 @@ class ImportOPMLTestCase extends AggregatorTestCase {
$this->drupalPost('admin/settings/aggregator/add/opml', $form, t('Import'));
$this->assertText(t('No new feed has been added.'), t('Attempting to upload invalid XML.'));
- $form = array('remote' => file_create_url($this->getEmptyOpml()));
+ $form = array('remote' => file_external_url($this->getEmptyOpml()));
$this->drupalPost('admin/settings/aggregator/add/opml', $form, t('Import'));
$this->assertText(t('No new feed has been added.'), t('Attempting to load empty OPML from remote URL.'));
diff --git modules/blogapi/blogapi.module modules/blogapi/blogapi.module
index 17d1542..7796eb6 100644
--- modules/blogapi/blogapi.module
+++ modules/blogapi/blogapi.module
@@ -460,25 +460,29 @@ function blogapi_metaweblog_new_media_object($blogid, $username, $password, $fil
$filename .= '.' . $final_extension;
}
+ else {
+ $filename = $name;
+ }
+ $uri = file_build_uri($filename);
$data = $file['bits'];
if (!$data) {
return blogapi_error(t('No file sent.'));
}
- if (!$file = file_unmanaged_save_data($data, $filename)) {
+ if (!$file = file_unmanaged_save_data($data, $uri)) {
return blogapi_error(t('Error storing file.'));
}
$row = new stdClass();
$row->uid = $user->uid;
- $row->filepath = $file;
+ $row->uri = $file;
$row->filesize = $filesize;
drupal_write_record('blogapi_files', $row);
// Return the successful result.
- return array('url' => file_create_url($file), 'struct');
+ return array('url' => file_external_url($file), 'struct');
}
/**
* Blogging API callback. Returns a list of the taxonomy terms that can be
diff --git modules/blogapi/blogapi.test modules/blogapi/blogapi.test
index 6a74004..dd3d68c 100644
--- modules/blogapi/blogapi.test
+++ modules/blogapi/blogapi.test
@@ -70,7 +70,7 @@ class BlogAPITestCase extends DrupalWebTestCase {
// Upload file.
$file = current($this->drupalGetTestFiles('text'));
- $file_contents = file_get_contents($file->filepath);
+ $file_contents = file_get_contents($file->uri);
$file = array();
$file['name'] = $this->randomName() . '.txt';
$file['type'] = 'text';
diff --git modules/color/color.module modules/color/color.module
index 24078ee..baf3bf6 100644
--- modules/color/color.module
+++ modules/color/color.module
@@ -7,7 +7,7 @@
function color_help($path, $arg) {
switch ($path) {
case 'admin/help#color':
- $output = '
' . t('The color module allows a site administrator to quickly and easily change the color scheme of certain themes. Although not all themes support color module, both Garland (the default theme) and Minnelli were designed to take advantage of its features. By using color module with a compatible theme, you can easily change the color of links, backgrounds, text, and other theme elements. Color module requires that your file download method be set to public.', array('@url' => url('admin/settings/file-system'))) . '
';
+ $output = '
' . t('The color module allows a site administrator to quickly and easily change the color scheme of certain themes. Although not all themes support color module, both Garland (the default theme) and Minnelli were designed to take advantage of its features. By using color module with a compatible theme, you can easily change the color of links, backgrounds, text, and other theme elements.', array('@url' => url('admin/settings/file-system'))) . '
';
$output .= '
' . t("It is important to remember that color module saves a modified copy of the theme's specified stylesheets in the files directory. This means that if you make any manual changes to your theme's stylesheet, you must save your color settings again, even if they haven't changed. This causes the color module generated version of the stylesheets in the files directory to be recreated using the new version of the original file.") . '
';
$output .= '
' . t('To change the color settings for a compatible theme, select the "configure" link for the theme on the themes administration page.', array('@themes' => url('admin/appearance'))) . '
';
$output .= '
' . t('For more information, see the online handbook entry for Color module.', array('@color' => 'http://drupal.org/handbook/modules/color/')) . '
';
@@ -32,22 +32,15 @@ function color_theme() {
*/
function color_form_system_theme_settings_alter(&$form, &$form_state) {
if (color_get_info(arg(4)) && function_exists('gd_info')) {
- if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) != FILE_DOWNLOADS_PUBLIC) {
- // Disables the color changer when the private download method is used.
- // TODO: This should be solved in a different way. See issue #181003.
- drupal_set_message(t('The color picker only works if the download method is set to public.', array('@url' => url('admin/settings/file-system'))), 'warning');
- }
- else {
- $form['color'] = array(
- '#type' => 'fieldset',
- '#title' => t('Color scheme'),
- '#weight' => -1,
- '#attributes' => array('id' => 'color_scheme_form'),
- '#theme' => 'color_scheme_form',
- );
- $form['color'] += color_scheme_form($form_state, arg(4));
- $form['#submit'][] = 'color_scheme_form_submit';
- }
+ $form['color'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Color scheme'),
+ '#weight' => -1,
+ '#attributes' => array('id' => 'color_scheme_form'),
+ '#theme' => 'color_scheme_form',
+ );
+ $form['color'] += color_scheme_form($form_state, arg(4));
+ $form['#submit'][] = 'color_scheme_form_submit';
}
}
@@ -300,7 +293,7 @@ function color_scheme_form_submit($form, &$form_state) {
$paths['color'] = file_directory_path() . '/color';
$paths['target'] = $paths['color'] . '/' . $id;
foreach ($paths as $path) {
- file_check_directory($path, FILE_CREATE_DIRECTORY);
+ file_prepare_directory($path, FILE_CREATE_DIRECTORY);
}
$paths['target'] = $paths['target'] . '/';
$paths['id'] = $id;
diff --git modules/image/image.admin.inc modules/image/image.admin.inc
index 1aba780..2113d5c 100644
--- modules/image/image.admin.inc
+++ modules/image/image.admin.inc
@@ -679,11 +679,10 @@ function theme_image_style_preview($style) {
// Set up preview file information.
$preview_file = image_style_path($style['name'], $original_path);
- $preview_path = file_create_path($preview_file);
- if (!file_exists($preview_path) && image_style_create_derivative($style, $original_path, $preview_file)) {
- $preview_path = file_create_path($preview_file);
+ if (!file_exists($preview_file)) {
+ image_style_create_derivative($style, $original_path, $preview_file);
}
- $preview_image = image_get_info($preview_path);
+ $preview_image = image_get_info($preview_file);
if ($preview_image['width'] > $preview_image['height']) {
$preview_width = min($preview_image['width'], $sample_width);
$preview_height = round($preview_width / $preview_image['width'] * $preview_image['height']);
@@ -711,9 +710,9 @@ function theme_image_style_preview($style) {
// Build the preview of the image style.
$output .= '