Asked  2 Years ago    Answers:  5   Viewed   184 times

I am trying to restrict direct access to files in a directory. So for example i have website.com/files/example.flv.

So if users go straight to the file in the URL, i want them to be redirected to the home page.

I have tried the following using htaccess

deny from all

but its not working great. Is there a way i could do this using php, then in the user goes straight to the file in the url, they will get redirected.

So if the user goes to the file link in the url, they will be sent to the home page. So can this only be done using htaccess

 Answers

3

If you want to restrict access to files, you should consider storing them outside the public DocumentRoot and using PHP to deliver the file, applying your own access logic. This means outside the www or public_html folders, depending on the hosting environment you are working with.

<?php

// Suppose your "public_html" folder is .
$file = './../data/test.gif';
$userCanDownloadThisFile = false; // apply your logic here

if (file_exists($file) && $userCanDownloadThisFile) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename=filename.gif');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    ob_clean();
    flush();
    readfile($file);
}
Thursday, October 13, 2022
 
hektor
 
1

Send out a header defining the file's name.

$filename = $name . "." . $type;
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));

I've included additional headers, since you should send out these as well. This is just a modified example of what you can see in the PHP documentation on readfile.

Friday, December 9, 2022
 
tushar
 
3

By the looks of it your file download script may be setting the wrong Content-Length, so that the last few bytes of the file can spill over into the next request, causing all manners of brokenness.

What web server and OS are you using, and how are you invoking PHP? Because if it's Windows I'd have a suspicion that your PHP installation may somehow be writing to stdout as a text instead of a binary stream. This would cause each n byte to be converted to a rn sequence, which would probably make most binary files unreadable as well as making the response body a bit longer than the Content-Length header said it was.

$parsed_url['localpath'] = LOCALROOT . $parsed_url['path'];

That seems rather dangerous. I would hope $filename were checked and validated to within an inch of its life before trying anything like that. (Filename validation is deceptively hard.)

Saturday, October 29, 2022
 
ziya
 
4

I suppose I wouldn't use a .htaccess (or any kind of HTTP-authentication) for that : .htaccess / .htpasswd are great when you want to allow/deny access to a whole directory, and not to specific files.


Instead, I would :

  • Deny any access to the files -- i.e. use a .htaccess file, containing Deny from All
    • That way, no-one has access to the file
    • Which means everyone will have to use another way to get to the files, than a direct URL.
  • Develop a PHP script that would :
    • receive a file identifier (a file name, for instance ; or some identifier that can correspond to the file)
    • authenticate the users (with some login/password fields), against the data stored in the database
    • if the user is valid, and has access to the file (This is if different users don't have access to the same set of files), read the content of the file from your PHP script, and send it the the user.

The advantage is that your PHP script has access to the DB -- which means it can allow users to log-in, log-out, it can use sessions, ...


About the "send the file from PHP", here are a couple of questions that might bring some light :

  • Sending correct file size with PHP download script
  • Resumable downloads when using PHP to send the file?
  • forcing a file download with php
Sunday, August 14, 2022
 
kainix
 
5

For the fun of it I've whipped this together:

class FileFinder
{
    private $onFound;

    private function __construct($path, $onFound, $maxDepth)
    {
        // onFound gets called at every file found
        $this->onFound = $onFound;
        // start iterating immediately
        $this->iterate($path, $maxDepth);
    }

    private function iterate($path, $maxDepth)
    {
        $d = opendir($path);
        while ($e = readdir($d)) {
            // skip the special folders
            if ($e == '.' || $e == '..') { continue; }
            $absPath = "$path/$e";
            if (is_dir($absPath)) {
                // check $maxDepth first before entering next recursion
                if ($maxDepth != 0) {
                    // reduce maximum depth for next iteration
                    $this->iterate($absPath, $maxDepth - 1);
                }
            } else {
                // regular file found, call the found handler
                call_user_func_array($this->onFound, array($absPath));
            }
        }
        closedir($d);
    }

    // helper function to instantiate one finder object
    // return value is not very important though, because all methods are private
    public static function find($path, $onFound, $maxDepth = 0)
    {
        return new self($path, $onFound, $maxDepth);
    }
}

// start finding files (maximum depth is one folder down) 
$count = $bytes = 0;
FileFinder::find('.', function($file) use (&$count, &$bytes) {
    // the closure updates count and bytes so far
    ++$count;
    $bytes += filesize($file);
}, 1);

echo "Nr files: $count; bytes used: $bytesn";

You pass the base path, found handler and maximum directory depth (-1 to disable). The found handler is a function you define outside, it gets passed the path name relative from the path given in the find() function.

Hope it makes sense and helps you :)

Tuesday, November 15, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 

Browse Other Code Languages