Drupal 7 upload private files easy

One of the new features of the Drupal 7 core is new File API. I would like to show how easy it become to use private file system.

Our task is quite simple: user should be able to upload private files that only he has access to download. Also we will add permission for "administrator" role to download any private file that users have downloaded.

So lets start. First of all we create separate page with form and defining our custom permissions.

/**
 * Implements hook_menu().
 */
function example_file_menu() {
  $items = array();
 
  $items['example_file'] = array(
    'title' => 'Upload private file.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('example_file_upload_form'),
    'access arguments' => array('upload private files'),
    'type' => MENU_NORMAL_ITEM,
  );
 
  return $items;
}
 
 
/**
 * Implements hook_permission().
 */
function example_file_permission() {
  return array(
    'upload private files' => array(
      'title' => t('Upload private files'),
    ),
    'download own private files' => array(
      'title' => t('Download own private files'),
    ),
    'download all private files' => array(
      'title' => t('Download all private files'),
    ),
  );
}
 
/**
 * Private file upload form.
 */
function example_file_upload_form($form, &$form_state) {
  $form = array();
 
  $form['private_file'] = array(
    '#type' => 'file',
    '#title' => t('Choose a file'),
  );
 
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Upload as private file'),
  );
 
  return $form;
}

Now we need to create submit handler where we save file as private.

/**
 * Submit handler for private file upload form.
 */
function example_file_upload_form_submit() {
  $file = file_save_upload('private_file', array(), 'private://');
  if ($file) {
    drupal_set_message(t('Thank you for uploading private file. You can download it from @url',
            array('@url' => file_create_url($file->uri))));
  }
}

Key function is file_save_upload(). Here we define how we would like to save file and validators (in second argument). In this implementation we use standard validator but you of course welcome to look into more details about this function and define your custom rules.

After we have saved file we need to define access callback to download the file. This should be done in hook_file_download().

/**
 * Implements hook_file_download().
 */
function example_file_file_download($uri) {
  // Get the file record based on the URI. If not in the database just return.
  $files = file_load_multiple(array(), array('uri' => $uri));
  if (count($files)) {
    foreach ($files as $item) {
      // Since some database servers sometimes use a case-insensitive comparison
      // by default, double check that the filename is an exact match.
      if ($item->uri === $uri) {
        $file = $item;
        break;
      }
    }
  }
 
  global $user;
  if (($file->uid == $user->uid && user_access('download own private files'))
    || user_access('download all private files')) {
    // Access is granted.
    $headers = file_get_content_headers($file);
    return $headers;
  }
}

And that's it. We need to set up private files folder and we can start testing this code.

It is really great that we can build such functionality in this easy way. Taking opportunity I would like to thank all people who were involved in building this functionality. It is really great!

You are welcome to download this module below.

Attached files: 

Comments

Is there any way do same things for example for file fields? It's imteresging for me cause there is OG integration in my http://drupal.org/project/advimage - so I'm going port that module to D7 - and it would be cool if there will be possible make fully private galleries even private on filesystem level

Hi, That's a nice little function there. thanks for sharing.