5

I love the fact that D7 allows you to choose whether files should be stored in the public or private file system on a per-field basis.

But here's my question: is it possible to have image files that are stored in the private file system, while thumbnails etc. created via image styles are stored in the public file system, so anyone can access them? In other words, I want to protect the original image files, but not their thumbnails.

By default theme_image_style seems to place the generated styles in the same file system (public or private) as the original image, and I don't see any arguments to change that...

1
  • I've been wondering this as well.
    – Jane Panda
    Commented Oct 25, 2011 at 3:34

4 Answers 4

4

What about creating 2 fields ? One for storing the thumbnail and let it "public". The other one for storing the original image, mark it as "private" and define a permission for it using field permissions module ?

Edit Oct, 26: let's add some code :)
So if your confortable with creating a module, here are the instructions.
Create 2 fields: field_img_public and field_img_private, one will be on the public filesystem, the other on the private.

Then create a module to store this hook_node_presave():

function MYMODULE_node_presave($node) {
  //Retrieve the file object from the public image.
  $fid_items = field_get_items('node', $node, 'field_img_public');
  $fid = $fid_items[0]['fid'];
  $img_public = file_load($fid);

  //Create the private path.
  $img_private_path = str_replace('public://', 'private://', $img_public->uri);
  $private_dir = pathinfo($img_private_path,  PATHINFO_DIRNAME);

  //Verify if the private folder exists.
  file_prepare_directory($private_dir, FILE_CREATE_DIRECTORY);

  //Copy the image
  $img_private = file_copy($img_public, $img_private_path, FILE_EXISTS_RENAME);

  //Save the resulting file object.
  $node->field_img_private['und'][0] = (array)$img_private;
}

Then you just upload the public image and the private get populated.

4
  • Thanks for the answer tostinni, but I'm a little confused... if I used two fields, then I would need to upload the image twice... I don't want to have to upload the thumbnail image, or keep track of it in the database--I want to have the thumbnail created automatically via image styles, as I have it now. I just want that thumbnail image to reside in sites/default/files (public file system), rather than sites/default/files/private (where the original image is, private file system). Commented Oct 25, 2011 at 12:10
  • I added some code to achieve this ;)
    – tostinni
    Commented Oct 26, 2011 at 8:50
  • Thank you tostinni for the code example! My main issue with your solution is that the original image file is now existing in 2 locations, which is redundant, and eats twice the disc space. Also, it feels very "hacky." But I can't think of a better solution at the moment, so again: thanks for sharing. Commented Nov 12, 2011 at 15:01
  • Yep that's the main problem, but I can't see how to achieve this other way...
    – tostinni
    Commented Nov 12, 2011 at 19:51
3

There is now Image Style Access to do this.

Allows granular access control to images and image style derivatives.

EDIT: Disclosure - this is my module.

2
  • Is this your module? Normally, we like people to disclose any affiliations when they make recommendations.
    – mpdonadio
    Commented Mar 5, 2013 at 23:30
  • This looks exactly like what I'm looking for. :) Any chance for a Drupal 8 version?
    – s427
    Commented Jan 5, 2017 at 21:00
1

A possible lightweight solution, which is what I ended up going with, is to save the images in the public file system, and simply use a .htaccess file to protect the original image file directory.

0

Use this function in a custom module if your are generating images from a custom template.

function mymodule_image_style_url($style_name, $uri) {
  $filename = drupal_basename($uri);

  $directory   = 'public://styles/' . $style_name . '/public/';
  $destination = $directory . $filename;


  //TODO: You will need to delete destination folders if you want to refresh styles....
  if (file_exists($destination)) return file_create_url($destination);

  $style = image_style_load($style_name);

  if ($style) {

    $image = image_load($uri);

    flog_it($image, "image");

    foreach ($style['effects'] as $effect) {
        flog_it($effect, "effect");

        image_effect_apply($image, $effect);
    }

    file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
    image_save($image, $destination);
  }

  return file_create_url($destination);

}

Then use it in a node template like this:

<img src="<?php echo mymodule_image_style_url('image_preview', $node->field_original_image[LANGUAGE_NONE][0]['uri']) ?>" alt="">

Instead of using more modules this solution will boost your website when using your image styles from private file images.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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