PHP: How can I block direct URL access to a file, but still allow it to be downloaded by logged in users?
Asked Answered
A

3

39

I have a website where users should be able to log in and listen to a song (a self-created mp3). I want to make it so the logged in user can listen/download/whatever, and the file should reside on the server (not be stored in the MySQL database), but not be able to be accessed by non-users who have the path to the URL.

For example: say my mp3 is located at mysite.com/members/song.mp3 If you are logged in, you should be able to see the mysite.com/members/index.php page, which will allow access to the song.mp3 file. If you're not logged in, the mysite.com/members/index.php page will not show you the song.mp3 file, and linking directly to it should not grant access.

I'm pretty sure this is done via htaccess, and I have done a lot of Googling already, and searched on here. The two closest answers I found were this htaccess guide http://perishablepress.com/press/2006/01/10/stupid-htaccess-tricks/ and this StackOverflow question Block direct access to a file over http but allow php script access but neither answer all my questions to meet my criteria. What am I missing?

Abbatial answered 19/8, 2011 at 20:39 Comment(0)
S
61

Into folder members create new folder files, move here all your songs, create new .htaccess file and add the following lines:

Order Deny,Allow
Deny from all


Into folder members create file get_song.php and add the following code:

if( !empty( $_GET['name'] ) )
{
  // check if user is logged    
  if( is_logged() )
  {
    $song_name = preg_replace( '#[^-\w]#', '', $_GET['name'] );
    $song_file = "{$_SERVER['DOCUMENT_ROOT']}/members/files/{$song_name}.mp3";
    if( file_exists( $song_file ) )
    {
      header( 'Cache-Control: public' );
      header( 'Content-Description: File Transfer' );
      header( "Content-Disposition: attachment; filename={$song_file}" );
      header( 'Content-Type: application/mp3' );
      header( 'Content-Transfer-Encoding: binary' );
      readfile( $song_file );
      exit;
    }
  }
}
die( "ERROR: invalid song or you don't have permissions to download it." );


And now, you can use this URL to get the song file:
http://mysite.com/members/get_song.php?name=my-song-name

Shelving answered 19/8, 2011 at 21:45 Comment(3)
Instead of denying direct access, you could store the file outside wwwroot.Descriptive
I tried this for reading a text file from the files folder and it worked but I could not show a jpeg image calling the php. I set content-type to image/jpeg. If anyone tried this with images can you please help me out.Lenticel
I tried this, but I am not able to open the files after they download: failed to open stream: HTTP request failed! HTTP/1.1 403 ForbiddenKnighterrantry
H
7

The only thing you can do for this via .htaccess is require a referer that comes from your site, and it is NOT secure. it is beyond trivial to forge a referer and anyone could suck your site dry.

The ONLY way you'll be able to have only logged-in users download the file is by placing the file OUTSIDE of your webroot and having a PHP script mediate access. In short:

if (is_logged_in()) {
   readfile($name_of_file);
} else {
   die("Access denied");
}
Homemade answered 19/8, 2011 at 20:44 Comment(1)
wouldnt say its "the only thing"Gadroon
G
3

Are you using a scripting language such as PHP to handle your website? if so then the best way is to create a script that handles "delivery" of the content. Save the content in a protected directory, ie above your http or www folder. Then when the user is logged in, the link to your content would look like this:

http://yoursite.com/listen.php?song_id=xxx

the script will locate the required song by the id and then present the data to the user

Gadroon answered 19/8, 2011 at 20:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.