Search code examples
php.htaccessmod-rewritehttpcookie

.htaccess protect download private files from user's directory using php


My php script create a user's directory to store private files and I need to keep it private except for the owner.

Basically my structure is like this:

- root/
- storage/
---- users/
----------user1/
---------------.htaccess
---------------images/
---------------tmp/
-------------------session-id-file
----------user2/
---------------.htaccess
---------------images/
---------------tmp/
-------------------session-id-file

This means when a new user register then a new user's directory is created in /storage/users:

$dir = __DIR__ . "/storage/user/" . $user["id"]; mkdir($dir);

Then a new .htaccess is created inside:

 $myfile = fopen($file, "w") or die("Unable to create file!");
 $txt = "RewriteCond %{HTTP_COOKIE}        PHPSESSID=(\w+)\n
 **RewriteCond {CURRENT-DIRECTORY}/tmp/access-%1      -f \n**
 RewriteRule ^(.+)$  $1  [L]\n
 RewriteRule .+  /deny   [L]\n";
 fwrite($myfile, $txt);
 fclose($myfile);

The .htaccess appears as:

RewriteCond %{HTTP_COOKIE}        PHPSESSID=(\w+)
RewriteCond {CURRENT-DIRECTORY}/tmp/access-%1      -f
RewriteRule ^(.+)$  $1  [L]

RewriteRule .+  /deny   [L]

When user login a new session-id-file is crerated in user's tmp directory:

touch($dir . "/tmp/" . session_id());

My question is: how detect {current directory} where the htaccess is located ? Basically how fix the wrong line in .htaccess:

        RewriteCond {CURRENT-DIRECTORYY}}/tmp/access-%1      -f \n

I have seen similar question but I'm not able to detect current directory based on directory created on fly.

A good option could be using just one .htaccess into /users directory instead of many .htaccess for each user as I did in my example.

Thanks for any suggestion :)


Solution

  • First of all, you can change:

    RewriteRule ^(.+)$ $1 [L]
    

    To:

    RewriteRule ^ - [L]
    

    Which means the same thing. - can be used to say don't make any change, just apply the flags.

    For denying, you can do that properly using the [F] flag to return a 403 forbidden, instead of a 200 rewrite to /deny. Like so:

    RewriteRule ^ - [F,L]
    

    If you still want the contents of /deny to be returned then add an ErrorDocument directive for 403 and point it to that page.

    For writing to a file in PHP, you can just use file_put_contents instead of those three calls to fopen, fwrite and fclose. See the documentation.

    To answer your actual question, for the current directory, you can't get it directly from RewriteCond variables, but you can just write it in to the file when you generate it with PHP.

    Here's an example of that with the other suggested changes:

    $txt = "RewriteCond %{HTTP_COOKIE} PHPSESSID=(\w+)\n
    RewriteCond $dir/tmp/access-%1 -f\n
    RewriteRule ^ - [L]\n
    RewriteRule ^ - [F,L]\n";
    file_put_contents($myfile, $txt) or die("Unable to create file!");
    

    So it becomes, for example:

    RewriteCond %{HTTP_COOKIE} PHPSESSID=(\w+)
    RewriteCond /root/storage/users/userid/tmp/access-%1 -f
    RewriteRule ^ - [L]
    RewriteRule ^ - [F,L]