From 4509ee310fd8c366e641955e8f3a24a9011488e3 Mon Sep 17 00:00:00 2001
From: Colan Schwartz <colan@58704.no-reply.drupal.org>
Date: Thu, 30 Oct 2014 15:19:04 -0400
Subject: [PATCH] Issue #2000934 by colan | Dave Reid: Select directory for
 uploaded files.

---
 file_entity.module    |  3 +++
 file_entity.pages.inc | 64 +++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 63 insertions(+), 4 deletions(-)

diff --git a/file_entity.module b/file_entity.module
index 5d058e4..e5f1b6b 100644
--- a/file_entity.module
+++ b/file_entity.module
@@ -426,6 +426,9 @@ function file_entity_permission() {
     'create files' => array(
       'title' => t('Add and upload new files'),
     ),
+    'choose file destination' => array(
+      'title' => t('Select destination for each uploaded file'),
+    ),
     'view own private files' => array(
       'title' => t('View own private files'),
     ),
diff --git a/file_entity.pages.inc b/file_entity.pages.inc
index a00245a..ed5b3d9 100644
--- a/file_entity.pages.inc
+++ b/file_entity.pages.inc
@@ -112,6 +112,20 @@ function file_entity_add_upload_step_upload($form, &$form_state, array $options
     '#default_value' => isset($form_state['storage']['upload']) ? $form_state['storage']['upload'] : NULL,
   );
 
+  // Add an option to specify the upload path if the user has permission to do so.
+  if (user_access('choose file destination') ||
+      user_access('bypass file access') ||
+      user_access('administer files')) {
+    $form['path'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Upload path'),
+      '#description' => t('Enter the path within the upload folder where you would like to place the file (e.g. "documents/finance").  Do not add preceding or trailing slashes.  Leave blank to keep it at the root, with no subfolders.'),
+      '#default_value' => file_uri_target($form['upload']['#upload_location']),
+      '#required' => FALSE,
+      '#maxlength' => 255,
+    );
+  }
+
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['next'] = array(
     '#type' => 'submit',
@@ -439,6 +453,26 @@ function file_entity_add_upload_submit($form, &$form_state) {
       // Change the file from temporary to permanent.
       $file->status = FILE_STATUS_PERMANENT;
 
+      // Move the file to the specified target directory if the user has
+      // the proper permission.
+      if (user_access('choose file destination') ||
+          user_access('bypass file access') ||
+          user_access('administer files')) {
+
+        // Get the URI for the target path.
+        $uri_new = file_entity_upload_destination_uri(array(
+          'uri_scheme' => file_uri_scheme($file->uri),
+          'file_directory' => $form_state['storage']['path'],
+        )) . "/" . drupal_basename($file->uri);
+
+        // If it changed, move the file to its new location.
+        if ($file->uri != $uri_new) {
+          $path = drupal_dirname($uri_new);
+          file_prepare_directory($path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+          $file = file_move($file, $uri_new, FILE_EXISTS_RENAME);
+        }
+      }
+
       // Save the form fields.
       // Keep in mind that the values for the Field API fields must be in
       // $form_state['values'] and not in ['storage']. This is true as long as
@@ -494,7 +528,12 @@ function file_entity_upload_destination_uri(array $params, array $data = array()
     'file_directory' => '',
   );
 
-  $destination = trim($params['file_directory'], '/');
+  // Sanitize the provided path by removing any slashes and dots from the
+  // beginning and end, and neutralize any attempts to traverse up the tree.
+  // We're assuming it's not necessary to run check_url() on it because this is
+  // usually done on output.
+  $destination = trim($params['file_directory'], '/.');
+  $destination = str_replace('/../', '/', $destination);
 
   // Replace tokens.
   $destination = token_replace($destination, $data);
@@ -536,9 +575,26 @@ function file_entity_add_upload_multiple($form, &$form_state, $params = array())
  * Submit handler for the multiple upload form.
  */
 function file_entity_add_upload_multiple_submit($form, &$form_state) {
-  $upload_location = !empty($form['upload']['#upload_location']) ?
-    $form['upload']['#upload_location'] . '/' :
-    variable_get('file_default_scheme', 'public') . '://';
+
+  // Set the upload directory where the file should be dropped.
+  if (user_access('choose file destination') ||
+      user_access('bypass file access') ||
+      user_access('administer files')) {
+
+    // The current user has permission to specify the location.
+    // Grab it from the submitted form.
+    $upload_location = file_entity_upload_destination_uri(array(
+      'file_directory' => $form_state['values']['path'],
+    )) . "/";
+  }
+  else if (!empty($form['upload']['#upload_location'])) {
+    // If the form specfied a directory at the outset, use that.
+    $upload_location = $form['upload']['#upload_location'] . '/';
+  }
+  else {
+    // Use the default location for uploaded files.
+    $upload_location = variable_get('file_default_scheme', 'public') . '://';
+  }
 
   // Ensure writable destination directory for the files.
   file_prepare_directory($upload_location, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
-- 
1.9.1

