[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

redirecting to a folder that does not have public access privilage

Posted on 2005-05-16
8
Medium Priority
?
259 Views
Last Modified: 2006-11-18
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
0
Comment
Question by:dmehran
8 Comments
 
LVL 4

Accepted Solution

by:
Kooroo earned 2000 total points
ID: 14015680
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
 
LVL 9

Expert Comment

by:gruntar
ID: 14016252
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
 
LVL 20

Expert Comment

by:virmaior
ID: 14018338
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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 7

Expert Comment

by:jdpipe
ID: 14018852
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
 
LVL 7

Expert Comment

by:jdpipe
ID: 14018928
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
 

Author Comment

by:dmehran
ID: 14033437
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
 
LVL 7

Expert Comment

by:jdpipe
ID: 14033585
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
 

Author Comment

by:dmehran
ID: 14039571
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

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Developers of all skill levels should learn to use current best practices when developing websites. However many developers, new and old, fall into the trap of using deprecated features because this is what so many tutorials and books tell them to u…
The title says it all. Writing any type of PHP Application or API code that provides high throughput, while under a heavy load, seems to be an arcane art form (Black Magic). This article aims to provide some general guidelines for producing this typ…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…
Suggested Courses
Course of the Month19 days, 1 hour left to enroll

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question