redirecting to a folder that does not have public access privilage

Hi, I am trying to set up the following functionality for a website that provides music lessons in the form of video and audio lessons:

Members of the site will login to their account using their un/pw set. Once they login, they can purchase individual lessons and of course a database keeps track of the lessons that this individual has purchased.

Now here is the part that I have problem with and I am hoping that it is possible to do the following: What I like to do is to have these video and audio files residing in a folder with no public access privilege (only owner and group privilege). This way no one can access these files by directly typing the video file address on their browsers and accessing them directly. Meanwhile members who log into their accounts should be able to click on a link in their member area and view the lessons that they have paid for.

thanks in advance
dmehranAsked:
Who is Participating?
 
KoorooConnect With a Mentor Commented:
You want code that looks like this:

$file = "absolute system path to file";
header("Content-Description: File Transfer");
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=".basename($file));
@readfile($file);

What this does is it will send a download for any file in the system that you define in $file regardless of it's visibility to the web service itself. so for instance, let's say I have a file in /home/moo/file.dat and the webserver's document root is in /usr/www/ ... under normal circumstances, there should be no way for a user with a browser to get my file (not necessarily true, but close enough). If I write a script called download.php and put it in /usr/www/ with the following contents,

<?php
$file = "/home/moo/file.dat";
header("Content-Description: File Transfer");
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=".basename($file));
@readfile($file);
?>

a user putting in http://yourdomain.tld/download.php will get prompted to download file.dat .... even though it exists outside the scope of the web server. Now following along, since $file is simply a string, your script can be able to specify the path to the file dynamically following a user/pass authentication or using any php structure at all.

so, I can do the following :
<?
if ((($_POST['user'] == "John") || ($_POST['user'] == "Tom")) && ($_POST['password'] == "moo!"))
{
$file = "/home/moo/" . $_POST['user'] . ".dat";
header("Content-Description: File Transfer");
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=".basename($file));
@readfile($file);
}
?>

and now, if either user John or Tom submits their username and a password of "moo!", they should be prompted to download John.dat or Tom.dat ... depending on the user. Now this is a fairly trivial piece of code and woefully insecure, but I think it should be enough to get you started.

One major caveat though,
make sure to have some verification or security around whatever you use for the path to the file. Make sure it's not something a user can specify or is passed via a form or register_globals or url parsing as then they'll be able to attempt to download any file on the system...like a password file.
0
 
gruntarCommented:
This is the right way to do it as Kooroo said. since you're selling stuff you should check;

- if user is logged in (so that you prevent downloading if someone clicks on download.php and is not logged in)
- if user payed for the file that he want to download.

if those two criteria are fulfiled than you output file to download otherwise show error message.

cheers
0
 
virmaiorCommented:
Kooroo's solution is the core part of how you deliver the file to the user via PHP.
1.  The look of this can be significantly improved however by using the rewritemod in htaccess (assuming you are using apache).

the core file is still Kooroo's variant,
you just would place the following in a directory called "/lessons/"
beneath the web root:

.htaccess:

ReWriteEngine On
RewriteRule ^/?([^/]*\.pdf?|[^\./]*)[:;,\.]*$ /download.php [L,NS]

This in turn would translate any request for a pdf (alter the file type freely)
into a call to the download.php script...


within the script, you can then look at the $_SERVER['REQUEST_URI'] variable to determine the file they are looking for,
download it exactly how Kooroo suggested.
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
jdpipeCommented:
I think that the above is perhaps not the best approach. Rather that accepting a POST with the correct username and password, you should FIRST have a page where the user login details are sorted out, for example the following:

<?php
session_start();

$sql="SELECT password FROM users WHERE username=".mysql_escape_string($_POST['username']);

$res = mysql_query($sql);

if(mysql_num_rows($res)){
    $row=mysql_fetch_assoc($res);
    if($row['password'] == md5($_POST['password'])){
        $_SESSION['loggedin']=1;
        $_SESSION['username']=$_POST['username'];
        print("Please proceed to the <a href="download.php">download page</a>");
    }else{
        die("Password was incorrect");
    }
}else{
    die("Unknown username");
}

?>

Now, the above page will set a SESSION variable which records you current username and the fact that they have logged in. On the download page, you can now show a list of the products which your user has paid for (I won't cover that part here), and you can then provide access to those files only. The user won't have to type in their username and password every time they download a file.

--------------- download.php -------------------
<?php
session_start();
define("DOWNLOAD_DIR","/var/local/download/audiovideodownloaddirectory");

$action="list";
if(isset($_GET['action'])){

$sql="SELECT filename FROM useraccessrights WHERE username=".$_SESSION['username'];
$res=mysql_query($sql);
if(!mysql_num_rows($res)){
    die("You have no entitlements");
}




0
 
jdpipeCommented:
woops! more to come...

--------------- download.php -------------------
<?php
session_start();
define("DOWNLOAD_DIR","/var/local/download/audiovideodownloaddirectory");

$action="list";
if(isset($_GET['action'])){
   $action=$_GET['action'];
}

switch($action){
    case "list":
         $sql="SELECT filename FROM useraccessrights WHERE username='".$_SESSION['username']."'";
         $res=mysql_query($sql);
         if(!mysql_num_rows($res)){
              die("You have no entitlements");
         }
         while($row=mysql_fetch_assoc()){
             print("<a href=\"?action=fetch&file=".urlencode($row['filename'])."\">".htmlspecialchars($row['filename'])."</a><br>");
         }
         break;
   
    case "fetch":
        $sql="SELECT mimetype,filename FROM useraccessrights WHERE username=".$_SESSION['username']." AND    
               filename='".mysql_escape_string($_GET['filename'])."'";
        $res=mysql_query($sql);
        if(!mysql_num_rows()){
            die("Sorry, access denied");
        }
        $row=mysql_fetch_assoc($res);
        header("Content-Type: ".$row['mimetype']);
        header("Content-Disposition: attachment; filename=".$row['filename']);
        readfile(DOWNLOAD_DIR."/".$row['filename']);
}

?>

This last file does the job of checking that the user is logged in and then checking that they have the rights to access the file in question. The files are stored in a configurable directory of your choosing - off the DocumentRoot, so it's not publically accessible.

Does that help? I can give you the database structure if required.

JP


0
 
dmehranAuthor Commented:
Hello again and sorry for the late reply. First, thanks for the elaborate explanation and the tips as well as answers from the rest of experts. With a little variation of your solution I got it to work. I changed the MIME type setting from  ... "application/force-download" like kooroo suggested to the following:

header("Content-Type: video/x-ms-wmv");

above changes allows for the user to play the video from the server while downloading it. I had already made use of session variables like the example that 'jdpipe' provided and I didn't have problem setting up the database and verifying/authenticating the user before giving privilege for accessing the video files that are in windows media format.

Ideally it would have been nice if I could come up with an affordable way of preventing the user from downloading the files to their machine and only have them play the video files staight from the server everytime (without being able to download the file).


thanks again
0
 
jdpipeCommented:
I think that a good way to prevent downloading is to use a flash-based video player. Methods which use RTSP etc are still problematic.
JP
0
 
dmehranAuthor Commented:
good point 'jdpipe', as a matter of fact I started experimenting with flash video about 2 or 3 weeks ago and I am converting all my .wmv files to .flv formats. It is a lot of work but it does the job.

thanks
dmehran
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.