繁体   English   中英

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

[英]Allow a PHP script access to PDFs in a folder - but prevent direct URL references

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

问题是每个 PDF 也可以通过使用直接 URL 查询(即网站/文件夹/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>*

除了从根目录中删除文件之外,如果您正在运行 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;

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

在行动中这是这样工作的

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:导入文件includer PHP页面

(文件下载器.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 页面,即第二个页面,如果没有设置正确的 cookie,则该页面会显示为die() 该 cookie 仅在您需要时设置。 在您的页面上。 当然,您也可以在 JavaScript 中执行此操作,但这会暴露 cookie,但对于大多数未经授权的共享,它仍然会处理它。

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

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

<?php
    header("Location: http://yoursite.com/some-other-page/"); /* Redirect browser here */
?>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM