使用 php 和 jQuery 允许经过身份验证的用户下载 apache 的 webroot 目录之外的文件
Using php and jQuery to allow authenticated users to download a file outside apache's webroot directory
这个问题的变体似乎在网络上闲逛了很多,但是我还没有找到一个看起来可行且足够全面的解决方案来给我一个关于该怎么做的体面线索。因此,我将试一试,post 此处尽可能具体。
我正在开发一个简单的 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 之外,然后将文件树指向该位置——每当客户端尝试下载文件时,这将导致 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 文件树放在一起? (我如何从那里调用 php 脚本以及如何将其传递给客户端?)
请注意,我还没有大量使用 jQuery 和 php,所以对于这个可能微不足道的问题,我深表歉意。非常感谢任何帮助和代码片段。
感谢亲爱的社区!
编辑:经过进一步研究,我发现了这个优秀的 post by Chris,它帮助我创建了一个 PHP 脚本来处理从外部检索文件根目录。
不过,我仍在努力调用脚本并返回文件。我按以下方式设置:
服务器端 - 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 调用应该是什么样子?我做错了什么?
- 需要如何更改调用才能下载文件?
非常感谢大家
- 麦克
好的,经过更多的研究和大量的试验和错误,我让它工作了,代码现在看起来像这样:
客户端 (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;
?>
在浏览器中,用户将看到一个包含文件内容的弹出窗口 window。
这仍然不是一个非常好的解决方案:用户不会得到一个很好的下载提示,因此他会在新的浏览器选项卡中面对二进制数据。不完全是我所希望的,最重要的是,它很丑!
更多阅读表明 jQuery/AJAX 需要更多处理才能提供用户友好的文件下载。似乎 John Culviner 不久前遇到了这个问题 ("You can certainly use an XMLHttpRequest object to download a binary (or otherwise) file but there is nothing you can do to the response to somehow get it saved on the user’s computer.") 并且对此有一个很好的方便的解决方法。
关于从安全位置获取文件并将其发送到客户端浏览器的问题,我认为这个问题已得到解答。
我希望这对以后的其他人有所帮助!
麦克
这个问题的变体似乎在网络上闲逛了很多,但是我还没有找到一个看起来可行且足够全面的解决方案来给我一个关于该怎么做的体面线索。因此,我将试一试,post 此处尽可能具体。
我正在开发一个简单的 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 之外,然后将文件树指向该位置——每当客户端尝试下载文件时,这将导致 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 文件树放在一起? (我如何从那里调用 php 脚本以及如何将其传递给客户端?)
请注意,我还没有大量使用 jQuery 和 php,所以对于这个可能微不足道的问题,我深表歉意。非常感谢任何帮助和代码片段。
感谢亲爱的社区!
编辑:经过进一步研究,我发现了这个优秀的 post by Chris,它帮助我创建了一个 PHP 脚本来处理从外部检索文件根目录。 不过,我仍在努力调用脚本并返回文件。我按以下方式设置:
服务器端 - 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 调用应该是什么样子?我做错了什么?
- 需要如何更改调用才能下载文件?
非常感谢大家
- 麦克
好的,经过更多的研究和大量的试验和错误,我让它工作了,代码现在看起来像这样:
客户端 (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;
?>
在浏览器中,用户将看到一个包含文件内容的弹出窗口 window。 这仍然不是一个非常好的解决方案:用户不会得到一个很好的下载提示,因此他会在新的浏览器选项卡中面对二进制数据。不完全是我所希望的,最重要的是,它很丑!
更多阅读表明 jQuery/AJAX 需要更多处理才能提供用户友好的文件下载。似乎 John Culviner 不久前遇到了这个问题 ("You can certainly use an XMLHttpRequest object to download a binary (or otherwise) file but there is nothing you can do to the response to somehow get it saved on the user’s computer.") 并且对此有一个很好的方便的解决方法。
关于从安全位置获取文件并将其发送到客户端浏览器的问题,我认为这个问题已得到解答。
我希望这对以后的其他人有所帮助!
麦克