diff --git a/sites/all/modules/contrib/imagecache/imagecache.module b/sites/all/modules/contrib/imagecache/imagecache.module index 55d48ce..06d5cd0 100644 --- a/sites/all/modules/contrib/imagecache/imagecache.module +++ b/sites/all/modules/contrib/imagecache/imagecache.module @@ -394,14 +394,60 @@ function _imagecache_strip_file_directory($path) { return $path; } +/** + * Extracts the preset name and image path from the URI of the original + * request. + * + * The method of using the request URI is preferred over the method of using + * the arguments parsed out of the query string and provided by the Drupal menu + * system because the request URI is preserved in escaped form, while the + * query string gets automatically URL-decoded by the web server before being + * passed to Drupal. This allows ImageCache to properly handle requests to + * retrieve files with names that contain special characters (i.e. the plus + * sign, "+") or escape sequences (i.e. "%20"). + * + * @param $preset + * A reference to the variable that will be populated with the preset + * name, or NULL if a preset could not be extracted from the request URI. + * + * @param $path + * A reference to the variable that will be populated with the path, or + * NULL if a path could not be extracted from the request URI. + */ +function _imagecache_extract_preset_and_path_from_uri(&$preset, &$path) { + $request_uri = $_SERVER['REQUEST_URI']; + $full_path = preg_replace('!^/(index.php)?(\?q=)?(.*)$!', '$3', $request_uri); + + if (!empty($full_path)) { + // Strip out private or public file path + if (preg_match('!^system/files/(.*)$!', $full_path, $matches)) { + $path = $matches[1]; + } + else { + $path = _imagecache_strip_file_directory($full_path); + } + + /* The path will look like this: + * "imagecache/uc_thumbnail/Penguins+on+the+beach.jpg" + * + * This makes the first path component "imagecache", followed by the + * preset, followed by the image path. + */ + list($unused, $preset, $path) = explode('/', $path, 3); + } + else { + $path = NULL; + $preset = NULL; + } + + return $result; +} /** * callback for handling public files imagecache requests. */ function imagecache_cache() { - $args = func_get_args(); - $preset = check_plain(array_shift($args)); - $path = implode('/', $args); + _imagecache_extract_preset_and_path_from_uri($preset, $path); _imagecache_cache($preset, $path); } @@ -409,9 +455,7 @@ function imagecache_cache() { * callback for handling private files imagecache requests */ function imagecache_cache_private() { - $args = func_get_args(); - $preset = check_plain(array_shift($args)); - $source = implode('/', $args); + _imagecache_extract_preset_and_path_from_uri($preset, $source); if (user_access('view imagecache '. $preset) && !in_array(-1, module_invoke_all('file_download', $source))) { _imagecache_cache($preset, $source); @@ -444,15 +488,26 @@ function _imagecache_cache($presetname, $path) { // umm yeah deliver it early if it is there. especially useful // to prevent lock files from being created when delivering private files. $dst = imagecache_create_path($preset['presetname'], $path); + if (is_file($dst)) { imagecache_transfer($dst); } + /* NOTE: Although we could roll this conditional into the one above by + * modifying $dst in the conditional test (i.e. + * "is_file($dst = urldecode($dst)"), that could pose a problem. The + * file might not be in the cache, and if it isn't, we don't want the + * destination to have an unescaped name (could lead to file name + * collisions). + */ + elseif (is_file(urldecode($dst))) { + imagecache_transfer(urldecode($dst)); + } // preserve path for watchdog. $src = $path; // Check if the path to the file exists. - if (!is_file($src) && !is_file($src = file_create_path($src))) { + if (!is_file($src) && !is_file($src = file_create_path($src)) && !is_file($src = urldecode($src))) { watchdog('imagecache', '404: Unable to find %image ', array('%image' => $src), WATCHDOG_ERROR); header("HTTP/1.0 404 Not Found"); exit;