用PHP强制下载然后重定向

时间:2011-04-07 01:23:05

标签: php redirect header download hide

我知道这个问题之前已被多次询问过,但我找不到符合我需要的答案。

我需要找到一种强制下载文件的方法,然后在下载开始后,重定向到“感谢下载”页面。

到目前为止,我有:

<?php
ob_start();

$token = $_POST['validationCode'];

if(isset($token)){

    $connect = mysql_connect('localhost', 'root', 'root');
    $db = mysql_select_db('mydb');

    if (!$connect || !$db){
        die('Connect Error (' . mysql_connect_errno() . ') '
                . mysql_connect_error());
    }

    $sql = mysql_query("SELECT * FROM emailaddresses WHERE token='$token'");
    $result = mysql_fetch_array($sql);
    if($result){
        header('Location: complete.php');
        header('Content-type: application/mp3');
        header('Content-Disposition: attachment; filename=track.mp3');
        $f = file_get_contents('downloads/track.mp3');
        print $f;
        $sql = "UPDATE emailaddresses SET download=1 WHERE token='$token'";
        $result = mysql_query($sql);
    }
    else{
        echo "There was a problem downloading the file" . mysql_error();
    }
}

ob_end_flush();

?>

隐藏下载文件的位置非常重要,否则我就会创建一个指向该文件的HTML链接。

我显然不能在其他标题下面放置重定向标题,因为它不起作用。除了在弹出窗口中打开并将主窗口指向“谢谢”页面之外,我无法真正看到从这里开始的地方 - 但这是最​​后的度假胜地。

任何人都可以提出任何建议吗?

干杯,

3 个答案:

答案 0 :(得分:5)

  1. 您无法隐藏文件位置。由于浏览器需要知道下载文件的URL的必要性,任何确定足以找到它的人都可以清楚地看到它。
  2. 如你所说,你不能连续两个标题重定向。您只能在使用Javascript超时后重定向到其他页面。
  3. 真的没有多少选择。如果您的主要目标是隐藏URL,那么无论如何这都是失败的原因。为了获得良好的可用性,您通常会在页面上包含纯链接(“下载无法启动?点击此处 ...”),因为用户可能会意外取消在错误的时间重定向以不可挽回地杀死下载。


    您不能在同一请求/响应中输出除文件本身以外的任何内容。您可以尝试@netcoder建议的多部分HTTP响应,但我不确定它的支持程度如何。首先假设有一个“浪费”的请求/响应,其中只下载文件而没有其他任何事情发生。通常使用此限制的方式如下:

    • 用户点击“下载”链接或使用他的电子邮件地址或启动下载过程所需的任何内容提交表单。
    • 服务器返回“感谢您从我们这里下载!您的下载将很快开始......”页。
    • 此页面包含Javascript或<meta>刷新或HTTP Refresh标头,导致延迟重定向到文件的网址。
    • “谢谢”页面将“重定向”到文件位置,但由于这会导致文件下载,因此页面不会明显更改,只会启动下载。

    请查看http://download.com以了解此操作的示例。

    如果允许用户下载文件,您可以将文件的下载位置设置为仅返回文件的脚本。您可以在“Thank you”页面和文件下载页面之间传递一些临时令牌,以验证是否允许下载。

答案 1 :(得分:1)

我所知道的PHP的唯一方法(下载,然后重定向)是使用多部分HTTP响应。这样的事情:

define('MP_BOUNDARY', '--'.sha1(microtime(true)));

header('Content-Type: multipart/x-mixed-replace; boundary="'.MP_BOUNDARY.'"');
flush();

echo "Content-Type: application/zip\r\n";
echo "Content-Disposition: attachment; filename=foo.zip\r\n";
echo "\r\n";
readfile('foo.zip');
echo MP_BOUNDARY;
flush();

echo "Content-Type: text/html\r\n";
echo "\r\n";
echo '<html><script type="text/javascript">location.href="http://www.google.ca";</script></html>';
echo MP_BOUNDARY.'--';
flush();

在您的情况下,您可以输出“感谢下载”页面内容而不是JavaScript重定向。

我不确定它是否适用于所有/主要浏览器。

答案 2 :(得分:1)

好的,首先,浏览器需要知道要下载的文件位置。任何打开像Firebug这样的标准浏览器开发工具的人都能够以纯文本格式查看文件的URL。

现在,我想您希望保护您的文件免遭未经授权的下载。如果这是您想要的,那么使用会话就有办法。

在您的第一页上,您将放置代码以检查下载是否已获得授权。然后,您将使用标识文件的内容放入当前会话。任何对文件唯一的东西都可以,比如数据库ID。

$_SESSION['download_key'] = time();

然后,您将重定向到具有此类

的html元的页面
<meta http-equiv="refresh" content="5;/download.php?file=download_key" />

这是您要说“谢谢你好下载我真棒文件”的页面。请注意,如果您愿意,也可以将“content”属性的内容放在头文件中,如此

header('Refresh: 5;/download.php?file=download_key');

请注意,5是下载文件对话框出现之前的秒数。

然后在download.php上,您将执行以下操作:

1-使用$ _GET ['file']检查请求了哪个文件。

2-然后检查session_key是否存在于会话中。如果没有,则退出脚本

if (!isset($_SESSION['download_key'])) die('Unauthorized');

3-然后检查时间戳是否早于某个任意时间限制。这里30秒

if ($_SESSION['download_key'] - time() > 30) die('Unauthorized');

4-最后,如果全部结账,则发送文件

header('Content-disposition: attachment; filename=myfile.ext');
header('Content-type: bin/x-file-type'); //Change for the correct mimetype
readfile('myfile.ext');

在readfile之后,您将把代码设置为在数据库中将下载设置为1.

就是这样,受保护的文件下载,任何直接使用URL的人都会受到大量“未经授权”的文本的欢迎。

我还想补充一点,如果你有一个大文件(超过几千字节),你可能最好禁用输出缓冲,因为这意味着php会在内存中保留一份文件在整个下载期间。使用readfile函数,php会将它发送到浏览器,因为它在磁盘上读取它,因此将使用更少的内存(并将开始更快地发送数据)。

编辑:使它起作用的是以下

我实际上颠倒了序列:访问者首先被重定向到包含Refresh标头/标签的感谢页面。 Refresh标头的神奇之处在于它在加载内容后重定向。在感谢页面上,浏览器看到该标题然后在显示页面时等待指定的时间,然后重定向到下载。重定向后,浏览器会看到要下载的文件,而不是更改页面,只显示下载文件对话框。一旦用户单击“确定”,下载将开始,但他将保持在同一页面上。

简而言之,您不需要在文件下载后重定向,因为您已经在感谢页面上了!我认为甚至不可能在文件下载后重定向。只需看一下当您点击指向Web服务器上的直接文件的链接时会发生什么。浏览器提示下载,但不会削减您的导航。下载开始后,您可以通过链接高兴地点击页面。下载结束时,您可能在一个完全不同的网站上。这就是为什么你之前只能显示感谢页面的原因。但是如果你为刷新标题/标记添加零,则一旦加载页面就会出现下载提示,因此几乎就好像这两个是同时的(在访问者的眼中)