Blog Linux WordPress

private file attachments in wordpress

Before WordPress 3.0, I use codes from the plugin Private Files in one of client website to protect the files from illegal download/viewing. It works by not allowing access to WP's uploads directory and sending and then serving a custom 404 page. It works fine until WordPress 3.0 started sending headers before calling the template's 404.php. This resulted to the plugin not generating the requested file. After so much googling, I found out that there's a better way of doing it by using redirect in .htaccess.

Here's my .htaccess placed on the /wp-content/uploads/ directory.

IndexIgnore *
Options +FollowSymlinks
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(www.)? [NC]
RewriteCond %{REQUEST_URI} !hotlink.(gif|png|jpg|doc|xls|pdf|html|htm|xlsx|docx) [NC]
RewriteRule .*.(gif|png|jpg|doc|xls|pdf|html|htm|xlsx|docx)$ [NC]

What it does is that files will not be displayed if the referrer is not my own domain. It forces the user/visitor to click on the link to be able to view/download the file(only if the extension is any of those listed above). The checking is not case-sensitive (that's what [NC] stands for).

Together with my custom codes for user access management, I was able to display and hide links based on the user profile. At the same time, search engines like Google will not be able to crawl and cache my files. So for me, it's actually many birds in one stone and I didn't even have to add another code on my themes and plugins (actually, I removed the custom 404). Just to be clear, I managed to get the following with this fix.

  1. Prevent Google from caching and viewing my files

  2. Prevent hotlinking. That is, another site will use images stored on my server to display them on another website. Another thing is that files will not be served/viewed by simply pasting the URL/URI on the address bar.

  3. Forcing the users to login before downloading/viewing files they own.

  4. Prevent users from viewing other user's files when they are logged in. This is achieved by not displaying the link to the files they do not own.

Whew, that's a lot! Unfortunately, it took me quite some time to find the solution. Actually, two nights of sleep was lost for this. And like many of the problems I've written before, the solution is so damn simple. By the way, the same can be implemented in NGINX (which I also use). Of course, you need to translate the directives.

Source : Unfortunately, I forgot where I got this but it's somewhere in the forum. I'll try to update the post once I find it again.

Note : The code is just a sample. It's not actually running on this blog.