summaryrefslogtreecommitdiff
path: root/includes/file.inc
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2006-03-07 19:14:30 +0000
committerDries Buytaert <dries@buytaert.net>2006-03-07 19:14:30 +0000
commitdda131587fa50ae5b5b40d3ab21b644ea5b1271d (patch)
treecd2b6d557c62281f1c268b9342f4169ebfd6fd7d /includes/file.inc
parent9530e545012d42f8d13b198b8e73793f5ae5352e (diff)
downloadbrdo-dda131587fa50ae5b5b40d3ab21b644ea5b1271d.tar.gz
brdo-dda131587fa50ae5b5b40d3ab21b644ea5b1271d.tar.bz2
- Patch #5961 by dopry et al: fixed problems with file api and open_basedir restrictions.
Diffstat (limited to 'includes/file.inc')
-rw-r--r--includes/file.inc116
1 files changed, 90 insertions, 26 deletions
diff --git a/includes/file.inc b/includes/file.inc
index f8d7b91e6..edaa02a5d 100644
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -130,42 +130,120 @@ function file_check_path(&$path) {
return false;
}
+
/**
- * Check if $source is a valid file upload. If so, process $_FILES
- * and return its contents as an object.
+ * Check if $source is a valid file upload. If so, move the file to Drupal's tmp dir
+ * and return it as an object.
+ *
+ * The use of SESSION['file_uploads'] should probably be externalized to upload.module
+ *
+ * @todo Rename file_check_upload to file_prepare upload.
+ * @todo Refactor or merge file_save_upload.
+ * @todo Extenalize SESSION['file_uploads'] to modules.
*
* @param $source
+ * @return false for an invalid file or upload. A file object for valid uploads/files.
+ *
*/
-function file_check_upload($source) {
+
+function file_check_upload($source = 'upload') {
+ // Cache for uploaded files. Since the data in _FILES is modified
+ // by this function, we cache the result.
+ static $upload_cache;
+
+ // Test source to see if it is an object.
if (is_object($source)) {
+
+ // Validate the file path if an object was passed in instead of
+ // an upload key.
if (is_file($source->filepath)) {
return $source;
}
+ else {
+ return false;
+ }
+ }
+
+ // Return cached objects without processing since the file will have
+ // already been processed and the paths in _FILES will be invalid.
+ if (isset($upload_cache[$source])) {
+ return $upload_cache[$source];
}
- elseif ($_FILES["edit"]["name"][$source] && is_uploaded_file($_FILES["edit"]["tmp_name"][$source])) {
+
+ // If a file was uploaded, process it.
+ if ($_FILES["edit"]["name"][$source] && is_uploaded_file($_FILES["edit"]["tmp_name"][$source])) {
+
+ // Check for file upload errors and return false if a
+ // lower level system error occurred.
+ switch ($_FILES["edit"]["error"][$source]) {
+
+ // We are not actually using the constants since they weren't introduced
+ // until php 4.3.0.
+
+ // UPLOAD_ERR_OK: File uploaded successfully
+ case 0:
+ break;
+
+ // UPLOAD_ERR_INI_SIZE: File size exceeded php.ini value
+ case 1:
+ // UPLOAD_ERR_FORM_SIZE: File size exceeded MAX_FILE_SIZE form value
+ case 2:
+ drupal_set_message(t('The file %file could not be saved, because it exceeds the maximum allowed size for uploads.', array('%file' => theme('placeholder', $source))), 'error');
+ return 0;
+
+ // UPLOAD_ERR_PARTIAL: File was only partially uploaded
+ case 3:
+ // UPLOAD_ERR_NO_FILE: No file was uploaded
+ case 4:
+ drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => theme('placeholder', $source))), 'error');
+ return 0;
+
+ // Unknown error
+ default:
+ drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => theme('placeholder', $source))),'error');
+ return 0;
+ }
+
+ // Begin building file object.
$file = new StdClass();
$file->filename = trim(basename($_FILES["edit"]["name"][$source]), '.');
- $file->filepath = $_FILES["edit"]["tmp_name"][$source];
+
+ // Create temporary name/path for newly uploaded files.
+ $file->filepath = tempnam(file_directory_temp(), 'tmp_');
+
$file->filemime = $_FILES["edit"]["type"][$source];
+ // Rename potentially executable files, to help prevent exploits.
if (((substr($file->filemime, 0, 5) == 'text/' || strpos($file->filemime, 'javascript')) && (substr($file->filename, -4) != '.txt')) || preg_match('/\.(php|pl|py|cgi|asp)$/i', $file->filename)) {
$file->filemime = 'text/plain';
- rename($file->filepath, $file->filepath .'.txt');
$file->filepath .= '.txt';
$file->filename .= '.txt';
}
- $file->error = $_FILES["edit"]["error"][$source];
+ // Move uploaded files from php's upload_tmp_dir to Drupal's file temp.
+ // This overcomes open_basedir restrictions for future file operations.
+ if (!move_uploaded_file($_FILES["edit"]["tmp_name"][$source], $file->filepath)) {
+ drupal_set_message(t('File upload error. Could not move uploaded file.'));
+ watchdog('file', t('Upload Error. Could not move uploaded file(%file) to destination(%destination).', array('%file' => theme('placeholder', $_FILES["edit"]["tmp_name"][$source]), '%destination' => theme('placeholder', $file->filepath))));
+ return false;
+ }
+
$file->filesize = $_FILES["edit"]["size"][$source];
$file->source = $source;
+
+ // Add processed file to the cache.
+ $upload_cache[$source] = $file;
return $file;
}
+
else {
// In case of previews return previous file object.
if (file_exists($_SESSION['file_uploads'][$source]->filepath)) {
return $_SESSION['file_uploads'][$source];
}
}
+ // If nothing was done, return false.
+ return false;
}
/**
@@ -372,9 +450,12 @@ function file_delete($path) {
* when in use, but when false append a _X to the filename.
* @return An object containing file info or 0 in case of error.
*/
-function file_save_upload($source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
- // Make sure $source exists in $_FILES.
+function file_save_upload($source, $dest = false, $replace = FILE_EXISTS_RENAME) {
+ // Make sure $source exists && is valid.
if ($file = file_check_upload($source)) {
+
+ // This should be refactored, file_check_upload has already
+ // moved the file to the temprary folder.
if (!$dest) {
$dest = file_directory_temp();
$temporary = 1;
@@ -384,23 +465,6 @@ function file_save_upload($source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
}
}
- // Check for file upload errors.
- switch ($file->error) {
- case 0: // UPLOAD_ERR_OK: File uploaded successfully
- break;
- case 1: // UPLOAD_ERR_INI_SIZE: File size exceeded php.ini value
- case 2: // UPLOAD_ERR_FORM_SIZE: File size exceeded MAX_FILE_SIZE form value
- drupal_set_message(t('The file %file could not be saved, because it exceeds the maximum allowed size for uploads.', array('%file' => theme('placeholder', $source))), 'error');
- return 0;
- case 3: // UPLOAD_ERR_PARTIAL: File was only partially uploaded
- case 4: // UPLOAD_ERR_NO_FILE: No file was uploaded
- drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => theme('placeholder', $source))), 'error');
- return 0;
- default: // Unknown error
- drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => theme('placeholder', $source))),'error');
- return 0;
- }
-
unset($_SESSION['file_uploads'][is_object($source) ? $source->source : $source]);
if (file_move($file, $dest, $replace)) {
if ($temporary) {