WOPR Posted February 9, 2010 Share Posted February 9, 2010 I'm trying to use a download.php script to hide the directory where the files I am going to serve are located. This seems like it should be a relatively simple task but for some reason this is just absolutely confounding me....it's been a while since I messed around with php so it's probably something stupid that I am missing but so far for the life of me I can't figure out the problem. Here's what I've got in my download.php script (one that I found by googling): <?php // Usage: <a href="download.php?file=captcha.png">Download[/url] // Path to downloadable files (will not be revealed to users so they will never know your file's real address) $hiddenPath = "http://www.themeinerz.com/dl_files/ut3/maps/pc/"; // VARIABLES if (!empty($_GET['file'])){ $file = str_replace('%20', ' ', $_GET['file']); $category = (!empty($_GET['category'])) ? $_GET['category'] . '/' : ''; } $file_real = $hiddenPath . $category . $file; $ip = $_SERVER['REMOTE_ADDR']; // Check to see if the download script was called if (basename($_SERVER['PHP_SELF']) == 'download.php'){ if ($_SERVER['QUERY_STRING'] != null){ // HACK ATTEMPT CHECK // 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) { if ((substr($file, 0, 1) == '.') || (strpos($file, '..') > 0) || (substr($file, 0, 1) == '/') || (strpos($file, '/') > 0)) { // Display hack attempt error echo("Hack attempt detected!"); die(); } //--------------------DEBUG----------------------- echo "file is: $file "; echo "file_real is: $file_real "; echo "POST:"; print_r($_POST); echo "GET:"; print_r($_GET); //--------------------DEBUG----------------------- // If requested file exists if (file_exists($file_real)){ // Get extension of requested file $extension = strtolower(substr(strrchr($file, "."), 1)); // Determine correct MIME type switch($extension){ case "png": $type = "video/x-ms-asf"; break; case "avi": $type = "video/x-msvideo"; break; case "jpg": $type = "application/octet-stream"; break; case "jpeg": $type = "video/quicktime"; break; case "mp3": $type = "audio/mpeg"; break; case "mpg": $type = "video/mpeg"; break; case "gif": $type = "video/mpeg"; break; case "rar": $type = "encoding/x-compress"; break; case "txt": $type = "text/plain"; break; case "wav": $type = "audio/wav"; break; case "pdf": $type = "text/plain"; break; case "doc": $type = "audio/wav"; break; case "jpeg": $type = "text/plain"; break; case "bmp": $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 * $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 set_time_limit(0); print(fread($stream,1024*Cool); flush(); } fclose($stream); } }else{ // Requested file does not exist (File not found) echo("Requested file does not exist"); die(); } } } ?> What I have then at the moment for testing is simply a blank index page with an a link passing in the file name like this: <a href="download.php?file=CTF-SpoonDog_PC.rar">download[/url] I added the "debug" section to the .php script so I could see what was being set and make sure the variables look right and they do because when I hit the link it shows me this: file is: CTF-SpoonDog_PC.rar file_real is: http://www.themeinerz.com/dl_files/ut3/maps/pc/CTF-SpoonDog_PC.rar POST:Array ( ) GET:Array ( [file] => CTF-SpoonDog_PC.rar ) Requested file does not exist If I do a copy paste of the real_file value into a new browser tab it see's the file just fine...so what the heck is the deal here (why does it say the file doesn't exist)....any help would be greatly appreciated. Quote Link to comment Share on other sites More sharing options...
Psycho Posted February 9, 2010 Share Posted February 9, 2010 You should define the path relative to the server - i.e. not over http. What is the actual path to the file ON THE SERVER? The location of the file shouldn't even be externally accessible over the internet if you are trying to protect it. Quote Link to comment Share on other sites More sharing options...
WOPR Posted February 9, 2010 Author Share Posted February 9, 2010 The pages that will have the links to download the files are on a different server than the files themselves that was why I thought I had to give it the full http address. So the file is at http://www.themeinerz.com/dl_files/ut3/maps/pc/CTF-SpoonDog_PC.rar The page that will link to that file is http://www.iamgaming.com/dev/dltest/ The reason I'm doing this is because I have unlimited bandwidth on one server and not on the other... My main goal here is just to prevent people from seeing the path and posting direct download links to the file/s on sites other than mine. Quote Link to comment Share on other sites More sharing options...
d_barszczak Posted February 9, 2010 Share Posted February 9, 2010 Hi WOPR, I use this to get files off my local server to prevent full path disclosure but I have no idea if you can retrive files over http. <?php $filename = "CTF-SpoonDog_PC.rar"; $realfile = "http://www.themeinerz.com/dl_files/ut3/maps/pc/CTF-SpoonDog_PC.rar"; header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename='.basename("filename")); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); readfile($realfile); ?> May be worth a try. Quote Link to comment Share on other sites More sharing options...
Psycho Posted February 9, 2010 Share Posted February 9, 2010 The reason I'm doing this is because I have unlimited bandwidth on one server and not on the other... In order to "read()" a file it has to be, well, read. That means the server calling the file is reading it from the external server and then serving it to the user. You are, in effect, trippling your overall bandwidth and doubling it on the server where you have limited bandwidth: Example: User requests 10MB file from server 1 Server 1 reads file from server 2 - Server 1 uses 10MB in bandwidth from download - Server 2 uses 10MB in bandwidth from upload Server 1 then serves the file to the user - Server 1 uses 10MB in bandwidth from upload So, that 10MB file just cost you 30MB of bandwidth overall and 20MB is on server 1 (where you have limited bandwidth). Quote Link to comment Share on other sites More sharing options...
WOPR Posted February 10, 2010 Author Share Posted February 10, 2010 The reason I'm doing this is because I have unlimited bandwidth on one server and not on the other... In order to "read()" a file it has to be, well, read. That means the server calling the file is reading it from the external server and then serving it to the user. You are, in effect, trippling your overall bandwidth and doubling it on the server where you have limited bandwidth: Example: User requests 10MB file from server 1 Server 1 reads file from server 2 - Server 1 uses 10MB in bandwidth from download - Server 2 uses 10MB in bandwidth from upload Server 1 then serves the file to the user - Server 1 uses 10MB in bandwidth from upload So, that 10MB file just cost you 30MB of bandwidth overall and 20MB is on server 1 (where you have limited bandwidth). Wow that is an excellent point that never even crossed my mind...So let me ask you this....does that scenario still apply if the download.php file was on server2 and I linked to it from server1? Then everything comes from server2 even though you initiate it from a link on a page hosted by server1...right? Quote Link to comment Share on other sites More sharing options...
Psycho Posted February 10, 2010 Share Posted February 10, 2010 Wow that is an excellent point that never even crossed my mind...So let me ask you this....does that scenario still apply if the download.php file was on server2 and I linked to it from server1? Then everything comes from server2 even though you initiate it from a link on a page hosted by server1...right? If I am understanding you correctly, that should work. You might even be able to do a header redirect from server 1 to server 2 to sort of mask it from the user, but I wouldn't guarantee that without validating it. Example: Script on server 1 for downloading files if (isset($_GET['file_id'])) { header("Location: http://www.server2.com/downloadFile.php?file_id={$_GET['file_id']}"); } Then just create the requisite script on server 2 Quote Link to comment Share on other sites More sharing options...
WOPR Posted February 10, 2010 Author Share Posted February 10, 2010 yep yep got it. I will make sure to confirm that this works by watching my bandwidth but it makes sense to me. Thanks a lot for the help! @ d_barszczak thanks for posting your code, that helped me clean up the script I was using. Quote Link to comment Share on other sites More sharing options...
d_barszczak Posted February 10, 2010 Share Posted February 10, 2010 No problem, I never even thought of the bandwidth thing good job somebody did Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.