=== added file 'private.php' --- private.php 1970-01-01 00:00:00 +0000 +++ private.php 2007-08-18 19:38:13 +0000 @@ -0,0 +1,28 @@ +'.print_r($_SESSION).'', 'error'); + +// get file needed from $_GET +$filename = ''; +$headers = array(); + +// check node access +/* +if (node_access('view', $node)) { + + // pipe file + file_transfer($filename, $headers); +} +*/ \ No newline at end of file === modified file 'includes/common.inc' --- includes/common.inc 2007-09-20 08:30:34 +0000 +++ includes/common.inc 2007-09-26 03:04:07 +0000 @@ -1624,7 +1624,7 @@ function drupal_build_css_cache($types, $data = ''; // Create the css/ within the files folder. - $csspath = file_create_path('css'); + $csspath = _file_create_path('css', FILE_DOWNLOADS_PUBLIC); file_check_directory($csspath, FILE_CREATE_DIRECTORY); if (!file_exists($csspath .'/'. $filename)) { @@ -1668,7 +1668,7 @@ function drupal_build_css_cache($types, * Delete all cached CSS files. */ function drupal_clear_css_cache() { - file_scan_directory(file_create_path('css'), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE); + file_scan_directory(_file_create_path('css', FILE_DOWNLOADS_PUBLIC), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE); } /** @@ -1862,7 +1862,7 @@ function drupal_build_js_cache($files, $ $contents = ''; // Create the js/ within the files folder. - $jspath = file_create_path('js'); + $jspath = _file_create_path('js', FILE_DOWNLOADS_PUBLIC); file_check_directory($jspath, FILE_CREATE_DIRECTORY); if (!file_exists($jspath .'/'. $filename)) { @@ -2109,7 +2109,7 @@ function _packer_backreferences($match, * Delete all cached JS files. */ function drupal_clear_js_cache() { - file_scan_directory(file_create_path('js'), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE); + file_scan_directory(_file_create_path('js', FILE_DOWNLOADS_PUBLIC), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE); variable_set('javascript_parsed', array()); } === modified file 'includes/file.inc' --- includes/file.inc 2007-09-25 12:39:31 +0000 +++ includes/file.inc 2007-09-26 03:04:07 +0000 @@ -12,8 +12,8 @@ * Common file handling functions. */ -define('FILE_DOWNLOADS_PUBLIC', 1); -define('FILE_DOWNLOADS_PRIVATE', 2); +define('FILE_DOWNLOADS_PUBLIC', 0); +define('FILE_DOWNLOADS_PRIVATE', 1); define('FILE_CREATE_DIRECTORY', 1); define('FILE_MODIFY_PERMISSIONS', 2); define('FILE_EXISTS_RENAME', 0); @@ -32,40 +32,132 @@ define('FILE_EXISTS_ERROR', 2); define('FILE_STATUS_TEMPORARY', 0); define('FILE_STATUS_PERMANENT', 1); + +/** + * Create download path to a file. + * + * Unlike _file_create_url this takes a file object as input rather than a path. + * + * @param &$file + * A file object. + * @return + * A string containing the path to the desired file + */ +function file_create_url(&$file) { + // Avoid duplication with _file_create_url + if (!isset($file->private)) { + $file->private = FILE_DOWNLOADS_PUBLIC; + } + return _file_create_url($file->filename, $file->private); +} + + /** * Create the download path to a file. * - * @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. + * @param $path + * A string containing the path of the file to generate URL for. + * @param $private + * An integer indicated whether the file is public (0) or private (1). + * @return + * A string containing a URL that can be used to download the file. */ -function file_create_url($path) { +function _file_create_url($path, $private = FILE_DOWNLOADS_PUBLIC) { // 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())), '\\/'); } - 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)); + + // Check if the file is private + if ($private) { + // If it is private return a private file path + return url('system/files/'.$path, array('absolute' => TRUE)); // TODO: this will need to be changed when private.php is implemented + } + else { + // Otherwise return a public file path + return $GLOBALS['base_url'] .'/'. file_directory_path() .'/'. str_replace('\\', '/', $path); } } + /** * Make sure the destination is a complete path and resides in the file system * directory, if it is not prepend the file system directory. * - * @param $dest A string containing the path to verify. If this value is + * Unlike _file_create_path this function takes a file object as input rather than a path. + * + * @param $file + * A file object containing the path to verify and the public/private + * status of the file. + * @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). + */ +function file_create_path(&$file) { + + + /* + * Note by Kyle C + * + * This should probably be updated to have better logic. Something along the lines + * of if private isn't set then we should query the database. + */ + if (!isset($file->private)) { + $file->private = FILE_DOWNLOADS_PUBLIC; + } + + // Avoiding Duplication with _file_create_path + return _file_create_path($file->filename, $file->private); +} + +/** + * Make sure the destination is a complete path and resides in the file system + * directory, if it is not prepend the file system directory. + * + * @param $dest + * A string containing the path to verify. If this value is * omitted, Drupal's 'files' directory will be used. - * @return A string containing the path to file, with file system directory + * @param $private + * An integer containg 0 if the public file path + * should be checked or a 1 if the private file path should be checked. + * This should be omitted if it isn't known whether a file will reside + * in the public or private file path. + * @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). */ -function file_create_path($dest = 0) { - $file_path = file_directory_path(); +function _file_create_path($dest = 0, $private = NULL) { + + /* + A small performance hit will be necessary in some cases because it won't + be clear from the calling function whether a file will be residing in + the public or private file path. So in that case we query the database + to determine if the file is public or private. + */ + if ($private == NULL) { + + $result = db_query("SELECT private,status FROM {files} WHERE filepath='%s'",$dest); + while($file = db_fetch_object($result) ) { + $private = $file->private; + } + + } + + // If private look in private files directory otherwise look in public files directory + if ($private == FILE_DOWNLOADS_PRIVATE) { + $file_path = file_directory_private_path(); + } + else { + $file_path = file_directory_path(); + } + + // Return file_directory_path if $dest is not supplied if (!$dest) { return $file_path; } + // file_check_location() checks whether the destination is inside the Drupal files directory. if (file_check_location($dest, $file_path)) { return $dest; @@ -211,11 +303,15 @@ function file_check_location($source, $d * - FILE_EXISTS_REPLACE - Replace the existing file * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique * - FILE_EXISTS_ERROR - Do nothing and return FALSE. - * @return True for success, FALSE for failure. + * @param $private An integer indicating whether the file should be copied to Drupal's + * public or private file path. + * FILE_DOWNLOADS_PUBLIC - The public file path should be used. + * FILE_DOWNLOADS_PRIVATE - The private file path should be used. + * @return TRUE for success, FALSE for failure. */ -function file_copy(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) { - $dest = file_create_path($dest); - +function file_copy(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME, $private = FILE_DOWNLOADS_PUBLIC) { + + $dest = _file_create_path($dest, $private); $directory = $dest; $basename = file_check_path($directory); @@ -289,7 +385,7 @@ function file_copy(&$source, $dest = 0, * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is * unique * - FILE_EXISTS_ERROR - Do nothing and return FALSE. - * @return The destination file path or FALSE if the file already exists and + * @return The destination file path or FALSE if the file already exists or * FILE_EXISTS_ERROR was specified. */ function file_destination($destination, $replace) { @@ -325,12 +421,16 @@ function file_destination($destination, * - FILE_EXISTS_REPLACE - Replace the existing file * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique * - FILE_EXISTS_ERROR - Do nothing and return FALSE. + * @param $private An integer indicating whether the file should be moved to Drupal's + * public or private file path. + * - FILE_DOWNLOADS_PUBLIC - The public file path should be used. + * - FILE_DOWNLOADS_PRIAVTE - The private file path should be used. * @return True for success, FALSE for failure. */ -function file_move(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) { +function file_move(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME, $private = FILE_DOWNLOADS_PUBLIC) { $path_original = is_object($source) ? $source->filepath : $source; - if (file_copy($source, $dest, $replace)) { + if (file_copy($source, $dest, $replace, $private)) { $path_current = is_object($source) ? $source->filepath : $source; if ($path_original == $path_current || file_delete($path_original)) { @@ -413,6 +513,7 @@ function file_create_filename($basename, } else { $name = $basename; + $ext = ""; } $counter = 0; @@ -538,7 +639,7 @@ function file_save_upload($source, $vali // Create temporary name/path for newly uploaded files. if (!$dest) { - $dest = file_destination(file_create_path($file->filename), FILE_EXISTS_RENAME); + $dest = file_destination(file_create_path($file), FILE_EXISTS_RENAME); } $file->source = $source; $file->destination = $dest; @@ -766,8 +867,10 @@ function file_save_data($data, $dest, $r /** * Set the status of a file. * - * @param file A Drupal file object - * @param status A status value to set the file to. + * @param file + * Drupal file object + * @param status + * A status value to set the file to. * @return FALSE on failure, TRUE on success and $file->status will contain the * status. */ @@ -797,7 +900,7 @@ function file_transfer($source, $headers drupal_set_header($header); } - $source = file_create_path($source); + $source = _file_create_path($source, FILE_DOWNLOADS_PRIVATE); // Transfer file in 1024 byte chunks to save memory usage. if ($fd = fopen($source, 'rb')) { @@ -829,7 +932,7 @@ function file_download() { $filepath = $_GET['file']; } - if (file_exists(file_create_path($filepath))) { + if (file_exists(_file_create_path($filepath, FILE_DOWNLOADS_PUBLIC))) { $headers = module_invoke_all('file_download', $filepath); if (in_array(-1, $headers)) { return drupal_access_denied(); @@ -956,6 +1059,15 @@ function file_directory_path() { } /** + * Determine the default 'private-files' directory + * + * @return A string containing the path to Drupal's private-files directory. + */ +function file_directory_private_path() { + return variable_get('file_private_path', 'private-files'); +} + +/** * Determine the maximum file upload size by querying the PHP settings. * * @return @@ -972,3 +1084,57 @@ function file_upload_max_size() { } return $max_size; } + + +/** + * Set file accessibility in Drupal's database and update file path accordingly. + * + * @param + * A file object that has had its "private" variable updated to + * indicate whether the file should be public or private. + * - To have the file be privately accessible the "private" field should be set to FILE_DOWNLOADS_PRIVATE. + * . - To have the file be publicly accessible the "private" field should be set to FILE_DOWNLOADS_PUBLC. + * @return + * A boolean with TRUE if the operation was successful and FALSE if the operation failed. + */ +function file_set_private(&$file) { + + // Make sure private member is set + if (!isset($file->private)) { + $file->private = FILE_DOWNLOADS_PUBLIC; + } + + // If file is private we check the private directory to make sure it is writable, if not the directory is created + if ($file->private && file_check_directory(file_directory_private_path(), FILE_CREATE_DIRECTORY)) { + + // Move file to private path + if (file_move($file, file_directory_private_path(), FILE_EXISTS_RENAME, FILE_DOWNLOADS_PRIVATE) ) { + $file->filename = basename($file->filepath); + $result = db_query("UPDATE {files} SET private='%d', filepath='%s', filename='%s' WHERE fid='%d'", $file->private, $file->filepath, $file->filename, $file->fid); + return TRUE; + } + elseif ($file->private) { + drupal_set_message (t('The chosen private path is not writable or cannot be created, please choose another.'),'error'); + return FALSE; + } + else { + drupal_set_message (t('The chosen file could not be moved to the private path.'),'error'); + return FALSE; + } + } + + // If this point has be reached the file is public + if (file_check_directory(file_directory_path(), FILE_CREATE_DIRECTORY)) { + if (file_move($file->filepath, file_directory_path(), FILE_EXISTS_RENAME, FILE_DOWNLOADS_PUBLIC)) { + $file->filename = basename($file->filepath); + $result = db_query("UPDATE {files} SET private='%d', filepath='%s', filename='%s' WHERE fid='%d'",$file->private, $file->filepath, $file->filename, $file->fid); + return TRUE; + } + else { + drupal_set_message(t('The chosen file could not be moved to the public path.'), 'error'); + } + } + + return FALSE; +} + === modified file 'includes/locale.inc' --- includes/locale.inc 2007-09-04 21:10:45 +0000 +++ includes/locale.inc 2007-09-26 03:04:08 +0000 @@ -1629,7 +1629,7 @@ function _locale_update_js_files() { // Add the translation JavaScript file to the page. if ($files && !empty($language->javascript)) { - drupal_add_js(file_create_path(variable_get('locale_js_directory', 'languages') .'/'. $language->language .'_'. $language->javascript .'.js'), 'core'); + drupal_add_js(_file_create_path(variable_get('locale_js_directory', 'languages') .'/'. $language->language .'_'. $language->javascript .'.js', FILE_DOWNLOADS_PUBLIC), 'core'); } } @@ -2100,14 +2100,14 @@ function _locale_rebuild_js($langcode = // Construct the directory 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 = _file_create_path(variable_get('locale_js_directory', 'languages'), FILE_DOWNLOADS_PUBLIC); // Only create a new file if the content has changed. $data_hash = md5($data); if ($language->javascript != $data_hash) { if (!empty($language->javascript)) { // We are recreating the new file, so delete the old one. - file_delete(file_create_path($dir .'/'. $language->language .'_'. $language->javascript .'.js')); + file_delete(_file_create_path($dir .'/'. $language->language .'_'. $language->javascript .'.js', FILE_DOWNLOADS_PUBLIC)); $language->javascript = ''; } else { @@ -2155,7 +2155,7 @@ function _locale_rebuild_js($langcode = // delete it and reset the database. elseif (!empty($language->javascript)) { // Delete the old JavaScript file - file_delete(file_create_path(variable_get('locale_js_directory', 'languages') .'/'. $language->language .'_'. $language->javascript .'.js')); + file_delete(_file_create_path(variable_get('locale_js_directory', 'languages') .'/'. $language->language .'_'. $language->javascript .'.js', FILE_DOWNLOADS_PUBLIC)); db_query("UPDATE {languages} SET javascript = '' WHERE language = '%s'", $language->language); watchdog('locale', 'Deleted JavaScript translation file for the locale %language.', array('%language' => t($language->name))); } === modified file 'modules/blogapi/blogapi.module' --- modules/blogapi/blogapi.module 2007-09-05 08:42:01 +0000 +++ modules/blogapi/blogapi.module 2007-09-26 03:04:07 +0000 @@ -367,7 +367,7 @@ function blogapi_metaweblog_new_media_ob } // Return the successful result. - return array('url' => file_create_url($file), 'struct'); + return array('url' => _file_create_url($file, FILE_DOWNLOADS_PUBLIC), 'struct'); } /** * Blogging API callback. Returns a list of the taxonomy terms that can be === modified file 'modules/locale/locale.install' --- modules/locale/locale.install 2007-09-02 15:19:16 +0000 +++ modules/locale/locale.install 2007-09-26 03:04:08 +0000 @@ -126,7 +126,7 @@ function locale_uninstall() { $files = db_query('SELECT javascript FROM {languages}'); while ($file = db_fetch_object($files)) { if (!empty($file)) { - file_delete(file_create_path($file->javascript)); + file_delete(file_create_path($file)); } } === modified file 'modules/system/system.admin.inc' --- modules/system/system.admin.inc 2007-09-14 12:16:55 +0000 +++ modules/system/system.admin.inc 2007-09-26 03:04:08 +0000 @@ -1266,6 +1266,15 @@ function system_file_system_settings() { '#after_build' => array('system_check_directory'), ); + $form['file_private_path'] = array( + '#type' => 'textfield', + '#title' => t('Private file path'), + '#default_value' => file_directory_private_path(), + '#maxlength' => 255, + '#description' => t('A file system path where priavte files will be stored. This directory has to exist and be writable by Drupal. Changing this location after the site has been in use will cause problems so only change this setting on an existing site if you know what you are doing.'), + '#after_build' => array('system_check_directory','system_set_htaccess'), + ); + $form['file_directory_temp'] = array( '#type' => 'textfield', '#title' => t('Temporary directory'), @@ -1277,10 +1286,10 @@ function system_file_system_settings() { $form['file_downloads'] = array( '#type' => 'radios', - '#title' => t('Download method'), + '#title' => t('Default Download method'), '#default_value' => variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC), '#options' => array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using HTTP directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')), - '#description' => t('If you want any sort of access control on the downloading of files, this needs to be set to private. You can change this at any time, however all download URLs will change and there may be unexpected problems so it is not recommended.') + '#description' => t('Public files are accessible by everyone whereas private files are only accessible by those who can view the node the file is attached to.') ); return system_settings_form($form); === modified file 'modules/system/system.install' --- modules/system/system.install 2007-09-20 08:37:22 +0000 +++ modules/system/system.install 2007-09-26 03:04:08 +0000 @@ -3714,6 +3714,14 @@ function system_update_6029() { return array(); } +function system_update_6030() { + $ret = array(); + + // Create files column + db_add_field($ret, 'files', 'private', array('type' => 'int', 'not null' => TRUE, 'default' => 0)); +} + + /** * Add the tables required by actions.inc. */ === modified file 'modules/system/system.module' --- modules/system/system.module 2007-09-25 11:49:36 +0000 +++ modules/system/system.module 2007-09-26 03:04:07 +0000 @@ -590,7 +590,7 @@ function system_theme_select_form($descr /** * Checks the existence of the directory specified in $form_element. This * function is called from the system_settings form to check both the - * file_directory_path and file_directory_temp directories. If validation + * file_directory_path, file_private_path and file_directory_temp directories. If validation * fails, the form element is flagged with an error from within the * file_check_directory function. * @@ -603,6 +603,42 @@ function system_check_directory($form_el } /** + * Set .htaccess file in private files directory to prevent file reads through apache. + * + * This is intended as a callback for private files form to create the corresponding .htaccess file + * so the bad guys can't get to private files if the private file directory happens to reside in + * the web root. + * + * @param $form_element + * The form element containing the name of the directory to prevent access to. + */ + function system_set_htaccess($form_element) { + + // Prevent files from being accessed and prevent directory listing + // Start with a newline in case there isn't a newline at the end of the file + $htcontents ="\norder allow,deny\ndeny from all\nIndexIgnore *\n"; + $location = $form_element['#value'].'/.htaccess'; + + // Check if contents have already been written + if (file_exists($location)) { + $oldcontents = file_get_contents($location); + if ($oldcontents !== FALSE && strstr($oldcontents, $htcontents) !== FALSE) { + return $form_element; + } + } + + // Write .htaccess contents + if (!file_put_contents($location,$htcontents,FILE_APPEND)) { + form_set_error($form_element['#parents'][0],'The .htaccess file in the private files directory could not be written to.'); + } + else { + drupal_set_message('The private files directory has been protected from external access.', 'status'); + } + + return $form_element; +} + +/** * Retrieves the current status of an array of files in the system table. */ function system_get_files_database(&$files, $type) { === modified file 'modules/system/system.schema' --- modules/system/system.schema 2007-09-11 19:14:34 +0000 +++ modules/system/system.schema 2007-09-26 03:04:08 +0000 @@ -68,6 +68,7 @@ function system_schema() { 'filemime' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), 'filesize' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0), 'status' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), + 'private' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), 'timestamp' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0), ), 'indexes' => array( === modified file 'modules/upload/upload.admin.inc' --- modules/upload/upload.admin.inc 2007-08-07 08:39:35 +0000 +++ modules/upload/upload.admin.inc 2007-08-15 21:05:46 +0000 @@ -80,6 +80,14 @@ function upload_admin_settings() { '#options' => array(0 => t('No'), 1 => t('Yes')), '#description' => t('Set whether files attached to nodes are listed or not in the node view by default.'), ); + + $form['settings_general']['upload_private_default'] = array( + '#type' => 'radios', + '#title' => t('Upload access default'), + '#default_value' => variable_get('upload_private_default', FILE_DOWNLOADS_PUBLIC), + '#options' => array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using HTTP directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')), + '#description' => t('This determines whether file uploads will be publicly or privately accessible by default'), + ); $form['settings_general']['upload_extensions_default'] = array( '#type' => 'textfield', === modified file 'modules/upload/upload.module' --- modules/upload/upload.module 2007-09-12 18:29:31 +0000 +++ modules/upload/upload.module 2007-09-26 03:13:22 +0000 @@ -1,5 +1,5 @@ list to 0 for checkboxes added to a form after // it has been submitted. Since unchecked checkboxes have no return value and do not @@ -184,22 +192,25 @@ function upload_node_form_submit($form, // Save new file uploads. if (($user->uid != 1 || user_access('upload files')) && ($file = file_save_upload('upload', $validators))) { - $file->list = variable_get('upload_list_default', 1); + $file->private = variable_get('upload_private_default', FILE_DOWNLOADS_PUBLIC); + $file->list = variable_get('upload_list_default',1); $file->description = $file->filename; $_SESSION['upload_current_file'] = $file->fid; $_SESSION['upload_files'][$file->fid] = $file; } // attach session files to node. - if (!empty($_SESSION['upload_files'])) { - foreach ($_SESSION['upload_files'] as $fid => $file) { - $form_state['values']['files'][$fid] = $file; + if (count($_SESSION['upload_files'])) { + foreach($_SESSION['upload_files'] as $fid => $file) { + $node->files[$fid] = $file; } } + } function upload_form_alter(&$form, $form_state, $form_id) { if ($form_id == 'node_type_form' && isset($form['identity']['type'])) { + $form['#cache'] = FALSE; $form['workflow']['upload'] = array( '#type' => 'radios', '#title' => t('Attachments'), @@ -249,7 +260,6 @@ function upload_form_alter(&$form, $form $form['#attributes']['enctype'] = 'multipart/form-data'; } } - $form['#submit'][] = 'upload_node_form_submit'; } } @@ -267,6 +277,10 @@ function upload_nodeapi(&$node, $op, $te } break; + case 'prepare': + _upload_prepare($node); + break; + case 'view': if (isset($node->files) && user_access('view uploaded files')) { // Add the attachments list to node body with a heavy @@ -282,16 +296,6 @@ function upload_nodeapi(&$node, $op, $te } break; - case 'prepare': - // Initialize $_SESSION['upload_files'] if no post occurred. - // This clears the variable from old forms and makes sure it - // is an array to prevent notices and errors in other parts - // of upload.module. - if (!$_POST) { - $_SESSION['upload_files'] = array(); - } - break; - case 'insert': case 'update': if (user_access('upload files')) { @@ -325,7 +329,7 @@ function upload_nodeapi(&$node, $op, $te array( 'key' => 'enclosure', 'attributes' => array( - 'url' => file_create_url($file->filepath), + 'url' => file_create_url($file), 'length' => $file->filesize, 'type' => $file->filemime ) @@ -346,7 +350,7 @@ function theme_upload_attachments($files foreach ($files as $file) { $file = (object)$file; if ($file->list && empty($file->remove)) { - $href = file_create_url($file->filepath); + $href = file_create_url($file); $text = $file->description ? $file->description : $file->filename; $rows[] = array(l($text, $href), format_size($file->filesize)); } @@ -389,16 +393,8 @@ function upload_save(&$node) { // Remove file. Process removals first since no further processing // will be required. - if (!empty($file->remove)) { + if ($file->remove) { db_query('DELETE FROM {upload} WHERE fid = %d AND vid = %d', $fid, $node->vid); - - // If the file isn't used by any other revisions delete it. - $count = db_result(db_query('SELECT COUNT(fid) FROM {upload} WHERE fid = %d', $fid)); - if ($count < 1) { - file_delete($file->filepath); - db_query('DELETE FROM {files} WHERE fid = %d', $fid); - } - // Remove it from the session in the case of new uploads, // that you want to disassociate before node submission. unset($_SESSION['upload_files'][$fid]); @@ -407,14 +403,16 @@ function upload_save(&$node) { } // Create a new revision, or associate a new file needed. - if (!empty($node->old_vid) || isset($_SESSION['upload_files'][$fid])) { + if (!empty($node->old_vid) || array_key_exists($fid, $_SESSION['upload_files'])) { db_query("INSERT INTO {upload} (fid, nid, vid, list, description) VALUES (%d, %d, %d, %d, '%s')", $file->fid, $node->nid, $node->vid, $file->list, $file->description); file_set_status($file, FILE_STATUS_PERMANENT); + file_set_private($file); } // Update existing revision. else { db_query("UPDATE {upload} SET list = %d, description = '%s' WHERE fid = %d AND vid = %d", $file->list, $file->description, $file->fid, $node->vid); file_set_status($file, FILE_STATUS_PERMANENT); + file_set_private($file); } } // Empty the session storage after save. We use this variable to track files @@ -424,7 +422,7 @@ function upload_save(&$node) { function upload_delete($node) { $files = array(); - $result = db_query('SELECT DISTINCT f.* FROM {upload} u INNER JOIN {files} f ON u.fid = f.fid WHERE u.nid = %d', $node->nid); + $result = db_query('SELECT DISTINCT f.* FROM upload u INNER JOIN files f ON u.fid = f.fid WHERE u.nid = %d', $node->nid); while ($file = db_fetch_object($result)) { $files[$file->fid] = $file; } @@ -466,11 +464,11 @@ function _upload_form($node) { $form['files']['#theme'] = 'upload_form_current'; $form['files']['#tree'] = TRUE; foreach ($node->files as $key => $file) { - $file = (object)$file; - $description = file_create_url($file->filepath); + $description = file_create_url($file); $description = "". check_plain($description) .""; $form['files'][$key]['description'] = array('#type' => 'textfield', '#default_value' => !empty($file->description) ? $file->description : $file->filename, '#maxlength' => 256, '#description' => $description ); $form['files'][$key]['size'] = array('#value' => format_size($file->filesize)); + $form['files'][$key]['private'] = array('#type' => 'radios', '#options' => array(FILE_DOWNLOADS_PUBLIC => 'Public', FILE_DOWNLOADS_PRIVATE => 'Private'), '#default_value' => $file->private ); $form['files'][$key]['remove'] = array('#type' => 'checkbox', '#default_value' => !empty($file->remove)); $form['files'][$key]['list'] = array('#type' => 'checkbox', '#default_value' => $file->list); // If the file was uploaded this page request, set value. this fixes the @@ -514,12 +512,13 @@ function _upload_form($node) { * Theme the attachments list. */ function theme_upload_form_current(&$form) { - $header = array(t('Delete'), t('List'), t('Description'), t('Size')); + $header = array(t('Delete'), t('List'),t('Access'), t('Description'), t('Size')); foreach (element_children($form) as $key) { $row = array(); $row[] = drupal_render($form[$key]['remove']); $row[] = drupal_render($form[$key]['list']); + $row[] = drupal_render($form[$key]['private']); $row[] = drupal_render($form[$key]['description']); $row[] = drupal_render($form[$key]['size']); $rows[] = $row; @@ -557,13 +556,13 @@ function upload_load($node) { function upload_js() { // We only do the upload.module part of the node validation process. $node = (object)$_POST; - $form_state = array(); - // Handle new uploads, and merge tmp files into node-files. - upload_node_form_submit(array(), $form_state); - $node->files = array_merge(isset($form_state['values']['files']) ? $form_state['values']['files'] : array(), upload_load($node)); - $files = isset($_POST['files']) ? $_POST['files'] : array(); + // Load existing node files. + $node->files = upload_load($node); + + // Handle new uploads, and merge tmp files into node-files. + _upload_prepare($node); $form = _upload_form($node); $form += array( @@ -585,8 +584,8 @@ function upload_js() { $output = theme('status_messages') . drupal_render($form); // We send the updated file attachments form. - // Don't call drupal_json(). ahah.js uses an iframe and + // Don't call drupal_json(). upload.js uses an iframe and // the header output by drupal_json() causes problems in some browsers. print drupal_to_js(array('status' => TRUE, 'data' => $output)); exit; -} +} \ No newline at end of file === modified file 'modules/user/user.module' --- modules/user/user.module 2007-09-19 18:00:52 +0000 +++ modules/user/user.module 2007-09-26 03:24:43 +0000 @@ -510,7 +510,7 @@ function user_perm() { */ function user_file_download($file) { if (strpos($file, variable_get('user_picture_path', 'pictures') .'/picture-') === 0) { - $info = image_get_info(file_create_path($file)); + $info = image_get_info(_file_create_path($file, FILE_DOWNLOADS_PRIVATE)); return array('Content-type: '. $info['mime_type']); } } @@ -765,7 +765,7 @@ function template_preprocess_user_pictur if (variable_get('user_pictures', 0)) { $account = $variables['account']; if (!empty($account->picture) && file_exists($account->picture)) { - $picture = file_create_url($account->picture); + $picture = _file_create_url($account->picture, FILE_DOWNLOADS_PUBLIC); } else if (variable_get('user_picture_default', '')) { $picture = variable_get('user_picture_default', '');