Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

PHP download management

Status
Not open for further replies.

SgtBadass

MIS
Jul 16, 2002
19
GB
I'm looking to write something that will allow only logged-in users to download files (PDFs, Word docs etc).

I'll have the files in a directory so I'm looking at ways of stopping people from just finding the links, or passing links on to people.

Anyone got any ideas? Or links to software that does this?
 
picture the following directory listing:

.
..
index.php
login.php
/downloadables
/downloadables/one.pdf
/downloadables/two.pdf
/downloadables/.htaccess

the .htaccess file should contain the following
Code:
Deny From All

you, of course store your downloadable files in the downloadables directory ;-)

in the index.php file
Code:
<?
require_once "login.php";
$path = "downloadables/";
if (isset($_GET['filename'])):
$filename=$_GET['filename'];
$permittedfiles = array("one.pdf","two.pdf");//insert names of permitted files

if (file_exists($path.$filename) && in_array($filename, $permittedfiles)):
   $filesize = filesize($path.$filename);
   header('Content-type: application/octet-stream');
   header('Content-Disposition: attachment; filename="$filename"');
readfile($path.$filename);
	exit();
else:
  echo "invalid download attempt";
endif;
else:
?>
These files are available for download<br/>
<a href="<?=$_SERVER['PHP_SELF']?>?filename=one.pdf">One.pdf</a><br/>
<a href="<?=$_SERVER['PHP_SELF']?>?filename=two.pdf">Two.pdf</a>
<?
endif;
?>

note that you could use a directory crawl function to populate your variables and anchors.

in the login.php file use a cut down form of my login script. this needs the users and passwords to be stored in an array in the valid login function. there is no reason why you can't point this function at a db or a text file instead.
Code:
<?php 
session_start();
define ("TIMEOUT", 10); //set this to the number of minutes
//use this script by just including the page at the top of every real page
if (!loggedon()):  
	login();  
else:
	//do nothing
endif;

function loggedon() {
	//this tests the current status
	if (isset ($_SESSION['loggedon'])):
		if (login_expired()):
			$GLOBALS['msg'] = "Login expired";
			return false;
		else:
			$_SESSION['lastaccess'] = strtotime("now");
			return true;
		endif;
	else:
		$GLOBALS['msg'] = "You must log on to access this page";
		return false;
	endif;
}
function login_expired() {
	if (isset($_SESSION['lastaccess'])):
		if ( ($_SESSION['lastaccess'] + (TIMEOUT * 60 * 60) ) < strtotime("now") ):
			return true;
		else:
			return false;
		endif;
	else:
		return true;
	endif;
}

function logout($msg=NULL)
{
	unset ($_SESSION['loggedon']);
/*	if (isset($_COOKIE[session_name()])):
		setcookie(session_name(), '', time()-42000, '/');
	endif; */
	if (!empty($msg)) $GLOBALS['msg'] = $msg;
	display_login();
}
//master script
function login()
{
	if (!isset ($_POST['submit'])):
		logout();
	endif;
	
	switch ($_POST['submit']):
		case "Go":
			if (!test_fresh_login()):
				logout("You cannot use the back button to login");
			endif;
			
			if (!validlogon()):
				logout("Either username or password is incorrect");
			else:
				$_SESSION['username'] = $_POST['username'];
				$_SESSION['loggedon'] = true;
				$_SESSION['lastaccess'] = strtotime("now");
				unset ($_POST);
			endif;
		break;
		default:
			logout();
	endswitch;
}

function test_fresh_login()
{
	if (isset($_SESSION['uniqid'])):
		if (isset($_POST['uniqid'])):
			if ($_SESSION['uniqid'] === $_POST['uniqid']):
				unset ($_SESSION['uniqid']);
				return true;
			else:
				return false;
			endif;
		else:
			return false;
		endif;
	else:
		return false;
	endif;
}

function validlogon()
{
	print_r($_POST);
	if (!isset ($_POST['username']) || !isset ($_POST['pwd'])):
		return false;
	endif;
	$valids = array ("admin"=>"password"); //include list of valid username/passwords here
	if (
			(isset($valids[$_POST['username']]))
			 && 
			($valids[$_POST['username']] == $_POST['pwd'])):
		return true;
	else:
		return false;
	endif;
}
function display_login() {
echo "<hr>";
print_r($_SESSION);
print_r($_POST);
echo "<hr>";
$_SESSION['uniqid'] = uniqid("el_can_");
?>
<style type="text/css">
#loginform, {text-align:left;width:50%;border: 1px solid #669966;font-size:14px; margin:0 auto; font-family:Verdana, Arial, Helvetica, sans-serif;}
#loginform .row {clear:both;}
#loginform .field{float:right; width:57%; padding-left:1px; text-align:left}
#loginform .label {float:left; width:39%; padding-right:1px; padding-left:1px;; text-align:right;}
#loginform .row input[type="text"] {width: 90%;}
#loginform .spacer {line-height:1px;}
#loginform input {font-size:14px;}
#loginform .loginmessage {clear:both; width:100%; color:red; text-align:center;}
</style>
<div id="loginform">
<form action="<?=$_SERVER['PHP_SELF']?>" method="post">
<input type="hidden" name="uniqid" value="<?=$_SESSION['uniqid'] ?>" />
<input type="hidden" name="action" value="login" />
<div class="spacer">&nbsp;</div>
<div class="row">
	<span class="label">Username:</span>
	<span class="field"><input type="text" name="username"  /></span>
</div>
<div class="row">
	<span class="label">Password:</span>
	<span class="field"><input type="text" name="pwd"  />
<input type="submit" name="submit" value="Go" /></span>
</div>
</form>
<? if (!empty($GLOBALS['msg'])) echo "<span class=\"loginmessage\">{$GLOBALS['msg']}</span>"; ?>
</div> <!-- end login form -->
<?
exit;
}
?>

post back if this doesn't work for you.
Justin
 
Create a log in page. Other than that, you'd have to keep moving the files to other locations. That could be a hassle.

Mark
 
Marvellous stuff, I'll try it out but it's already given me ideas - thanks!
 
For added security, I usually keep my download directory outside of Apache's knowledge completely... that way if I bonehead up the htaccess file people still can't get to it.
 
Apologies if this sounds stupid (I don't know a lot about the inner workings of apache!), but do you mean by putting your docs outside the httpdoc directory?

These documents will be in a hosted environment, so I guess I'm limited to where I can put things.
 
what skiflyer means is that typically apache serves documents from a webroot - a directory in the filesystem and its subdirectories. php can address any directory in the filesystem to which it has read access.

so putting stuff outside the webroot means it can never be inadvertently served to users.

if you're on a hosted platform you can often point your domain name at a directory below your root. then you can store these kind of riles in the root and be confident (more or less) that people can't get to it.

but the htaccess solution works just as well if you set it up right.
 
you can stream the content, with a one-time working stream-id.
so, if they log in and "hack" the stream-id, it will only work that one time, as then you update the field to "close_stream" or something..

then they will only stream commercials about your webpage instead, lol.. or a bmp file, size of 200mb.. :p not as funny as it was when ISDN was still hip.

Olav Alexander Mjelde
Admin & Webmaster
 
Can you point me to an example of this streaming thing? I've still got dial-up users, a bmp file sounds marvellous!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top