Hi everyone,

I'm stuck on the best way to handle this. In a nutshell, I'm creating a website that sets up forums between one or several parties. Each participant of a forum can upload file attachments to any message they post.

What I want is a way to protect those uploads from being downloaded by non-authorized parties. The way it works now, I have a script that takes the forumID and the messageID, checks to make sure the user has access to the forum, and if so, returns the file to them for download. The problem however, is that if someone knows the file path "ex - user_data/forums/2400/filename.ext", they can grab it from there.

I don't want to have to make the user type in their username/password again in order to access the file, as is the case if I used .htaccess and .htpasswd....at least that I know of.

Anyone have suggestions?

EDIT: I guess I should caveat that by saying...a way OTHER than placing documents above the web root :)

8 Years
Discussion Span
Last Post by compdoc

ok found this on another forum. you might be able to work with it. you can also do a surch for (hide download url php script)

// Usage: <a href="download.php?file=test.txt&category=test">download</a>
// Path to downloadable files (will not be revealed to users so they will never know your file's real address)
$hiddenPath = "secretfiles/";

if (!empty($_GET['file'])){
$file = str_replace('%20', ' ', $_GET['file']);
$category = (!empty($_GET['category'])) ? $_GET['category'] . '/' : '';
$file_real = $hiddenPath . $category . $file;

// Check to see if the download script was called
if (basename($_SERVER['php_SELF']) == 'download3.php'){
if ($_SERVER['QUERY_STRING'] != null){
// Make sure the request isn't escaping to another directory
if (substr($file, 0, 1) == '.' ¦¦ strpos($file, '..') > 0 ¦¦ substr($file, 0, 1) == '/' ¦¦ strpos($file, '/') > 0){
// Display hack attempt error
echo("Hack attempt detected!");
// If requested file exists
if (file_exists($file_real)){
// Get extension of requested file
$extension = strtolower(substr(strrchr($file, "."), 1));
// Determine correct MIME type
case "asf": $type = "video/x-ms-asf"; break;
case "avi": $type = "video/x-msvideo"; break;
case "exe": $type = "application/octet-stream"; break;
case "mov": $type = "video/quicktime"; break;
case "mp3": $type = "audio/mpeg"; break;
case "mpg": $type = "video/mpeg"; break;
case "mpeg": $type = "video/mpeg"; break;
case "rar": $type = "encoding/x-compress"; break;
case "txt": $type = "text/plain"; break;
case "wav": $type = "audio/wav"; break;
case "wma": $type = "audio/x-ms-wma"; break;
case "wmv": $type = "video/x-ms-wmv"; break;
case "zip": $type = "application/x-zip-compressed"; break;
default: $type = "application/force-download"; break;
// Fix IE bug [0]
$header_file = (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ? preg_replace('/\./', '%2e', $file, substr_count($file, '.') - 1) : $file;
// Prepare headers
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public", false);
header("Content-Description: File Transfer");
header("Content-Type: " . $type);
header("Accept-Ranges: bytes");
header("Content-Disposition: attachment; filename=\"" . $header_file . "\";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($file_real));
// Send file for download
if ($stream = fopen($file_real, 'rb')){
while(!feof($stream) && connection_status() == 0){
//reset time limit for big files
// Requested file does not exist (File not found)
echo("Requested file does not exist");

Thanks for the code; I may implement a form of that in as well, but I'd like to actually protect the files themselves, just in case someone finds out where they are stored. I think I may use .htaccess and see if I can't loop back to my existing script with that.


you could always password protect the directory they are stored in, that way if someone finds out where they are they will need a password. you should be able to put a password on the directory from your webhost control panel

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.