Lucien Dubois Lucien Dubois - 3 months ago 10
PHP Question

Protect images through .htaccess and PHP

I would like to check if users are logged in to access image files.
Images would have this form

https://domain.com/folders/imagename.jpg


I tried this in the .htaccess:

RewriteEngine On
RewriteCond %{REQUEST_URI}\.jpg
RewriteRule ^(.*)\.jpg$ /protect.php


And this in my protect.php file

<?php
if(rcp_is_active()){
header('Content-Type: image/jpg');
readfile($imageurl);
}
else{
readfile("https://placeholdit.imgix.net/~text?txtsize=38&txt=Forbidden&w=400&h=400")
}
?>


My question:


  • How should I complete my .htaccess file to pass the filename.jpg to the php file?


Answer

Update your .htaccess RewriteRule to pass the matched filename to the PHP script as follows (your RewriteCondition is superfluous):

RewriteEngine On
RewriteRule ^((.*)\.jpg)$ /protect.php/$1

Then you can access the passes value using $_SERVER['PATH_INFO'] or $_SERVER['PATH_TRANSLATED'] (then Apache tries to map it to the real path according to document root, see mod_cgi and RFC 3875 for more information about this). For this to work AcceptPathInfo needs to be enabled in Apache httpd (the default).

or use

RewriteRule ^((.*)\.jpg)$ /protect.php?filename=$1

and use $_GET['filename']. Especially here, beware for directory traversal attacks (e.g., someone uses /protect.php?filename=../../someother-file.jpg). I usually apply realpath to normalize the path and check that it starts with the folder which contains the files or the document root ($_SERVER['DOCUMENT_ROOT']).

In both cases also make sure you only deliver allowed files (e.g., what happens if an attacker uses /protect.php/protect.php). This might leak sensitive data.

PS: Maybe you also want to make the response non-cacheable or provide a Content-Length.

PSS: Even for the forbidden case you also need to provide a proper Content-Type - or use a redirect (header('Status: 302'); and header("Location: https://placeholdit.imgix.net/~text?txtsize=38&txt=Forbidden&w=400&h=400");) so that you don't need to re-request that image again and again.