允许PHP脚本访问文件夹中的PDF-但阻止直接URL引用

时间:2018-11-05 23:10:33

标签: php pdf permissions cpanel

在使用CPanel的godaddy托管网站上,我有一个小的PHP脚本,该脚本显示服务器上文本文件中的每一行。每行都包含一个私有的href链接,指向只有登录用户才能看到的PDF。这些链接指向服务器上同一文件夹中的各种PDF。该代码工作正常,我可以单击链接并查看每个PDF。

问题在于,每个PDF也可以通过使用直接URL查询(即website / folder / pdfname.pdf)查看。因为这些是私人PDF,所以我不希望它们公开。我尝试将文件夹的CPanel权限更改为“所有者”-但这似乎阻止了PHP脚本也打开PDF。

是否有一种方法可以允许PHP脚本访问文件夹中的PDF,但是可以防止直接URL引用?

注意:我不是特别擅长PHP或CPanel-抱歉。

代码...

$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);

文件内容...

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>*

2 个答案:

答案 0 :(得分:0)

除了从根目录删除文件以外,如果您正在运行apache,还可以更改.htaccess (我确定基于Windows的系统具有与web.config等效的功能)禁止直接访问某些文件。如果将此代码段添加到该文件,它将拒绝扩展名为.pdf的文件:

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

从那里,在您的应用程序内部,您可以创建某种系统来管理PDF链接,因此,如果您将真实路径存储在数据库中,并使用id作为链接,则类似于:

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

或者如果您只是进行简单扫描:

<?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;

然后,如果用户尝试使用链接进行下载,则检查他们是否首先登录,如果已经登录,则通过执行类似的脚本来下载文件,然后再将其他任何内容输出到浏览器(包括空格) )

<?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;

答案 1 :(得分:0)

一个更简单和基本的例子(以及上一个答案的衍生)是使用两个单独的 PHP 文件,其中一个是在点击链接时在浏览器中评估设置的 cookie(设置为即将过期)(通过 JS 或 PHP 或其他方式设置)。如果 cookie 被正确读取,第一个 PHP 页面会导入第二个页面,该页面利用 PHP header() 重定向包含您的原始文件名用另一个名称强制下载。使用 Content Disposition 标头字段。

实际操作是这样的

1:带有下载链接的原始页面 - 我们将 cookie 设置为工作 2 分钟

<a onclick="setCookie(1, 1, 2, 60)" href="php-secure-files-delivery-page.php">Download My Final PDF name.pdf</a>

<script type="text/javascript">

    // set a cookie with your own time limits.
    function setCookie(days, hours, minutes, seconds) { // Create cookie
        var expires;
        var date = new Date();
        date.setTime(date.getTime()+(days*hours*minutes*seconds*1000));
        expires = "; expires="+date.toGMTString();
        document.cookie = "my_cookie_name"+"="+"my_cookie_value"+expires+"; path=/";
    }

</script>

在链接页面上,我们包含一个带有评估 PHP 页面的超链接。在这里,我们使用 JavaScript 使用自定义函数 setCookie(days, hours, minutes, seconds) 设置 cookie,它将接收您的到期愿望。请注意,1 是最小数量。不是0

2:下载页面 - 评估 cookie 和呈现文本,或者只是下载文件

(php-secure-files-delivery-page.php)

<?php

// if the cookie is set correctly, load the file downloader page.

if (isset($_COOKIE['my_cookie_name'] && $_COOKIE['my_cookie_name'] === 'my_cookie_value')) {

    require_once 'file-downloader.php'; // the file will force the download upon import.

} else {
    
    die('The link expired, go to your downloads section and click on the link again.');
}

?>

在这里我们评估 cookie,显示正确的信息或 die()。使用 require_once 我们将 PHP 页面转换为当前页面。

3:导入的文件包含器 PHP 页面

(file-downloader.php)

<?php

// We'll be outputting a PDF
header('Content-Type: application/pdf');

// It will be downloaded as your-downloaded.pdf
header('Content-Disposition: attachment; filename="your-downloaded.pdf"');

// The PDF source is in your own specified long name
readfile('original-with-really-weird-original-name.pdf');

?>

结果

  • 用户总是转到同一页面,并看到相应的信息。
  • 您可以随意命名服务器上的原始文件,例如“my_really_difficult_and_long_file_name.pdf”,而用户在下载文件时只能看到漂亮的文件名。
  • 对于更多文件,请在 cookie 函数中使用额外的输入来获取文件名,并在 php 下载器页面中使用一些 if 语句,用于查找单独的 PHP 页面到 require_once
  • 如果您转到浏览器的“下载”部分以尝试获取已下载文件的 url,您会看到启动 PHP 页面,即第二个页面,该页面让您空白并带有 {{ 1}} 如果没有设置正确的 cookie。该 cookie 仅在您需要时设置。在您的页面上。当然,您也可以在 JavaScript 中执行此操作,但这会暴露 cookie,但对于大多数未经授权的共享,它仍然会处理它。

最后,轻松保护您的文件夹(没有 Apache/Nginx/.htaccess 的东西)

在服务器上的本地文件夹或指令中使用 .htaccess 文件是最好和最安全的方式。但这不能转移到其他系统上的其他应用程序。而是在您的 PDF 文件的父文件夹上使用 die()index.php 页面(它们所在的位置),包括此标题重定向以消除不需要的访问:

default.php