如何在不给文件直接http访问的情况下在网站上提供可下载的发票?

时间:2014-01-16 04:26:44

标签: php mysql security download

正如标题所暗示的那样。我想让用户可以选择下载过去购买的发票。我不想存储这些文件,以便通过http轻松访问它们,例如http://www.site.com/inv/567.pdf

我已经考虑过这样做的一种方法,但我不认为这是最佳解决方案。

所以从本质上讲,我的服务器上有一个文件夹,在公共根目录下,在这个文件夹中,每个文件夹都有一个与客户帐户ID(MySQL行ID)相关的唯一ID。在每个文件夹中,我都可以存储与每个客户相关的发票或(.pdf文件)。

我可以在管理员的CMS中构建一个部分,用于处理将这些文件上传到各种用户帐户。

对于客户,当他们点击任何特定发票的下载按钮时,服务器会将发票复制到公共根目录中的临时目录,但在此过程中将其重命名为一些模糊的哈希值。然后将标题定向到此位置。

然后我可以运行一个cron作业来每隔x个时间清除一个临时文件夹。

鉴于我之前从未真正尝试完成此任务,我认为最好就此提出任何建议/反馈/建议或意见,因为我相信你们会对如何做出一些好主意这样做。提前感谢您提供的任何帮助!

4 个答案:

答案 0 :(得分:3)

您必须在网页脚本页面download_invoice.php中实施该流程。

  1. 提供download_invoice.php的链接。
  2. 表单查询字符串参数以传递到该页面 2.1。查询字符串可能类似于:?invoice_id=24&prod_id=63
  3. 为下载页面生成代码:
    3.1。读取查询参数 3.2。进程访问认证 3.3。失败时重定向到403页 3.4。继续成功。
    3.5。生成PDF文件的内容以下载并存储到字节缓冲区中 3.6。设置响应标头,如附件和内容类型 3.7。刷新对客户端的响应。
  4. 在客户端上,将提示用户存储文件,或者内容类型的关联应用程序将打开下载的文件。

    另请参阅类似的帖子:
         How to make PDF file downloadable in HTML link?

答案 1 :(得分:0)

我已经处理过这种情况并以两种不同的方式处理它。

1)Base64对pdf进行编码并将其存储在数据库中。 2)将pdf移动到Web服务器目录结构之外的另一个目录。您当然可以使用cron作业来完成此任务。如果用户将来需要pdf,那么您需要一个系统来移回文件。

我建议对pdf进行base64编码并将其存储在数据库中。

你写了以下内容: http://www.site.com/inv/567.pdf

我希望这不是敏感数据,因为每个人都可以访问存储为链接节目的pdf(即没有身份验证才能看到pdf)。

答案 2 :(得分:0)

如果要生成pdf并将其保留在root之外,则可以使用readfile()来传递文件,并具有基于文件名传递哈希的函数以防止URL黑客攻击。例如:

<?php
function getFile( $file, $hv){
    // prevent url hacking - $hv is passed as the valid hash based on the filename
    // it is double checked here
    // create a gethash() function and use your choice of hashing e.g. md5, base64 encoding, etc. to generate the hash
    $hash = gethash(basename($file));

    // if hash correct 
    if ($hv == $hash) {      

        // File Exists?
        if (file_exists($file)){
            // Parse Info / Get Extension
            $fsize = filesize($file);
            $path_parts = pathinfo($file);
            $ext = strtolower($path_parts["extension"]);

            // Determine Content Type
            switch ($ext) {
                case "pdf": $ctype="application/pdf"; break;
                case "exe": $ctype="application/octet-stream"; break;
                case "zip": $ctype="application/zip"; break;
                case "doc": $ctype="application/msword"; break;
                case "xls": $ctype="application/vnd.ms-excel"; break;
                case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
                case "gif": $ctype="image/gif"; break;
                case "png": $ctype="image/png"; break;
                case "jpeg":
                case "jpg": $ctype="image/jpg"; break;
                default: $ctype="application/force-download";
            }
            header("Pragma: public"); // required
            header("Expires: 0");
            header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
            header("Cache-Control: private",false); // required for certain browsers
            header("Content-Type: $ctype");
            // Download file
            header('Content-Disposition: attachment; filename='.basename($file));
            header("Content-Transfer-Encoding: binary");
            header("Content-Length: ".$fsize);

            if (ob_get_length() > 0 ) {
             //ob_end_clean();
             ob_clean();
             flush();
            }
            readfile( $file);
        } 
        else {
            echo('File Not Found: ' . $file);
        }
    }
    else {
        echo ('Invalid file request');
    }
} 
?>

答案 3 :(得分:0)

将pdf移动到无法通过浏览器访问的位置,例如/path/to/pdf/doc.pdf 然后有一个script.php:

//check if he has access
if ($has_access) {

   $id = $_GET['id'] + 0; //just numbers
   $file = '/path/to/pdf/'.$id.'.pdf'; 

   if (!file_exists($file)) die('cant find it');

   header('Content-type: application/pdf');
   header("Content-Disposition: attachment; filename=\"what_the_user_will see.pdf\"");

   $fp = fopen($file, 'r');

   while(!feof($fp)) {
echo fread($fp, 4096);
    flush();
   }
fclose($fp);

}

并链接到它

<a href="download.php?id=567">download</a>