Is there a way, and if so, how, to allow only logged in users to download a file using Joomla and PHP?
Here is the situation:
When users are logged in, they can click the product's download link to be brought to a download page. They click download, and are able to download the file. However, these users may be beta testers, or the file may be sensitive, so I need to, somehow, hide the direct link to the file. Be it a PHP file or something that checks if the user is logged in (I'm already familiar on how to do that) and send the file to them. (Rather than a link to a .zip file for instance, a link to a .php page that will push the file to them)
Link to a PHP file in which you check if the user is logged in, and then you can initiate the download using the correct headers:
<?php
header("Content-Disposition: attachment; filename= filename.ext");
header("Content-type: application/octet-stream");
and then pass the file's contents through using fpassthru()
Related
I made a database system with PHP and MYSQL. It has a lot of sensitive information so I'm trying to put the best security.
I have a question about video and audio files. I want only people that are logged in and that actually have permission to download the files to be able to download them, not anybody that just points to the folder where the media files are. How can I do that?! Thanks!
Call your files via a php wrapper, i.e. <img src="files/file.php?id=oj348jfoj" /> and in your file.php you output the file with image headers if the user has the rights to view the file. In you table, you have the real image URI that corresponds to your oj348jfoj token, and this is what you file.php loads and outputs as image to the requester. This way the real URI of your server files stays hidden and you get to check access rights for every image load.
You need to stream the file using PHP. Pass the name of the file using the query string and then write it to the page. You can check the permissions before you stream the file over.
Pseudo-code:
header("Content-Disposition: atachment; filename=$filename");
header("Content-Type: application/octet-stream");
header("Content-Length: ".filesize("$path/$filename"));
header("Pragma: no-cache");
header("Expires: 0");
$fp=fopen("$path/$filename","r");
print fread($fp,filesize("$path/$filename"));
fclose($fp);
exit();
So. The files have to be on the server, that's clear. Here's a suggestion: hide them somewhere. Then, when a user hits download, copy its contents to a temporary location and save into a MySQL table with expiring 10-30 minutes (could be more if HUGE files). Then the user could download from that link. Finally, run a cronjob every 10-30 minutes (the same amount) that deletes expired files.
This isn't 100% security as a non-logged in can download too, but only if a logged-in shares the URL, so then they could simply send that to them.
I have a uploads folder under my website folder root. They contains mp3s. Now this folder should only be accessible once the user has completed paypal payment for that particular mp3 i.e once the payment is complete, the download link should be emailed to them and they should only be able to download from that link.
I don't need any code extra but I just a general strategy of how such websites protect their premium content?
I am using PHP but you can provide strategy in Asp.Net too if that's more comfortable to you.
You should just not store the MP3 files in a location accessible from the outside. Instead, the link you give to the user should be a link to a page (PHP or anything) which will
verify that the user has the right to access the resource
stream the asked resource to the user
Something like
download.php?mp3FileId=5435
The download.php will check if the user is authenticated and has paid for the file 5435, then read this file from a protected resource, and stream it to the HTTP response, with the appropriate content type set.
Send links to .php, not to .mp3 files. If user have access to file - display file using PHP.
Example link:
http://domain.com/download.php?file=music.mp3
Script:
if($have_access) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Length: ' . filesize($file));
flush();
readfile($file);
}else{
die('You have no access.');
}
You can do this several ways. But which ever you choose the user should be required to enter username/password to access the files.
Simplest (and most foolproof) way - a htaccess-file in the protected directory. See this link for tutorial: http://www.elated.com/articles/password-protecting-your-pages-with-htaccess/
This is very common to protect member and vip areas of websites.
The best way would probably be to have the user register on your site and choose his/hers own username/password, and activate the account when Paypal payment is completed.
Then I would go with the download.php?id=XXX approach presented above
EDIT: We allow our product download after submitting a simple form.
To avoid the owners of "illegal websites" learning where our product downloads are located, I was thinking about renaming the download folder after every download.
How can I do this in PHP?
Instead, verify an authenticated session and then stream the download via PHP.
Then if any illegal website tries to download your file, they will find they need to be authenticated first.
Don't rename the directory. It will break if multiple users download the file simultaneously. Instead serve file via PHP like:
<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');
// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// The PDF source is in original.pdf
readfile('original.pdf');
?>
Yes, - you can do it by using rename PHP function, but what a strange approach? You better customize access settings for files which can be accessed via HTTP request and which can not. Let just registered users download files and identify real users from robots using user session cookies and, probably, add captcha if those file are so significant.
A possible solution might be to do a PHP system call to create a temporary softlink to your installer, and remove that softlink after a fixed amount of time.
But indeed, it seems you've got the wrong idea when it comes to safeguarding your installer.
A good way is to use a combination of .htaccess & key
.htaccess
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^([^\.]+)/([a-z0-9]+/i)$ serve.php?file=$2&key=$1 [NC,L]
After someone purchases your file set a key and ip in there customer account in mySQL send them the link to download via email (http://yoursite.com/key1234567/your.pdf) note they can only download once
person clicks download
then with serve.php
you check the key against there ip in there account and mark as downloaded
sql check on ip and key match
if($allowedToDownload===true){
header('Content-type: application/pdf');
// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// The PDF source is in original.pdf
readfile('hidDen_ArEa/'.basename($_REQUEST['file']));
}
Nothing personal, but it's not most clever idea.
Check $_SERVER['HTTP_REFERER'] - if this variable is not empty and not contains address of pre-download page, redirect user to some your pre-download page.
edit: checking HTTP_REFERER is not 100% protection against bots, but other methods (such as authentication) can be more annoying for users.
Also, sessions or cookies (with temporary token) can be used.
Best solution so far is the following: http://www.devshed.com/c/a/PHP/Simple-and-Secure-PHP-Download-Script-with-Limits-Tutorial/.
Thanks to all of you for directing me to this approach.
I am required to create a small website that people access through a html login/password form where a session begins. I have completed this however I need to log when a user clicks a link and downloads a file.
I need to record which user has clicked to downloaded the file.
All I have at the moment is a link to a download.php as follows
link
download
file
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="somefile.pdf"');
readfile('somefile.pdf');
how would I go about logging who has actually downloaded a file?
It would be very trivial to record the session login details at the top of the download.php file. It's not necessary to redirect via another intermediary file.
If you want to stop people directly linking to download.php you should put some security check at the start of download.php.
You could create a table in your database for the logging, with the user id, dates etc.
In download.php simply have an if statement to determine whether they're logged in (i.e. session is set) and then insert a new row into your logging table, complete with the user id, dates and other data.
Ok two solutions:
First the easy one. Don't do anything! Yes, apache already logs all access to every file in access.log file. I know this is the lazy way but would it satisfy?
Second, ok let's say you need a better way. Does it need to be in the database or can it just be a file? If so, then in your down file open a database connection write to a table and close and then read the pdf file. Or you can write to a flat file if it can be simple as that.
I previously posted here:
Controlling Access for Trial Subscription
Since this is a new question based on suggestions there, I thought I should start a new post. If this should have been an edit, please let me know for the future.
I think the solution I'm going with to control access will be to upload a file and hash the name. The file will be in the format:
/uploads/#############.pdf
A link will be sent to subscribers. The first time they come to the site, they'll be asked to create a "pin" and a "hint" to remember. Then can then access a landing page to list their items via an email address/pin combo.
My question is: I know I can control the access to the page that shows what items they can view, but is there a way to control the /uploads/[file] to only be download-able after some kind of programmatic check? I can't think of any way to do this....
Thanks again.
D.
Your pdf files don't have to be in a user viewable directory. They can be outside your web root. That way, noone can actually browse to www.yoursite.ext/uploads/2395wrfhgt.pdf to download it himself or share the link with others.
In order to download the pdf you'll have a dedicated script that will do all the access checks on the user that's requesting it, and if all ok it will set the appropriate headers, read the file from the filesystem, and print it out to the user.
So, lets say your site is at /var/www/site/htdocs/ and you upload every pdf into /var/www/site/uploads/ . You don't even need to hash the filenames but instead can keep them nicely named for easy organization.
Then, all the links to download a file will be made to point to www.yoursite.ext/download.php?id={fileid}
Your download.php will do all the access checks (properly logged in, has permissions to download the file etc), and then do the following:
$pathToPdf = '/var/www/site/uploads/some.pdf' ;
header('Content-Type: application/pdf');
header('Content-Length: ' . filesize($pathToPdf));
header('Content-Disposition: attachment; filename=' . 'some.pdf');
readfile($pathToPdf) ;
And that's pretty much it. Once you get this working you can look into improving a few things:
use mod_rewrite or similar to have the actual pdf filename in the link, which helps some browsers realize they should download it: www.yoursite.ext/download/{fileid}.pdf
consider using the web server instead of php to serve files, eg X-Sendfile header