I have zip files in my website and I made a log in system so only users with valid passwords can download the zip files ONCE.
But there is always a possibility that they can download the zip files directly by entering the file path in the browser address bar.
You can get the link of the zip file by viewing the source code.
How can I deny people from downloading zip files by simply posting the file link in the browser address bar? is possible?
Instead of placing the file in a web accessible folder (/var/www/ for example), place it above it so users can't browse to it (like /var/files). Then to serve it to your users, after they type the password, with a php script, have the script set the headers as they would if it were a file, and use readfile to output the contents of the file to the user.
Firstly, create a folder in your root (~/) called secure_zip or something. This should sit alongside your public_html folder (meaning they cannot be accessed by typing in a URL).
Next, create a new php script, called file.php or something:-
<?php
public function sendFile() {
$filename = "sample.zip";
$attachment_location = $_SERVER["DOCUMENT_ROOT"]
. "../secure_zip/" . $filename;
if (file_exists($attachment_location)) {
header('Cache-Control: public'); // needed for i.e.
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . $filename . '"');
readfile($attachment_location);
die();
} else {
die('Error: File not found.');
}
}
And call sendFile() if you authenticate the user using whatever logic you like, eg:
if (true) { sendFile(); }
Related
I have a website where users can login and are identified by sessions and $user[id]. They can upload files. Files are stores in htdocs/uploads. Every file data is stored in a table to have a link between filename, location and user_id. On some places on my website i give the possibility to download the file by: <a href="' . $row['path'] . '" target="_blank" download>Download file</a>.
Behind $row['path'] a URL like domain.com/uploads/filename.jpg is given. If the user know this URL path he can download the file also without login or identification by entering the URL into a browser. I want to avoid this. How can i ensure, that only files can be downloaded from htdocs/uploads by click on such a download link on my website.
=> I am not able to create a folder outside htdocs
=> I have tried to change the folder permissions but w/o success
=> My website is basically made in PHP, a solution in PHP is prefered.
Any idea/help available? Thank you!
You will need to go down the route of making PHP serve the file for you. This will ensure that you can validate user credentials before serving the file.
See examples on php.net here. This will explain how to serve files from PHP using header(). This answer also outlines some of the key concepts.
Once you've done this, you can deny direct access to these files using htaccess rules. This will ensure users can only access the files via the php endpoints, and those endpoints can perform validation of the user's credentials.
I have solved it by doing following:
Added a .htaccess file in my folder htdocs/uploads with following content:
<FilesMatch ".*">
Order Allow,Deny
Deny from All
</FilesMatch>
Created a file: file_download.php with following content:
// Doing here some user verification based on the session and user_id
if($user['id'] != 'something i want to be') {
die('Not allowed to download this file');
} else {
// Verify the download as requested
// Basic file name
$file = basename($_GET['file']);
// Path where the file should be stored
$file = 'uploads/'.$file;
if(!file_exists($file)){ // file does not exist
die(''.$file.' file not found');
} else {
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$file");
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: binary");
// read the file from disk
readfile($file);
}
}
Changed the download link from <a href="' . $row['path'] . '" target="_blank" download>Download file</a> to <a href="file_download.php?file=<?= $row['path'] ?>Download</a>
This way is blocking any try to download a file by using clear URL in the browser. the file can only be downloaded by having a user identification and the provided link from my website. If someone does not need the user verification, just delete the first if/else in the file_download.php.
When user want to download file from my web site, user have to click link like below
https://www.example.com/download.php?aaa=111&bbb=222
download.php
<?PHP
session_start();
include("connect.php");
$aaa = mysql_real_escape_string($_GET[aaa]);
$bbb = mysql_real_escape_string($_GET[bbb]);
if(($aaa = '111')&($bbb = '222')) // this line is example for ask stackoverflow //
{
$filePath_try_to_download = 'attachments_files/test.pdf';
if(file_exists($filePath_try_to_download))
{
$fileSize = filesize($filePath_try_to_download);
$fileName = "test.pdf";
header("Cache-Control: private");
header("Content-Type: application/stream");
header("Content-Length: ".$fileSize);
header("Content-Disposition: attachment; filename=".$fileName);
// Output file.
readfile ($filePath_try_to_download);
exit();
}
}
?>
I want to know when user download file from this link https://www.example.com/download.php?aaa=111&bbb=222 user can get my file path on server or not (attachments_files/test.pdf). If user can get my file path, how can i hide it's ? (file in this dir is very importance)
Since I was posting comments from my Phone, they couldn't really explain much, so here goes your answer.
I want to know when user download file from this link https://www.example.com/download.php?aaa=111&bbb=222 user can get my file path on server or not (attachments_files/test.pdf).
No, Users can not see that file path which you are reading via readfile(). They will not be able to find out that file's location at all.
And if you want to eliminate any chances of people guessing the file path simply put those files outside of your web root folder and then readfile() them from there.
$filePath_try_to_download = 'attachments_files/test.pdf';
That path is only known to your PHP code, which is not visible to users hence they have no idea from where did you read the file they are downloading, just eliminate the guesswork chances though :)
And Obviously you have to secure access to this url https://www.example.com/download.php?aaa=111&bbb=222 otherwise what's the point!
No. The user cannot get the file path. He only get the content outputed by PHP script.
Your can do this and the user only get the "Hello" string. So it's your PHP script's role determining which contents the user can get.
<?php
echo "Hello";
?>
Coult not find any similar problem solved on the web, so here's my situation:
I have a .jsp "webpage" that generates a .csv file based on specific parameters.
As an example, if I use my browser to open the site, I type in:
redownloadsubmitter.jsp?id=225&batch_id=2013_11_20&orgshort=NEP
The script then uses the data in the query string and generates the matching .csv file, named: NEP_DETAILS_2013_11_20.csv
Now what I want is to not manually having to use my browser, open the script and download the file to my local harddrive. Instead I want to use a PHP script that grabs the content and then can further format it, based on my needs.
I thought about the following code, but that did not work. Instead it returns nothing, empty website when I try it..
$download = file_get_contents('redownloadsubmitter.jsp?id=225&batch_id=2013_11_20&orgshort=NEP');
echo $download;
Any other ideas?
NOTE: just in case someone has this question: I have no access to the .jsp file and I therefore cannot change how it operates.
file_get_contents() isn't smart and doesn't know that's a URL you're passing in. It's trying to literally open a local file whose name is redownloadsubmitted.jsp.etc......
If you want f_g_c() to do an HTTP operation, then you'll have to include a full-blown URL:
$download = file_get_contents('http://example.com/redownloadsubmitter.jsp etc....');'
Try this code for download file.
<?php
/**
* $filename filename in server
* $downloadname filename when download file
*/
$filename = __FILE__;
$dowloadname = 'PHPDownload.php';
Header("content-type:application/octet-stream");
Header("Accept-Ranges: bytes");
Header("Accept-Length: ".filesize($filename));
Header("Content-Disposition: attachment; filename=".$dowloadname);
if(file_exists($filename) && $fp=fopen($filename,"r")) //file exists and open it
{
echo fread($fp,filesize($filename)); //read write to the browser
fclose($fp);
}
//End_php
I am trying to provide .pdf and .doc files to authorized users on a website. The user can only see the file selection page when logged in but this doesn't prevent an unauthorized user from viewing the documents if they have knowledge of the full URL.
How can I prevent unauthorized users from accessing these files?
the answer is quite simple,
#Jonnix has posted this as I was typing but I will explain a little more for you
one put your files outside of your public HTML directory if your unable to do this look at #Andri answer for an alternative
E.G cpanel setup
user/public_html
/public_html/download.php
user/documents/
/documents/file.doc
/documents/file.pdf
#dhh has posted a basic download.php php file however as your wanting to force download their things you can do like finding and supplying the correct mime type here is an extension on to his code as to the best way to 1 force download of a file, and 2 allow different file types
download.php
//check users is loged in and valid for download if not redirect them out
// YOU NEED TO ADD CODE HERE FOR THAT CHECK
// array of support file types for download script and there mimetype
$mimeTypes = array(
'doc' => 'application/msword',
'pdf' => 'application/pdf',
);
// set the file here (best of using a $_GET[])
$file = "../documents/file.doc";
// gets the extension of the file to be loaded for searching array above
$ext = explode('.', $file);
$ext = end($ext);
// gets the file name to send to the browser to force download of file
$fileName = explode("/", $file);
$fileName = end($fileName);
// opens the file for reading and sends headers to browser
$fp = fopen($file,"r") ;
header("Content-Type: ".$mimeTypes[$ext]);
// this header tells the browser this is a download and not to try and render if it is able to E.G images
header('Content-Disposition: attachment; filename="'.$fileName.'"');
// reads file and send the raw code to browser
while (! feof($fp)) {
$buff = fread($fp,4096);
echo $buff;
}
// closes file after whe have finished reading it
fclose($fp);
P.S here is a big list of mime types if you want to add support for other files
https://www.freeformatter.com/mime-types-list.html
What you can do, is provide the equivalent of a PHP proxy for the files.
Put the files outside of the webroot, then write a script that checks the user is allowed access. If not, redirect them, if they do, set the appropriate headers and output the file data.
You should store all downloads outside your public / user-accessable doc root (but inside your basedir, of course) and add a download script for sending the download if the user is authorized.
Here's some example of how to "send" a file for downloading it.
$file = "ireland.jpg";
$fp = fopen($file,"r") ;
header("Content-Type: image/jpeg");
while (! feof($fp)) {
$buff = fread($fp,4096);
print $buff;
}
This did the job for me: I placed a .pdf and a .htaccess file with the following code in it in a normal folder (i named it "docs") on my apache webserver.
Order Deny,Allow
Deny from all
Allow from 127.0.0.1
<Files /index.php>
Order Allow,Deny
Allow from all
</Files>
Then i took the code from Martin Barkers answer above, changed the filepath to "docs/sample.pdf", and pasted it into a .php file in my root directory. That's it. You can't access the file per url now, but you can download it if you run test.php.
I have a file that users will purchase via paypal, clickbank and paydotcom. I have to host the file's download page on my server.
I've placed the file in a directory outside my public_html folder. The folder is on the same level as public_html and called "download" for example.
The script below is supposed to do that, but I have two problems with it...
1) It doesn't seem too secure. just check for a payment confirmation token on the querystring?
2) I can't the $path variable to point to the download folder without including my site.com public folder in the path. For example, when I echo $path, I get
/home/myuser/public_html/mysite.com
But I need it to resolve to
/home/myuser/download/myprotectedfile.zip
I'm sure there is a more secure or clever way to do this, so I'm asking...
<?php
// place this code inside a php file and call it f.e. "download.php"
$path = $_SERVER['DOCUMENT_ROOT']."/path2file/"; // change the path to fit your websites document structure
$fullPath = $path.$_GET['download_file'];
if ($fd = fopen ($fullPath, "r")) {
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);
switch ($ext) {
case "pdf":
header("Content-type: application/pdf"); // add here more headers for diff. extensions
header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\""); // use 'attachment' to force a download
break;
default;
header("Content-type: application/octet-stream");
header("Content-Disposition: filename=\"".$path_parts["basename"]."\"");
}
header("Content-length: $fsize");
header("Cache-control: private"); //use this to open files directly
while(!feof($fd)) {
$buffer = fread($fd, 2048);
echo $buffer;
}
}
fclose ($fd);
exit;
// example: place this kind of link into the document where the file download is offered:
// Download here
?>
The problem I'm having in getting this to work is the the value of $path includes my site.com reference, but the download directory is outside site.com. I need to get a reference up a level in order to point to the directory that holds the download file.
Also, as I stated earlier, I'm not sure how to do this (other than checking for an expected querystring value in a manner that's secure)
Thanks in advance!
You can use the parent directory shortcut ../ in your $path or the dirname function like:
$parent_dir = dirname( dirname( __FILE__ ) );
// first dirname is the directory of this file, second goes up one level, etc.
BTW, beware of indicating the path in your URL, one could read other files (like configuration files or ohter private files) by changing it to download.php?download_file=../../private/bank_certificate.pem. You should use realpath to get the absolute path of the file and compare it to an "authorized for download" file list.
You just need to consider the path like a normal directory path, not a web one. so to go up a level simply "../" e.g.
if you structure is like this
/path2file/inhere.pdf
/public_html/download.php
the path to the file would simply be from download.php "../path2file/inhere.pdf"
well if public_html is your doc root then you should be able to get the path to download would be
realpath($_SERVER[DOCUMENT_ROOT].'/../download');
Custom coding may not be the best solution these days for a file download script. Check out Drupal which has file download modules, that can be integrated with its Clickbank module as well:
http://drupal.org/project/clickbank_ipn