This can not possibly work:
chmod($filename, 0755);
echo "<td><iframe src='" . $filename . "' width=645 height=600 frameborder=0></iframe></td>";
chmod($filename, 0600);
You're making the file readable only for the amount of time it takes PHP to echo that one line of HTML. I.e., by the time the user clicks the link, permissions have already been revoked again. On top of that, the file is world-readable for that period of time, so anybody on the Internet can see it.
To do this more securely, do not have the web server serve the files directly, as you will not be able to control who has access to them. Instead, put them outside the document root so that they can not be seen at all by the web server, and then proxy them through a PHP script (via readfile() or similar) that performs an ownership check.
In your script that generates the link:
echo '<a href="/download.php?file=' . $fileId . '">PDF Download</a>';
Where $fileId
is some unique identifier for the file, but not the full file name.
Then, in download.php, something like this:
function getLoggedInUser() {
// return the logged-in user
}
function getFileForId($fileId) {
// get the full path to the file referenced by $fileId
}
function getOwnerOfFile($fileId) {
// get the user allowed to see the file referenced by $fileId
}
$fileId = $_GET['fileId'];
$file = getFileForId($fileId);
if (!file_exists($file)) {
header('HTTP/1.1 404 Not Found');
exit;
}
if (getLoggedInUser() !== getOwnerOfFile($fileId)) {
header('HTTP/1.1 403 Forbidden');
exit;
}
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="whatever.pdf"');
readfile($file);
[UPDATE]
and I have <a href="/viewbill.php?bid=<?php echo $invoice_number; ?>" title="View PDF Invoice">
where the $invoice_number is the name of the file.
That's fine, just make sure that viewbill.php performs a check to ensure that the logged-in user is the same as the user that the bill is for, otherwise any customer can view any other customer's bills simply by changing the invoice number in the URL.
When you say 'put them outside the document root' where do you mean exactly;
Let's say that your Apache document_root
directive points to /var/htdocs/public/
. In this case, everything in that directory and everything under it can be seen by Apache and potentially served directly to a client. E.g., if you have a PDF file in /var/htdocs/public/pdfs/12345.pdf
then a user can simply request the URL /pdfs/12345.pdf
in their browser, regardless of what PHP structures are in place. Often this is mitigated with the use of .htaccess files but this is not ideal. So, if you have files that you want to keep controlled, you should not put them anywhere under the document_root. For example, put them in /var/htdocs/docs/
instead. This way, Apache can not possibly see them, but you can still use readfile()
to pull their contents.