使用php和jQuery允许经过身份验证的用户在apache的webroot目录下下载文件

时间:2015-03-04 09:36:33

标签: php jquery file security download

这个问题的变化似乎在网上徘徊不少,但是我还没有找到一个似乎可行和全面的解决方案,足以给我一个关于该做什么的体面线索。因此,我将在这里给它一个镜头并发布,尽可能具体。

我正在开发一个简单的Web应用程序,允许一组受限用户在进行身份验证后从网站下载文件。包含mySQL后端的身份验证部分很容易实现并且工作正常。 为了将目录结构提供给客户端,我决定使用易于使用且工作正常的jqueryfiletree(https://github.com/daverogers/jQueryFileTree)。 出于测试目的,我简单地将文件名传递给客户端,然后允许它下载他们单击的文件。这是设置目录树结构并允许用户下载文件的代码:

$('#fileTreeObj').fileTree({ 
    root:'../filestore/',
    script: 'connectors/jqueryFileTree.php', 
    folderEvent: 'click', 
    expandSpeed: 500, 
    collapseSpeed: 500, 
    expandEasing: 'easeOutBounce', 
    collapseEasing: 'easeOutBounce', 
    loadMessage: 'Loading contents...' }, 
    function(file) { 
        openFile(file);
});

当然,只有文件位于apache的webroot内部或外部世界可直接访问的其他位置时,此功能才有效。 限制从该目录结构下载任何文件的唯一可行方法是将文件放在webroot之外,然后将filetree指向该位置 - 这将导致客户端尝试下载文件时出现http 404错误:

将文件树对象更改为

.
.
root:'/var/filestore/',
.
.

结果

"The requested URL /var/filestore/afile.txt was not found on this server."

这是有道理的,因为jquery脚本只提供文件位置,然后由客户端请求。

我想要实现的目标如下:

  • 将可下载文件放在apache的webroot
  • 之外的目录中
  • 添加允许从那里下载文件的功能
    • 不允许任何未经过身份验证的用户下载任何文件

使用符号链接或别名不是一种选择,因为这会破坏整个身份验证概念。任何未经过身份验证的用户都可以下载整个目录结构,前提是他或她知道文件名。 我有一个线索,我无法完全依赖于jQuery,并且我必须添加一个PHP脚本来将文件传递给客户端。缩小需要实现的目标,我想知道:

  • php函数/脚本如何看起来像

    • 从网络服务器上的非webroot目录中读取任何给定类型和大小的文件
    • 将文件传回客户端以供下载
  • 我如何将这个与我的jQuery filetree结合在一起? (我如何从那里调用php脚本,如何将其传递给客户端?)

请注意,我还没有使用jQuery和php做很多工作,所以我想为这个可能微不足道的问题道歉。任何帮助和代码片段都非常感谢。

感谢亲爱的社区!


编辑:经过一些进一步的研究后,我发现了post这个优秀的Chris,它帮助我创建了一个PHP脚本来处理从webroot外部检索文件。 不过,我仍然在努力调用脚本并返回文件。我按照以下方式设置:

服务器端 - PHP脚本(getFile.php)

<?php

$filename = $_POST['fbpath'];
$path = '/var/filestore/' . $filename;

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($path));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($path));
ob_clean();
flush();
readfile($path);
exit;

?>

客户端 - jQuery集成

$('#fileTreeObj').fileTree({ 
        root: '/var/filestore/', 
        script: 'connectors/jqueryFileTree.php', 
        folderEvent: 'click', 
        expandSpeed: 500, 
        collapseSpeed: 500, 
        expandEasing: 'easeOutBounce', 
        collapseEasing: 'easeOutBounce', 
        loadMessage: 'Loading contents...' }, 
        function(file) { 
                $.ajax({
                type:"GET",
                url:"getFile.php",
                data:{fbpath: file},
                success: function(response){
                            openFile(response);
                    }


    });
});

通过单击选择要下载的文件时,出现以下错误:

GET https://www.myserver.com/ftree/getFile.php?fbpath=%2Fvar%2Ffilestore%2Ffile1.txt net::ERR_CONTENT_LENGTH_MISMATCH

我可能错误地处理了PHP输出,因此我的问题是:

  • 适当的AJAX调用如何看起来像?我做错了什么?
  • 为了允许下载文件,需要如何更改呼叫?

非常感谢大家。

  • 麦克

1 个答案:

答案 0 :(得分:0)

好的,经过一些更多的研究和大量的反复试验,我得到了这个,现在代码看起来像这样:

客户端(jQuery / AJAX)

function(file) { 

        $.ajax({
        type:"POST",
        url:"getFile.php",
        data:{fbpath: file},
        success: function(data, textStatus, XMLHttpRequest) {
            var popup = window.open();
                popup.document.write(data);
        }

        });
});

服务器端(getFile.php)

<?php

$filename = $_POST['fbpath'];
$path = $filename;

header('Content-Description: File Transfer');
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename='.basename($path));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($path));
ob_clean();
flush();
readfile($path);
exit;

?>

在浏览器中,用户将获得一个包含文件内容的弹出窗口。 这仍然不是一个非常漂亮的解决方案:用户不会得到一个很好的下载提示,因此他在新的浏览器选项卡中面对二进制数据。不完全是我所希望的,而且最重要的是,这很丑陋!

更多阅读文章显示,jQuery / AJAX需要更多处理来提供用户友好的文件下载。似乎John Culviner前一段时间遇到过这个问题(&#34;您当然可以使用XMLHttpRequest对象来下载二进制(或其他)文件,但是对于某些方式的响应您无能为力将它保存在用户的计算机上。&#34; )并为此提供了一个方便的解决方案。

在将文件从安全位置取出并将其发送到客户端浏览器方面,我认为这个问题已得到解答。

我希望将来可以帮助其他人!

迈克