使用原始文件名下载的带有短URL的文件


File with a short URL downloaded with original filename

问题(请参阅下面的详细解释和我已经尝试过的东西):

有没有一种方法可以获得短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重写为原始文件位置。

这就是它的工作方式

  1. http://example.com/qf56p9z--.htaccess->http://example.com/download.php?prefix=qf56p9z
  2. download.php--php重定向-->http://example.com/d/qf56p9z/blahblah.xls
  3. http://example.com/d/qf56p9z/blahblah.xls-->.htaccess-->http://example.com/files/qf56p9z_blahblah.xls

在以上所有步骤中,浏览器的位置栏URL保持不变。