Private Files

Ok, latest wordpress plugin. I’m getting quite into these. The other two were modifications. This one is completely from scratch. There are several plugins to make a blog private, making it a good tool for basic collaboration / group ware. However file attachments / images have still been visible too the public, until now.

Private files acts as a proxy, making sure users are logged in before they can download any files. The nice thing about is, it doesn’t modify the current uploads at all, doesn’t store files in a different place, so if you want to stop using it, all links to files stay the same, so you don’t need to redo anything.

Download it here:

If you have deactivated the plugin or deleted it and you want to unprotect your files manually, just delete the .htaccess file within your wp-content/uploads directory.

As with most wordpress plugins, the security is not guaranteed, use at your own risk.

Change Log:
Added MS Office 2007 mime types
Enhancements to block URLs with /../ in them
Bugfix which prevented logged in subscriber users from accessing files.
Now accounts for spaces in file names
Shows a warning if you are not using WordPress permalinks
Should work on a wider variety of WordPress setups (subdirectories etc.), but uploads must be a subdirectory of your WordPress directory.
Should work with relative and absolute upload paths
Tested on the latest version of wordpress
Now uses raw file() read instead of echo, which should clear up issues on some setups.
Bug fix so this actually works under various wordpress conditions, eg. root and not root installations of wordpress
Tested with wordpress 2.5.1

Reader Comments

  1. Randy, sorry a little too busy at the moment.

    Ben, how the plugin works is it intercepts using a .htaccess file before a user can download a file, and checks if they’re logged in. If they are logged in the file contents will be streamed by the plugin, if not nothing will be sent. Even if a non-logged in user guesses the URI the plugin intercepts this query so should not be able to access it.

    Its not been extensively tested for all security holes though, so a little disclaimer I’m not responsible for any loss due to the use of this plugin.

    Oh, you knew Dawen, were you in Sha Tin College too?

  2. Thanks James, maybe I’ll give it a whirl.

    I went to Lexington High School in Lexington, MA. I knew a Dawen Wang there… I imagine he’s the same one.


  3. Am working on

    Like Tim Charles, the file stays protected no matter what. I tried :

    @ Line 212, Used str_replace to eliminate the unecessary path info as suggested in a previous post.

    When the 404 message displays, the URL in the address bar displays the exact URL of the file called for so everything seems to point to the correct place.

    Have tried with WP 2.7 and 2.8

    Help! Please!

  4. Working on a site for my church and want to password protect the weekly bulletins and newsletters from being downloaded. However, I am having a similar problem too others above – even if I am logged in – if I mark the files as protected, I still can’t download the files. If I unprotect everything then I can download them. I am using the newest version of wordpress…I have godaddy hosting – any thoughts on what I need to do? Am I supposed to create the htaccess file myself or does that plugin do that for me? Thanks for your help…

  5. One more tidbit for the post above – I was able to get this to work for everyone but contributors….it won’t work when I apply a role of subscriber to a user though. Any way to fix that? Thanks again…this is a great plugin!

  6. I’m trying to install this plugin, but my status never changes from unprotected. No matter what I do, I can’t get it to protect the file. Any help?

  7. Hi,
    first thank you very much for this plugin – i just started 1 day ago with my first steps in WP… to make the website secure i needed exactly this little tool! SUPER!

    Well just to let others and maybe you know: After installing the Plugin i was unable to watch the content of the blog (background, header, widgets, e.t.c) so i figured out that i needed to put the .htaccess not into the wp-content folder – but in the subfolder for real private content (in my case ist wp-content/2009/……).

    That way the “theme” content is not blocked if your not loged in ;)

    I hope this helps maybe you or other users for this wonderful piece of software!
    (Or maybe this is just bullshit and i’m too new and unexperienced at WP).

    Anyway, thanks!

  8. as a follow up. I think I’ve found the code that does the protecting and inserts the .htaccess file. It won’t let me insert it here.

    Can anyone advise how to alter this for a custom path? Or to just add a custom path so that the plugin protects both the uploads folder and an additional folder?

  9. Is there any way to use same time protected files and public files from medialibrary.
    Also when you upload files can you select if it is public or protected?

  10. I have the same problem with 404 message display. I notice that:
    When I use the plugin in a domain with multiple wordpress installations, it doesn’t work if the protected site is on a subdirectory and the wordpress is also installed in the root directory.
    If there isn’t wordpress installed in the root the wordpress installations are wording.

  11. Is it possible to change path into html (root)
    /wp/wp-content/downloads ? Tis is also the path in .htacees. At the moment the plugin doesn’t work with this path.

  12. I use this plugin but when user click on attachment receive follow error:

    Warning: strpos() [function.strpos]: Empty delimiter in /public_html/wordpress/wp-content/plugins/private-files/privatefiles.php on line 211

    Could you help me?

  13. Hello,
    I was hoping you could help me with the following error:

    Warning: mkdir() [function.mkdir]: Invalid argument in D:\Inetpub\localuser\PhoenixHN\phoenixonline\wp-content\plugins\private-files\privatefiles.php on line 162

    Warning: fopen(D:\Inetpub\localuser\PhoenixHN\phoenixonline\wp-admin/D:\Inetpub\localuser\PhoenixHN\phoenixonline/wp-content/uploads/.htaccess) [function.fopen]: failed to open stream: Invalid argument in D:\Inetpub\localuser\PhoenixHN\phoenixonline\wp-content\plugins\private-files\privatefiles.php on line 166

    Warning: fwrite(): supplied argument is not a valid stream resource in D:\Inetpub\localuser\PhoenixHN\phoenixonline\wp-content\plugins\private-files\privatefiles.php on line 167

  14. Hi James,

    Is this plugin compatible with WordPress 2.9.2? I’m getting this error when installing, activating, and trying to access an uploaded file. I’m logged in at the time:

    Internal Server Error

    The server encountered an internal error or misconfiguration and was unable to complete your request.

    Please contact the server administrator, [email protected] and inform them of the time the error occurred, and anything you might have done that may have caused the error.

    More information about this error may be available in the server error log.
    Apache/2.2.6 (FreeBSD) mod_ssl/2.2.6 OpenSSL/0.9.7e-p1 DAV/2 PHP/5.2.5 with Suhosin-Patch Server at Port 80

    If I deactivate, I can get access to the file.


    Jeff Miller

  15. Hello, James:

    First of all, thanks for the plugin, it usually works very nice… but after migrating my blog to another server, I’ve found the same problem as Jeff Miller (above).

    It only happens if I activate the “Force user login” option, otherwise it works OK. The only apparent difference between both servers is that the new one has different server names for HTTP and MySQL (not “localhost” for the hostname in wp-config.php).

    Thanks in advance,


  16. Hello again, James:

    It seems that commenting out line 354:
    // header(“Status: 302 Moved Temporarily”);
    solves the problem I’ve commented above…

    Thanks again for your plugin!


  17. I installed to WordPress 3.0 and it promptly shut down my entire site, giving me a 500 error. Every page was this way: Posts, pages, wp-admin, etc.

    After some poking around, I deleted the .htaccess file (which was placed in the blog’s root directory), which gave me access to the wp-admin and site index, but not to Pages or Posts.

    After more poking around, I was able to restore correct operation by adding a new .htaccess file to the root directory with the following (taken from another WordPress blog):

    # BEGIN WordPress

    RewriteEngine On
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]

    # END WordPress

    It appears that your plugin removes this line from the .htaccess file, but it is necessary for correct operation. Perhaps the .htaccess file is supposed to go somewhere other than the root directory? I will poke around some more to find out.

  18. I haven’t tried it on 3.0 yet so maybe it doesn’t work on that.

    The .htaccess file my plugin creates should go in the wp-uploads directory. Maybe wordpress 3.0 changes how you find out what that is.

    I’ll have a look sometime too.

  19. Is anyone able to make the plugin work with WP3?
    I am trying but having trouble with function apache_request_headers().

  20. Hi.
    I wonder if its possible to protect more than one Uploadfolder (I am using WP 3 with Multisite enabled and need the possibility to protect the other uploads folders too.)
    Kind regards,

  21. Hi James

    I have followed the instructions in the plugin, but when I click ‘Protect’ nothgin changes, the cp still says ‘Unprotected’.

    Can you suggest why this may be?


  22. I got it to work in WP 3. In privatefiles.php, find

    function private_upload_path() {
    $raw = get_option(‘upload_path’);
    return (substr($raw,0,1) == “/” ? substr(private_upload_fullpath(),strlen(private_root())+1) : $raw);

    Change the +1 to +2.

    The protect button in the CP may put the.htaccess file in the wrong place (root, don’t do it).

    Make your own .htaccess file containing the following and manually put it in the wp-content/uploads folder on your server.

    RewriteEngine On
    RewriteBase /
    RewriteRule . /afilethatshouldnotexist.txt
    Options -Indexes

  23. Ok, I think I got it now.

    In privatefiles.php, in the two places you see
    change it to
    including the quotes.

    Then go to the Private Files CP and choose a level and click Protect. It should place the .htaccess file properly now.

Write a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.