0

I have a custom content type with an image and a file field, both of which are uploaded to the private file system.

How do I create a public url to the image that will check for user permissions so that anonymous users are prevented from being able to browse to the image?

This is the code I tried first:

$url = file_create_url($node->field_my_private_image[$node->language][0]['uri']);

It generates a url to system/files/ but that url is visible to anonymous users and it isn't being restricted by user permissions.

I saw a security patch for drupal 7.13, but it was supposedly fixed and I'm using drupal 7.22.

Is there a built-in way to do this or do I need to implement some functions in my module to respond to special urls to access these files which will check permissions and then stream the file back to the browser?

  • So, you are already getting the file into the private directory that you want. What criteria determines what content can be accessed? Can users of a certain role all see all files uploaded to this area? or can only one person see a specific file or group of files at a time? – blue928 Jun 17 '13 at 6:47
  • I haven't been able to test tenken's solution yet, but yes, I want only users with a certain permission to be able to access those files. – Kenny Wyland Jun 17 '13 at 16:32
1

You want to implement hook_file_download in Drupal 7.

Control access to private file downloads and specify HTTP headers.

This hook allows modules enforce permissions on file downloads when the private file download method is selected. Modules can also provide headers to specify information like the file's name or MIME type.

A small example:

function mymodule_file_download($uri) {
  global $user;

  // Does the user have access based on some criteria ?
  if (!user_access('ACCESS PAY-PER-DOWNLOAD-CONTENT', $user)) {
    return -1;
  }

  // Does this module own the file given by the $uri ?
  if (db_query('
          SELECT fu.module
          FROM {file_usage} fu
          WHERE fu.module = :module_name AND fu.uri = :uri',
          array(':module_name' => 'mymodule',
                ':uri' => $uri)->rowCount() < 1) {
    return NULL;
  }

  // If the above conditions fallthru then populate HTTP header arrays
  // for content download; If you need to grab the file object and work on
  // it -- say output CSV from the data, you can grab it as follows ...
  $files = file_load_multiple(array(), array('uri' => $uri));
  // If empty, $file will be false, otherwise will contain the required file.
  $file = reset($files);

  return array('Content-Type' => file_get_mimetype($uri));  
}
0

From what I understand of the goals, personally I think this could be easily handled through hook_menu and defining permissions there. (API reference)

In a custom module you can setup the following:

function mymodule_menu(){
    $items['privatefiles'] = array(
        'title' = 'Private File Page',
        'page callback' = 'mymodule_list_private_files',
        ...
        'access arguments' = array('access my private files'),
    );
}

function mymodule_list_private_files() {
    //the logic in this function should
    //return the files you want the user to see.

    return $files;
}

What's happening here is basically we are providing a link that can only be accessed given the access rules in the access arguments. Only a person who has an account with those permissions will see this page and everyone else will get access denied.

The logic in the page call back retrieves a list of files from the database and renders them as you need.

This could get as complicated as you wanted to make it. You could even, for example, provide a dynamic link in the $item menu name where '%' would equal a username. With that you could even show files intended for that one person while another would see a completely different group of files (in the case they are purchasing images or something).

If you already have a link where the files are showing up publicly and you simply want to make those private, then you can use hook_menu to change the permissions just for that page and avoid writing logic altogether to retrieve and display files.

I'm not sure how comfortable or familiar you are with module development or hook_menu so I left the example a bit abstract. Please let me know if I can clarify anything.

  • That is what I currently have set up. The users with the proper permission can see the listing, but on that page I generate some links to images and files. If an anon user browses to those urls, they are able to see them. That's the problem. I'm trying to figure out how to protect those specific urls. I still have to try the hook_file_download suggestion from tenken. – Kenny Wyland Jun 18 '13 at 0:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.