问题(请参阅下面的详细解释和我已经尝试过的东西):
有没有一种方法可以获得短URLhttp://example.com/qf56p9z重定向到在表单/files/qf56p9z_(.*)
的服务器上找到的第一个文件,并将其下载到文件名为(.*)
的客户端上(如果可能,没有PHP)
背景:
我在服务器上有一个存储在/files/qf56p9z_blahblah.xls
中的文件,我希望可以从这个简短的URL访问:
http://example.com/qf56p9z
(+其他数千个文件相同)
此外,我希望当用户转到该URL时,该文件将以原始文件名下载到客户端计算机上,即blahblah.xls
。
这可能与PHP有关,我尝试了以下方法(这可以很容易地为我的数千个文件中的每一个自动化):
<?php
header('Content-type: ...');
header('Content-Disposition: attachment; filename="blahblah.xls"');
readfile('qf56p9z_blahblah.xls');
?>
但我发现这种方法有两个问题:
对于客户端每次读取文件,PHP都必须将整个文件加载到内存中,并输出新文件。这比apache只发送文件而不发送PHP 要消耗更多的CPU/内存
如果有一天我在其他地方托管所有这些文件(例如在AmazonS3上),该文件将不得不执行以下路径:
Distant-Hosting (AmazonS3) ==> my server/header modified with PHP ==> client
遗憾的是,数据必须这样做,而不是:
Distant-Hosting (AmazonS3) ==> client
您可以组合使用PHP和.htaccess(使用mod_rewrite)
场地结构
-
/var/www/html/files/
:包含文件的目录{prefix}_{filename}
格式 -
/var/www/html/download.php
:定位具有给定前缀的第一个文件的PHP脚本 -
/var/www/html/.htaccess
:具有2个用于重写下载URL的mod_rewrite规则
download.php
<?PHP
$files_dir = "files/";
if(isset($_GET['prefix'])){
$files = glob($files_dir.$_GET['prefix']."_*");
if(count($files) > 0) {
$dl = strlen($files_dir);
$pl = strlen($_GET['prefix']);
$fn = substr($files[0], $dl+$pl+1);
header("Location: d/".$_GET['prefix']."/".$fn);
}
}
?>
这会选择具有所需前缀的第一个文件并重定向到它
.htaccess
RewriteEngine On
RewriteRule ^('w+)$ download.php?prefix=$1 [L]
RewriteRule ^d/(.+)/(.+)$ files/$1_$2 [L]
第一条规则将短URL重写为download.php,第二条规则将URL重写为原始文件位置。
这就是它的工作方式
- http://example.com/qf56p9z--.htaccess->http://example.com/download.php?prefix=qf56p9z
- download.php--php重定向-->http://example.com/d/qf56p9z/blahblah.xls
- http://example.com/d/qf56p9z/blahblah.xls-->.htaccess-->http://example.com/files/qf56p9z_blahblah.xls
在以上所有步骤中,浏览器的位置栏URL保持不变。