Allow a PHP script access to PDFs in a folder - bu

2019-08-15 05:52发布

问题:

On a godaddy hosted website using CPanel, I have a small PHP script that shows each line in a text file that's on the server. Each line contains a private href link to a PDF that only the logged-in user can see. The links points to various PDFs in the same folder on the server. The code works fine and I can click on the link and see each PDF.

The problem is that each PDF can also be seen by using a direct URL query (i.e. website/folder/pdfname.pdf). As these are private PDFs, I don't want them public. I've tried changing CPanel permissions on the folder to "owner" - but that seems to prevent the PHP script from opening the PDFs also.

Is there a way to allow a PHP script access to PDFs in a folder - but prevent direct URL references?

NOTE: I'm not particularly adept at PHP or CPanel - sorry.

Code...

$fname = "PDF-" . $user_name.".txt";
$fnum = fopen($fname,"r");
echo "<tr>";
While (($str = fgets($fnum)) !==  false) {
    $arr = explode("|",$str);   
    for ($x  = 0 ;  $x < count($arr);  $x++) {
        echo "<td>$arr[$x]</td>";
    }
    echo "</tr>";   
}
echo "</tr>";
fclose($fnum);

File contents...

Xyz Company|21 Jan 2018|<a href="http://website.com"> website link</a>
Xyz Company|21 Jan 2018|<a href="http://website.com"> website link</a>
Xyz Company|21 Jan 2018|<a href="http://website.com"> website link</a>
Xyz Company|21 Jan 2018|<a href="http://website.com"> website link</a>*

回答1:

Asside from removing the files from the root, if you are running apache, you can change your .htaccess (I'm sure windows-based system have a web.config equivalent) to forbid access to certain files directly. If you add this snippet to that file, it will deny files with .pdf extension:

<FilesMatch "\.(pdf)$">
Order Allow,Deny
Deny from all
</FilesMatch>

From there, inside your app, you can create some sort of system for curating your PDF links, so if you store the real path in a database and use the id as the link similar to:

http://www.example.com/?file=1

or if you just do a simple scan:

<?php
# The folder that the PDFs are in
$dir = __DIR__.'/website/folder/';
# Loop over a scan of the directory (you can also use glob() here)
foreach(scandir($dir) as $file):
    # If file, create a link
    if(is_file($dir.$file)): ?>
<a href="?action=download&file=<?php echo $file ?>"><?php echo $file ?></a>
<?php
    endif;
endforeach;

Then, if the user tries to download using the link, you check they are first logged in and if they are, download the file by doing a script like so BEFORE you output anything else to the browser (including spaces):

<?php
session_start();
# First check that the user is logged in
if(empty($_SESSION['username']))
    die('You must be logged in to download this document.');
# Not sure which directory you are currently in, so I will assume root
# I would do basename() here incase the user tries to add in something like:
# ../index.php and tries to download files they are not supposed to
$file = __DIR__.'/website/folder/'.basename($_GET['file']);
if(!is_file($file))
    die('File does not exist.');
# Double check that the file is a pdf
elseif(strtolower(pathinfo($file, PATHINFO_EXTENSION)) != 'pdf')
    die('File appears to be invalid.');
# Start download headers
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;