views:

676

answers:

6

On the current website I'm working on, I've got a directory of files for users to download which would be really nice to have some security method other than obscurity ;)

I was wondering if there's any way to supply login information via PHP to htaccess as though a user were entering it.

Alternately, if anyone knows a better way to secure user downloads using PHP, that's also acceptable. All of my googling turns up "just use htaccess" which isn't really helpful, as from the non-savvy user's point of view, they have to log in twice every time they use the website.

My best guess at doing it exclusively with PHP is to store files above the web root, then copy them to a web accessible folder temporarily, but this seems highly inefficient and I couldn't think up any way to remove them after the download has finished.

Note: I don't own the server this is running on and don't have ssh access to it.

A: 

Why reinvent the wheel? Take a look at File Thingy, which is pretty easy to install and customise. If nothing else, you can study the source to learn how to perform the authentication step.

Paul Dixon
I could easily be way off, but it looks to me like that only authenticates that page. I need to protect from people just typing in a file name and downloading it.
Shadow
You can configure it exactly like that. See http://www.solitude.dk/filethingie/documentation/install
Paul Dixon
lol i just put file thingy in an app. although its just writing to the folder outside the webroot. it cant actually download those files . thats why i am looking at this question actually...
WalterJ89
+4  A: 

If files are not too big (Gb) you can always use readfile for file's download. In this mode you can check user's auth before, and if it's ok output file contents to user, otherwise send him to login page.

With this method you can put your files in protected (with .htaccess) directory so you can be sure that nobody who isn't authenticated can access them.

Alekc
The example given on the PHP doc is especially useful. Thanks.
Shadow
Better yet - put the files below the webserver's root directory, so you don't need to worry about securing the directory with .htaccess.
Dominic Rodger
readfile isn't a good idea. you have to set the correct headers and readfile doesn't support http "range".this means you kick out all download managers. Downloads are not resume able.
Bernd Ott
@Bernd Ott - This will work fine for me as no file will ever be over 20MB and I'll be surprised if that limit is ever approached, also the correct headers are shown on the PHP doc page, which seem to be working fine.
Shadow
Depending on your connection 20 Mbyte can be really really big.Headers are depending from file! sure you can always make a fake mime type, which always downloads (like application/x-download)
Bernd Ott
A: 
  1. You could use MySQL to store uploaded files, rather than storing them in a file, better and more secure, in my opinion. Just Google "MySQL upload php" for example.
  2. You could create the htaccess file using a PHP script, from your users table, each time a user accesses that folder, very troublesome.

I think the first option is better.

Moutaz
+3  A: 

I think I would either store them in a folder outside of the web root, or in a folder protected by .htaccess and then have a php script that checked if the user was logged in and allowed to download a file asked for. If he was, then just pass the file through to the user.

Example from linked page at php.net:

Example #1 Using fpassthru() with binary files

<?php

// open the file in a binary mode
$name = './img/ok.png';
$fp = fopen($name, 'rb');

// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));

// dump the picture and stop the script
fpassthru($fp);
exit;

?>


Someone else made a comment about having to report the correct content-type, which is true. Often, in my own experience, I already know it, or can use the file extension pretty easily. Otherwise you can always try to have a look at finfo_file. On that page there are also some comments about what you could do especially for images as well.

Svish
+1  A: 

you should use a php script to control the access. create a dir outside the webroot or inside the webroot with a .htaccess where you location the download files.

outsite the webroot is better.

you have to make sure that no one can access those files if they are located inside.

then take from the pear class lib. the class http_download.

using this class has many advantages.

  • Ranges (partial downloads and resuming)
  • Basic caching capabilities
  • Basic throttling mechanism
  • On-the-fly gzip-compression
  • Delivery of on-the-fly generated archives through Archive_Tar and Archive_Zip
  • Sending of PgSQL LOBs without the need to read all data in prior to sending

you should not use readfile oder any forwarding filepointer because you have to set the headers yourself and the don't support http "range".

for the access restrictions you can use you session-manager, password, framework, forum etc.

pear - http_download http://pear.php.net/package/HTTP_Download

you need to copy the url, because SO encodes it to url-encoded string (which is correct), but PEAR-homepage doesn't like that.

Bernd Ott
Error 404 - document not found
Svish
The underscore is encode by SO. replace the encoded value to the uscore again. pear homepage doesn't like encoded urls.
Bernd Ott
A: 

Hi Shadow,

Use X-SendFile! There's extensions for Apache, Lighty and NGinx so there's a good chance there's one for your webserver.

Once you have the extension installed, you can authenticate the user using your PHP script, and then add the header:

header('X-SendFile','/path/to/file');

When your PHP script is done, it will trigger the webserver to stream the file for you. This is especially efficient if you use PHP along with for example FastCGI, because it frees up the PHP process for other work.

Evert

Evert
I don't own the server and can't make changes to it at that level.
Shadow