Andrew
Andrew

Reputation: 3028

allowing only a specific user to download files off the server

I'm creating files based on user data (taking from the database table, writing to a csv file, storing on the server, and then printing out a link for the user (logged in) to download).

how can I ensure that only the user can download that file? For instance, if the file is stored at http://mysite.com/username/file, how can I make sure only that user, when signed in, is the only one who can download the file? Using php.

thanks for the help

Upvotes: 0

Views: 1684

Answers (6)

Michael Leaney
Michael Leaney

Reputation: 751

The PHP manual has a user submitted entry that does what you're looking for:

function query_to_csv($db_conn, $query, $filename, $attachment = false, $headers = true) {

    if($attachment) {
        // send response headers to the browser
        header( 'Content-Type: text/csv' );
        header( 'Content-Disposition: attachment;filename='.$filename);
        $fp = fopen('php://output', 'w');
    } else {
        $fp = fopen($filename, 'w');
    }

    $result = mysql_query($query, $db_conn) or die( mysql_error( $db_conn ) );

    if($headers) {
        // output header row (if at least one row exists)
        $row = mysql_fetch_assoc($result);
        if($row) {
            fputcsv($fp, array_keys($row));
            // reset pointer back to beginning
            mysql_data_seek($result, 0);
        }
    }

    while($row = mysql_fetch_assoc($result)) {
        fputcsv($fp, $row);
    }

    fclose($fp);
}

// Using the function
$sql = "SELECT * FROM table";
// $db_conn should be a valid db handle

// output as an attachment
query_to_csv($db_conn, $sql, "test.csv", true);

// output to file system
query_to_csv($db_conn, $sql, "test.csv", false);

Upvotes: 2

Jeff Wilbert
Jeff Wilbert

Reputation: 4520

Sounds like a trivial question... there's any number of ways, if the user is logged in then simply check the file they're requesting belongs to them.

The best way to do this would probably be to use a pass-through file. For example the request to /username/file would actually be calling /download.php?id=username&dl=file in which you can then checked the logged in user is equal to id or the username of the file trying to be downloaded from and if they match then use php header location to redirect the request to another location although that can be exploited by looking at headers; so to make it seemless, you'd store the files outside the web directory and read in the file using php and output it directly to the browser.

Upvotes: 0

Josh Foskett
Josh Foskett

Reputation: 4121

You could make a file called download.php, for example:

if($logged_in && $username == $_GET['download_username']) {

    header("Content-Type: application/force-download");
    header('Content-Disposition: attachment; filename=nameofdownload.zip');
    readfile('downloads/' . $_GET['download_username'] . '/file.zip');

}

Then in the downloads folder, you could create a .htaccess file, and put the following:

Deny from all

Upvotes: 1

Shane Fright
Shane Fright

Reputation: 385

Unfortunatley you will need to wrap the download in some code. You can use a technique similar to this:

if ($user->is_correct_user_with_access())
{
     header('Content-Type: application/octet-stream'); // this can be replaced with whatever file format you want;

     echo file_get_contents($local_path_to_file);
     die;
}

Also ensure that the file you are generating is not in a path that is publicly accessible (ie, it should be below your document root)

Upvotes: 0

Shomz
Shomz

Reputation: 37701

If the user is not logged in, or if it's a wrong user, just show a message or redirect or whatever you want instead of giving access to the file. And that url example you've shown should be only a page with a link or redirection to a real file. You can even generate a file name hashes for even better security.

Upvotes: 0

Andrew Barber
Andrew Barber

Reputation: 40150

I was about to edit your question and remove the sql and csv tags because, as asked, it doesn't really have to do with those topics. However, my answer does.

Instead of saving a file to the file system, just generate the csv file for output directly to the response. Your code would only generate the correct csv for the user (or no content for non users), thereby solving the problem.

This assumes generation of the file is modestly lightweight and would not be done very frequently.

Upvotes: 1

Related Questions