Commit 2f0d691c authored by catch's avatar catch

Issue #278425 by andypost, OnkelTem, chx, c960657, droplet et al: Fixed Using...

Issue #278425 by andypost, OnkelTem, chx, c960657, droplet et al: Fixed Using basename() is not locale safe.
parent c95075ec
......@@ -2940,7 +2940,7 @@ function drupal_get_css($css = NULL, $skip_alter = FALSE) {
foreach ($css as $key => $item) {
if ($item['type'] == 'file') {
// If defined, force a unique basename for this file.
$basename = isset($item['basename']) ? $item['basename'] : basename($item['data']);
$basename = isset($item['basename']) ? $item['basename'] : drupal_basename($item['data']);
if (isset($previous_item[$basename])) {
// Remove the previous item that shared the same base name.
unset($css[$previous_item[$basename]]);
......
......@@ -770,7 +770,7 @@ function file_copy(stdClass $source, $destination = NULL, $replace = FILE_EXISTS
$file = clone $source;
$file->fid = NULL;
$file->uri = $uri;
$file->filename = basename($uri);
$file->filename = drupal_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('uri' => $uri));
......@@ -783,7 +783,7 @@ function file_copy(stdClass $source, $destination = NULL, $replace = FILE_EXISTS
// If we are renaming around an existing file (rather than a directory),
// use its basename for the filename.
elseif ($replace == FILE_EXISTS_RENAME && is_file($destination)) {
$file->filename = basename($destination);
$file->filename = drupal_basename($destination);
}
$file = file_save($file);
......@@ -871,14 +871,14 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
// Build a destination URI if necessary.
if (!isset($destination)) {
$destination = file_build_uri(basename($source));
$destination = file_build_uri(drupal_basename($source));
}
// 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));
$destination = file_stream_wrapper_uri_normalize($destination . '/' . drupal_basename($source));
}
else {
// Perhaps $destination is a dir/file?
......@@ -958,7 +958,7 @@ function file_destination($destination, $replace) {
break;
case FILE_EXISTS_RENAME:
$basename = basename($destination);
$basename = drupal_basename($destination);
$directory = drupal_dirname($destination);
$destination = file_create_filename($basename, $directory);
break;
......@@ -1033,7 +1033,7 @@ function file_move(stdClass $source, $destination = NULL, $replace = FILE_EXISTS
// If we are renaming around an existing file (rather than a directory),
// use its basename for the filename.
elseif ($replace == FILE_EXISTS_RENAME && is_file($destination)) {
$file->filename = basename($destination);
$file->filename = drupal_basename($destination);
}
$file = file_save($file);
......@@ -1457,7 +1457,7 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
$file = new stdClass();
$file->uid = $user->uid;
$file->status = 0;
$file->filename = trim(basename($_FILES['files']['name'][$source]), '.');
$file->filename = trim(drupal_basename($_FILES['files']['name'][$source]), '.');
$file->uri = $_FILES['files']['tmp_name'][$source];
$file->filemime = file_get_mimetype($file->filename);
$file->filesize = $_FILES['files']['size'][$source];
......@@ -1855,7 +1855,7 @@ function file_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAM
$file = new stdClass();
$file->fid = NULL;
$file->uri = $uri;
$file->filename = basename($uri);
$file->filename = drupal_basename($uri);
$file->filemime = file_get_mimetype($file->uri);
$file->uid = $user->uid;
$file->status = FILE_STATUS_PERMANENT;
......@@ -1871,7 +1871,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.
elseif ($replace == FILE_EXISTS_RENAME && is_file($destination)) {
$file->filename = basename($destination);
$file->filename = drupal_basename($destination);
}
return file_save($file);
......@@ -2274,6 +2274,35 @@ function drupal_dirname($uri) {
}
}
/**
* Gets the filename from a given path.
*
* PHP's basename() does not properly support streams or filenames beginning
* with a non-US-ASCII character.
*
* @see http://bugs.php.net/bug.php?id=37738
* @see basename()
*
* @ingroup php_wrappers
*/
function drupal_basename($uri, $suffix = NULL) {
$separators = '/';
if (DIRECTORY_SEPARATOR != '/') {
// For Windows OS add special separator.
$separators .= DIRECTORY_SEPARATOR;
}
// Remove right-most slashes when $uri points to directory.
$uri = rtrim($uri, $separators);
// Returns the trailing part of the $uri starting after one of the directory
// separators.
$filename = preg_match('@[^' . preg_quote($separators, '@') . ']+$@', $uri, $matches) ? $matches[0] : '';
// Cuts off a suffix from the filename.
if ($suffix) {
$filename = preg_replace('@' . preg_quote($suffix, '@') . '$@', '', $filename);
}
return $filename;
}
/**
* Creates a directory using Drupal's default mode.
*
......@@ -2370,7 +2399,7 @@ function drupal_tempnam($directory, $prefix) {
$wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
if ($filename = tempnam($wrapper->getDirectoryPath(), $prefix)) {
return $scheme . '://' . basename($filename);
return $scheme . '://' . drupal_basename($filename);
}
else {
return FALSE;
......
......@@ -212,7 +212,7 @@ function sanitizePath($path) {
*/
protected function copyDirectoryJailed($source, $destination) {
if ($this->isDirectory($destination)) {
$destination = $destination . '/' . basename($source);
$destination = $destination . '/' . drupal_basename($source);
}
$this->createDirectory($destination);
foreach (new RecursiveIteratorIterator(new SkipDotsRecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST) as $filename => $file) {
......@@ -303,7 +303,7 @@ function findChroot() {
$chroot = '';
while (count($parts)) {
$check = implode($parts, '/');
if ($this->isFile($check . '/' . basename(__FILE__))) {
if ($this->isFile($check . '/' . drupal_basename(__FILE__))) {
// Remove the trailing slash.
return substr($chroot, 0, -1);
}
......
......@@ -317,7 +317,7 @@ static function getMimeType($uri, $mapping = NULL) {
}
$extension = '';
$file_parts = explode('.', basename($uri));
$file_parts = explode('.', drupal_basename($uri));
// Remove the first part: a full filename should not match an extension.
array_shift($file_parts);
......@@ -377,7 +377,7 @@ protected function getLocalPath($uri = NULL) {
$realpath = realpath($path);
if (!$realpath) {
// This file does not yet exist.
$realpath = realpath(dirname($path)) . '/' . basename($path);
$realpath = realpath(dirname($path)) . '/' . drupal_basename($path);
}
$directory = realpath($this->getDirectoryPath());
if (!$realpath || !$directory || strpos($realpath, $directory) !== 0) {
......
......@@ -141,7 +141,7 @@ public static function findInfoFile($directory) {
return FALSE;
}
foreach ($info_files as $info_file) {
if (drupal_substr($info_file->filename, 0, -5) == basename($directory)) {
if (drupal_substr($info_file->filename, 0, -5) == drupal_basename($directory)) {
// Info file Has the same name as the directory, return it.
return $info_file->uri;
}
......@@ -163,7 +163,7 @@ public static function findInfoFile($directory) {
* The name of the project.
*/
public static function getProjectName($directory) {
return basename($directory);
return drupal_basename($directory);
}
/**
......
......@@ -96,7 +96,7 @@ function _color_html_alter(&$vars) {
foreach ($color_paths as $color_path) {
// Color module currently requires unique file names to be used,
// which allows us to compare different file paths.
if (basename($old_path) == basename($color_path)) {
if (drupal_basename($old_path) == drupal_basename($color_path)) {
// Replace the path to the new css file.
// This keeps the order of the stylesheets intact.
$vars['css'][$old_path]['data'] = $color_path;
......@@ -389,7 +389,7 @@ function color_scheme_form_submit($form, &$form_state) {
// Copy over neutral images.
foreach ($info['copy'] as $file) {
$base = basename($file);
$base = drupal_basename($file);
$source = $paths['source'] . $file;
$filepath = file_unmanaged_copy($source, $paths['target'] . $base);
$paths['map'][$file] = $base;
......@@ -431,7 +431,7 @@ function color_scheme_form_submit($form, &$form_state) {
// Rewrite stylesheet with new colors.
$style = _color_rewrite_stylesheet($theme, $info, $paths, $palette, $style);
$base_file = basename($file);
$base_file = drupal_basename($file);
$css[] = $paths['target'] . $base_file;
_color_save_stylesheet($paths['target'] . $base_file, $style, $paths);
}
......@@ -571,7 +571,7 @@ function _color_render_images($theme, &$info, &$paths, $palette) {
// Cut out slices.
foreach ($info['slices'] as $file => $coord) {
list($x, $y, $width, $height) = $coord;
$base = basename($file);
$base = drupal_basename($file);
$image = drupal_realpath($paths['target'] . $base);
// Cut out slice.
......
......@@ -1065,6 +1065,9 @@ class FileTokenReplaceTestCase extends FileFieldTestCase {
$instance = field_info_instance('node', $field_name, $type_name);
$test_file = $this->getTestFile('text');
// Coping a file to test uploads with non-latin filenames.
$filename = drupal_dirname($test_file->uri) . '/текстовый файл.txt';
$test_file = file_copy($test_file, $filename);
// Create a new node with the uploaded file.
$nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
......
......@@ -192,7 +192,7 @@ class ImageStylesPathAndUrlUnitTest extends DrupalWebTestCase {
$this->assertNotIdentical(FALSE, $original_uri, t('Created the generated image file.'));
// Get the URL of a file that has not been generated and try to create it.
$generated_uri = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/'. basename($original_uri);
$generated_uri = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/'. drupal_basename($original_uri);
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
$generate_url = image_style_url($this->style_name, $original_uri);
......@@ -959,7 +959,7 @@ class ImageDimensionsUnitTest extends DrupalWebTestCase {
// Create a style.
$style = image_style_save(array('name' => 'test'));
$generated_uri = 'public://styles/test/public/'. basename($original_uri);
$generated_uri = 'public://styles/test/public/'. drupal_basename($original_uri);
$url = image_style_url('test', $original_uri);
$variables = array(
......
......@@ -254,7 +254,7 @@ function locale_translate_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), 'uri' => $filepath);
$file = (object) array('filename' => drupal_basename($filepath), 'uri' => $filepath);
_locale_import_read_po('db-store', $file, LOCALE_IMPORT_KEEP, $langcode[2]);
$context['results'][] = $filepath;
}
......
......@@ -1700,7 +1700,16 @@ protected function curlExec($curl_options, $redirect = FALSE) {
* An header.
*/
protected function curlHeaderCallback($curlHandler, $header) {
$this->headers[] = $header;
// Header fields can be extended over multiple lines by preceding each
// extra line with at least one SP or HT. They should be joined on receive.
// Details are in RFC2616 section 4.
if ($header[0] == ' ' || $header[0] == "\t") {
// Normalize whitespace between chucks.
$this->headers[] = array_pop($this->headers) . ' ' . trim($header);
}
else {
$this->headers[] = $header;
}
// Errors are being sent via X-Drupal-Assertion-* headers,
// generated by _drupal_log_error() in the exact form required
......
......@@ -254,7 +254,7 @@ function simpletest_result_form($form, &$form_state, $test_id) {
$row = array();
$row[] = $assertion->message;
$row[] = $assertion->message_group;
$row[] = basename($assertion->file);
$row[] = drupal_basename($assertion->file);
$row[] = $assertion->line;
$row[] = $assertion->function;
$row[] = simpletest_result_status_image($assertion->status);
......
......@@ -2162,7 +2162,7 @@ class DrupalErrorCollectionUnitTest extends DrupalWebTestCase {
function assertError($error, $group, $function, $file, $message = NULL) {
$this->assertEqual($error['group'], $group, t("Group was %group", array('%group' => $group)));
$this->assertEqual($error['caller']['function'], $function, t("Function was %function", array('%function' => $function)));
$this->assertEqual(basename($error['caller']['file']), $file, t("File was %file", array('%file' => $file)));
$this->assertEqual(drupal_basename($error['caller']['file']), $file, t("File was %file", array('%file' => $file)));
if (isset($message)) {
$this->assertEqual($error['message'], $message, t("Message was %message", array('%message' => $message)));
}
......
......@@ -198,7 +198,9 @@ class FileTestCase extends DrupalWebTestCase {
*/
function createFile($filepath = NULL, $contents = NULL, $scheme = NULL) {
if (!isset($filepath)) {
$filepath = $this->randomName();
// Prefix with non-latin characters to ensure that all file-related
// tests work with international filenames.
$filepath = 'Файл для тестирования ' . $this->randomName();
}
if (!isset($scheme)) {
$scheme = file_default_scheme();
......@@ -214,7 +216,7 @@ class FileTestCase extends DrupalWebTestCase {
$file = new stdClass();
$file->uri = $filepath;
$file->filename = basename($file->uri);
$file->filename = drupal_basename($file->uri);
$file->filemime = 'text/plain';
$file->uid = 1;
$file->timestamp = REQUEST_TIME;
......@@ -372,11 +374,11 @@ class FileValidatorTest extends DrupalWebTestCase {
$this->image = new stdClass();
$this->image->uri = 'core/misc/druplicon.png';
$this->image->filename = basename($this->image->uri);
$this->image->filename = drupal_basename($this->image->uri);
$this->non_image = new stdClass();
$this->non_image->uri = 'core/misc/jquery.js';
$this->non_image->filename = basename($this->non_image->uri);
$this->non_image->filename = drupal_basename($this->non_image->uri);
}
/**
......@@ -539,7 +541,7 @@ class FileUnmanagedSaveDataTest extends FileTestCase {
// Provide a filename.
$filepath = file_unmanaged_save_data($contents, 'public://asdf.txt', FILE_EXISTS_REPLACE);
$this->assertTrue($filepath, t('Unnamed file saved correctly.'));
$this->assertEqual('asdf.txt', basename($filepath), t('File was named correctly.'));
$this->assertEqual('asdf.txt', drupal_basename($filepath), t('File was named correctly.'));
$this->assertEqual($contents, file_get_contents($filepath), t('Contents of the file are correct.'));
$this->assertFilePermissions($filepath, variable_get('file_chmod_file', 0664));
}
......@@ -666,7 +668,7 @@ class FileSaveUploadTest extends FileHookTestCase {
$this->drupalPost('file-test/upload', $edit, t('Submit'));
$this->assertResponse(200, t('Received a 200 response for posted test file.'));
$this->assertRaw(t('You WIN!'));
$this->assertTrue(is_file('temporary://' . $dir . '/' . trim(basename($image3_realpath))));
$this->assertTrue(is_file('temporary://' . $dir . '/' . trim(drupal_basename($image3_realpath))));
// Check that file_load_multiple() with no arguments returns FALSE.
$this->assertFalse(file_load_multiple(), t('No files were loaded.'));
......@@ -2202,7 +2204,7 @@ class FileSaveDataTest extends FileHookTestCase {
$this->assertTrue($result, t('Unnamed file saved correctly.'));
$this->assertEqual(file_default_scheme(), file_uri_scheme($result->uri), t("File was placed in Drupal's files directory."));
$this->assertEqual($result->filename, basename($result->uri), t("Filename was set to the file's basename."));
$this->assertEqual($result->filename, drupal_basename($result->uri), t("Filename was set to the file's basename."));
$this->assertEqual($contents, file_get_contents($result->uri), t('Contents of the file are correct.'));
$this->assertEqual($result->filemime, 'application/octet-stream', t('A MIME type was set.'));
$this->assertEqual($result->status, FILE_STATUS_PERMANENT, t("The file's status was set to permanent."));
......@@ -2220,11 +2222,14 @@ class FileSaveDataTest extends FileHookTestCase {
function testWithFilename() {
$contents = $this->randomName(8);
$result = file_save_data($contents, 'public://' . 'asdf.txt');
// Using filename with non-latin characters.
$filename = 'Текстовый файл.txt';
$result = file_save_data($contents, 'public://' . $filename);
$this->assertTrue($result, t('Unnamed file saved correctly.'));
$this->assertEqual('public', file_uri_scheme($result->uri), t("File was placed in Drupal's files directory."));
$this->assertEqual('asdf.txt', basename($result->uri), t('File was named correctly.'));
$this->assertEqual($filename, drupal_basename($result->uri), t('File was named correctly.'));
$this->assertEqual($contents, file_get_contents($result->uri), t('Contents of the file are correct.'));
$this->assertEqual($result->filemime, 'text/plain', t('A MIME type was set.'));
$this->assertEqual($result->status, FILE_STATUS_PERMANENT, t("The file's status was set to permanent."));
......@@ -2336,7 +2341,10 @@ class FileDownloadTest extends FileTestCase {
// Test generating an URL to a created file.
$file = $this->createFile();
$url = file_create_url($file->uri);
$this->assertEqual($GLOBALS['base_url'] . '/' . file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath() . '/' . $file->filename, $url, t('Correctly generated a URL for a created file.'));
// URLs can't contain characters outside the ASCII set so $filename has to be
// encoded.
$filename = $GLOBALS['base_url'] . '/' . file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath() . '/' . rawurlencode($file->filename);
$this->assertEqual($filename, $url, t('Correctly generated a URL for a created file.'));
$this->drupalHead($url);
$this->assertResponse(200, t('Confirmed that the generated URL is correct by downloading the created file.'));
......@@ -2356,16 +2364,20 @@ class FileDownloadTest extends FileTestCase {
// Set file downloads to private so handler functions get called.
// Create a file.
$file = $this->createFile(NULL, NULL, 'private');
$contents = $this->randomName(8);
$file = $this->createFile(NULL, $contents, 'private');
$url = file_create_url($file->uri);
// Set file_test access header to allow the download.
file_test_set_return('download', array('x-foo' => 'Bar'));
$this->drupalHead($url);
$this->drupalGet($url);
$headers = $this->drupalGetHeaders();
$this->assertEqual($headers['x-foo'] , 'Bar', t('Found header set by file_test module on private download.'));
$this->assertEqual($headers['x-foo'], 'Bar', t('Found header set by file_test module on private download.'));
$this->assertResponse(200, t('Correctly allowed access to a file when file_test provides headers.'));
// Test that the file transfered correctly.
$this->assertEqual($contents, $this->content, t('Contents of the file are correct.'));
// Deny access to all downloads via a -1 header.
file_test_set_return('download', -1);
$this->drupalHead($url);
......@@ -2602,7 +2614,7 @@ class FileMimeTypeTest extends DrupalWebTestCase {
* Test mapping of mimetypes from filenames.
*/
public function testFileMimeTypeDetection() {
$prefix = 'simpletest://';
$prefix = 'public://';
$test_case = array(
'test.jar' => 'application/java-archive',
......
......@@ -138,7 +138,7 @@ function _file_test_form_submit(&$form, &$form_state) {
/**
* Reset/initialize the history of calls to the file_* hooks.
*
* @see file_test_get_calls()
* @see file_test_get_calls()
* @see file_test_reset()
*/
function file_test_reset() {
......
......@@ -3461,12 +3461,12 @@ function system_image_toolkits() {
function system_retrieve_file($url, $destination = NULL, $managed = FALSE, $replace = FILE_EXISTS_RENAME) {
$parsed_url = parse_url($url);
if (!isset($destination)) {
$path = file_build_uri(basename($parsed_url['path']));
$path = file_build_uri(drupal_basename($parsed_url['path']));
}
else {
if (is_dir(drupal_realpath($destination))) {
// Prevent URIs with triple slashes when glueing parts together.
$path = str_replace('///', '//', "$destination/") . basename($parsed_url['path']);
$path = str_replace('///', '//', "$destination/") . drupal_basename($parsed_url['path']);
}
else {
$path = $destination;
......
......@@ -2265,7 +2265,7 @@ class RetrieveFileTestCase extends DrupalWebTestCase {
function testFileRetrieving() {
// Test 404 handling by trying to fetch a randomly named file.
drupal_mkdir($sourcedir = 'public://' . $this->randomName());
$filename = $this->randomName();
$filename = 'Файл для тестирования ' . $this->randomName();
$url = file_create_url($sourcedir . '/' . $filename);
$retrieved_file = system_retrieve_file($url);
$this->assertFalse($retrieved_file, t('Non-existent file not fetched.'));
......@@ -2273,7 +2273,12 @@ class RetrieveFileTestCase extends DrupalWebTestCase {
// Actually create that file, download it via HTTP and test the returned path.
file_put_contents($sourcedir . '/' . $filename, 'testing');
$retrieved_file = system_retrieve_file($url);
$this->assertEqual($retrieved_file, 'public://' . $filename, t('Sane path for downloaded file returned (public:// scheme).'));
// URLs could not contains characters outside the ASCII set so $filename
// has to be encoded.
$encoded_filename = rawurlencode($filename);
$this->assertEqual($retrieved_file, 'public://' . $encoded_filename, t('Sane path for downloaded file returned (public:// scheme).'));
$this->assertTrue(is_file($retrieved_file), t('Downloaded file does exist (public:// scheme).'));
$this->assertEqual(filesize($retrieved_file), 7, t('File size of downloaded file is correct (public:// scheme).'));
file_unmanaged_delete($retrieved_file);
......@@ -2281,7 +2286,7 @@ class RetrieveFileTestCase extends DrupalWebTestCase {
// Test downloading file to a different location.
drupal_mkdir($targetdir = 'temporary://' . $this->randomName());
$retrieved_file = system_retrieve_file($url, $targetdir);
$this->assertEqual($retrieved_file, "$targetdir/$filename", t('Sane path for downloaded file returned (temporary:// scheme).'));
$this->assertEqual($retrieved_file, "$targetdir/$encoded_filename", t('Sane path for downloaded file returned (temporary:// scheme).'));
$this->assertTrue(is_file($retrieved_file), t('Downloaded file does exist (temporary:// scheme).'));
$this->assertEqual(filesize($retrieved_file), 7, t('File size of downloaded file is correct (temporary:// scheme).'));
file_unmanaged_delete($retrieved_file);
......
......@@ -816,7 +816,7 @@ function update_manager_file_get($url) {
// Check the cache and download the file if needed.
$cache_directory = _update_manager_cache_directory();
$local = $cache_directory . '/' . basename($parsed_url['path']);
$local = $cache_directory . '/' . drupal_basename($parsed_url['path']);
if (!file_exists($local) || update_delete_file_if_stale($local)) {
return system_retrieve_file($url, $local, FALSE, FILE_EXISTS_REPLACE);
......
......@@ -695,14 +695,14 @@ function update_verify_update_archive($project, $archive_file, $directory) {
}
if (empty($files)) {
$errors[] = t('%archive_file does not contain any .info files.', array('%archive_file' => basename($archive_file)));
$errors[] = t('%archive_file does not contain any .info files.', array('%archive_file' => drupal_basename($archive_file)));
}
elseif (!$compatible_project) {
$errors[] = format_plural(
count($incompatible),
'%archive_file contains a version of %names that is not compatible with Drupal !version.',
'%archive_file contains versions of modules or themes that are not compatible with Drupal !version: %names',
array('!version' => DRUPAL_CORE_COMPATIBILITY, '%archive_file' => basename($archive_file), '%names' => implode(', ', $incompatible))
array('!version' => DRUPAL_CORE_COMPATIBILITY, '%archive_file' => drupal_basename($archive_file), '%names' => implode(', ', $incompatible))
);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment