Goal: Your Drupal site has a Public file system but you have files you want to limit access to. This is the Public/Private File system conundrum. The following demonstrates how to solve your problem using the Private Download module.

Assumptions:
- A Drupal site with a Public file system pointing to "sites/default/files".
- CCK and CCK FileField modules are installed.

1) Understand your system:

- There shouldn't be a private folder in sites/default/files/
$ ls -al sites/default/files
- Are you operating out of a sub-directory? If your Drupal code is found in www.example.com/drupal then you're in a sub-directory. For the record, I'm in a sub-directory and I've set the base_url in settings.php to represent this.

2) Install and enable the Private Download Module

3) Configure Private Download settings (admin/settings/private_download)

- if you're in a sub-directory check the RewriteBase rule and prepend your directory name to it if it isn't there already:
RewriteBase /[optional-subdirectory]/system/files/private
- Save configuration

4) Check to make sure you now have a "private" directory with an .htaccess file

$ ls -al sites/default/files/private
$ ls -al sites/default/files/private/.htaccess

5) Specify which Roles can access files within the "private" directory. Go to admin/user/permissions to configure permissions

- Under "private_download module" check the "authenticated users" box. This will allow anyone who logs into your system to "access private download directory." Of course, you can create your own roles (admin/user/roles).
- Save permissions

6) Add a CCK FileField to a content type, let's call them myFile and myContentType, respectively.

- When configuring myFile go to Path settings > File path and specify "private" (without quotes.) Any files uploaded through this field will end up in the "private" directory.

7) Upload a file
- Create Content > myContentType
- Upload a file into the myFile field. Let's call it test_download.txt.
- Save

8) Everything should be setup now but you can verify everything works:
- Right click on test_download.txt, it should download (or open in browser)
- Left click on test_download.txt > Copy Link Location
- Logout
- Open a new browser tab and try either of these URL's (both should produce an "Access denied" error:

www.example.com/system/files/private/test_download.txt
www.example.com/sites/default/files/private/test_download.txt

Note: The second URL should be re-written to the first in the browser.

Comments

kbk’s picture

My hope is that this module can gain a Documentation Page or a README.txt file. I've posted a start, feel free to suggest changes.

kbk’s picture

A few edits (this was posted hastily before leaving work yesterday):

4) Check to make sure you now have a "private" directory with an .htaccess file

$ ls -al sites/default/files/private
$ ls -al sites/default/files/private/.htaccess

- Take a look at the contents of .htaccess:
$ less sites/default/files/private/.htaccess
- Use "Q" to exit viewing .htaccess

8) Everything should be setup now. but you can Vverify everything works:
- Left Right click on test_download.txt, it should download (or open in browser)
- Right Left click on test_download.txt > Copy Link Location
- Logout
- Clear your browser's cache and download history
- Open a new browser tab and try either of these URL's (both should produce an "Access denied" error:

www.example.com/system/files/private/test_download.txt
www.example.com/sites/default/files/private/test_download.txt

Note: The second URL should be re-written to the first in the browser.

johnhanley’s picture

@kbk,

Thanks for creating this issue.

Let's leave this thread open for a period and see what others might have to contribute, but what you have so far looks great.

5t4rdu5t’s picture

Thank you kbk!

This is just awesome! I've followed your instructions step by step and got it working on the first try. Actually, there's more info here than what I needed but it probably would do good to others.

A Documentation Page and a README.txt would be great, but is there a chance to include at least a link to this issue on the module's page while it gets there?

Thanks again!

kbk’s picture

Glad it helped, Libriana. I think there are (at least) four options for any documentation:
1) Include in README.txt
2) Create as separate page on d.o and link to it from the Resources section of the module homepage
3) Make it part of the Advanced Help (it would go into a "help" folder as an .html file along with a .ini and ship with the module; this is how Views does it anyways)
4) Leave it as an issue post only

mandreato’s picture

That is exactly what I needed.
Thank you Bacteria Man for the module and thank you kbk for this detailed explanation !
I vote for 2) Create as separate page on d.o and link to it from the Resources section of the module homepage

johnhanley’s picture

@kbk,

Thanks again for putting this together.

If you don't mind, at your convenience, please create a documentation page and I will link to it from the project page.

Many thanks,
John (aka. Bacteria Man)

guidot’s picture

Some additions to the docs:

  • If you use lighttpd as webserver the .htaccess-file won't do anything. But you can use mod_rewrite and a simple rewrite-rule to achieve the same functionality:
    1. Open the lighttpd-configuration-file (/etc/lighttpd/lighttpd.conf on debian).
    2. Look for the server.modules-variable, usually at the top of the file.
    3. Make sure you have a line "mod_rewrite", uncommented. It should look similar to this:
      server.modules              = (
                  "mod_alias",
                  "mod_accesslog",
                  "mod_compress",
                  "mod_rewrite",
                  "mod_redirect",
      #           "mod_evhost",
      #           "mod_evasive"
      )
    4. Add the rewrite rule:
      url.rewrite-once = ( "^/sites/default/files/private/(.*)" => "/system/files/private/$1" )
      

      Note: This may only work if you have clean URLs enabled (I use mod_magnet for that).

    5. Save the file and restart the web-server.
  • User pictures work with Private Download as well. You need to change the path to the pictures in /admin/user/settings to something below the private folder e.g. private/pictures.
    If you want to keep already existing user pictures you only need to manually
    1. move the files to the new directory,
    2. change the path in the picture-fields in the users-table (phpMyAdmin comes in handy) and
    3. clear the cache.
  • I suggest changing the help-text below the file-field on the Private Download-admin-page to something like: "Subdirectory within the "%directory" directory where the private download files will be stored. Drupal will need to have write access to this directory. Do not include preceding or trailing slashes."

BTW: A really nice UX-enhancement for Lighty- (and maybe other non-Apache-) users would be to disable the whole .htaccess-form-element and -creation-code if the web-server is lighttpd and instead put a little help-text onto the admin-page, informing the admin that it is her/his responsibility to include the correct rewrite-rule.

ikeigenwijs’s picture

followed the instructions to the letter, but no joy.

did it on 2 different sites but on both the same problem: Fout 310 (net::ERR_TOO_MANY_REDIRECTS): Er zijn te veel omleidingen.

Drupal 6.20
please advice, i realy need this
thx a lot

In .htaccess


RewriteEngine on
RewriteBase /system/files/private
RewriteRule ^(.*)$ $1 [L,R=301]

kbk’s picture

Status: Needs review » Needs work

I finally got around to this. The How To instructions from the OP can be found here:
http://drupal.org/node/1071944

Re: #8 I went ahead and created a child page for the lighttpd information:
http://drupal.org/node/1071982

- I omitted the final 2 points in #8, it looks like good information that should be opened in separate issues.

I believe once John places a link on the project page to the new documentation this issue can be closed.

Further edits to the above documentation should take place at the links given above.
Support requests should be filed in new issues.

johnhanley’s picture

Status: Needs work » Closed (fixed)

@kbk,

This is awesome--it looks great!

I have defined the documentation link on the project page.

Thanks to you and everyone else who contributed.

John

rag_gupta’s picture

Using this module disallows anonymous users to access registered users data. But user1 can access user2's data. How to restrict that also?

kbk’s picture

@rag_gupta, you will need to file a support request issue for that question. This issue is closed; see the Issue queue handbook http://drupal.org/node/317 for more.