使用 PHP 强制下载然后重定向

发布于 2024-10-31 07:28:17 字数 1227 浏览 0 评论 0原文

我知道这个问题以前已经被问过很多次了,但我找不到适合我需要的答案。

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

到目前为止,我已经:

<?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 链接。

显然我不能将重定向标头放在其他标头下方,因为它不起作用。除了在弹出窗口中打开它并将主窗口定向到“谢谢”页面之外,我真的不知道从这里该去哪里 - 但这是最​​后的手段。

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

干杯,

丰富

I know this question has been asked many times before but I can't find an answer to suit my needs.

I need to find a way to force the download of a file and then, after the download has started, redirect to a "thanks for downloading" page.

So far I have:

<?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();

?>

It's important to hide the download file's location otherwise I would have just created an HTML link to the file.

I obviously can't put a redirect header below the other headers as it just won't work. I can't really see where to go from here apart from opening this in a pop-up and directing the main window to the "thank you" page - but that is a LAST resort.

Can anyone give any suggestions?

Cheers,

Rich

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

恋你朝朝暮暮 2024-11-07 07:28:18
  1. 您无法隐藏文件位置。任何有决心找到它的人都可以清楚地看到它,因为浏览器需要知道下载文件的 URL。
  2. 正如您所说,您不能连续使用两个标头重定向来做到这一点。您只能在超时后使用 Javascript 重定向到不同的页面。

确实没有太多选择。如果您的主要目标是隐藏 URL,那么无论如何这都是失败的。为了获得良好的可用性,您通常会在页面上添加纯链接(“下载无法开始?单击此处...”),因为用户可能会意外取消在错误的时间进行重定向,从而不可挽回地终止下载。


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

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

请参阅 http://download.com 了解此操作的示例。

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

  1. You can't hide a file location. It'll be plainly visible to anybody determined enough to find it, by the very necessity that the browser needs to know the URL to download the file.
  2. You can't do it with two header redirects in succession, as you said. You can only redirect to a different page after some timeout using Javascript.

There really isn't much choice. If your primary goal is to hide the URL, that's a lost cause anyway. For good usability, you usually include the plain link on the page anyway ("Download doesn't start? Click here..."), since the user may accidentally cancel the redirect at just the wrong time to irrevocably kill the download.


You cannot output anything other than the file itself in the same request/response. You could try multi-part HTTP responses as suggested by @netcoder, but I'm not really sure how well that's supported. Just start with the assumption that there's one "wasted" request/response in which only the file is downloaded and nothing else happens. The way things usually work with this restriction is like this:

  • User clicks "download" link or submits form with his email address or whatever is required to initiate the download process.
  • Server returns the "Thank you for downloading from us! Your download will start shortly..." page.
  • This page contains Javascript or a <meta> refresh or HTTP Refresh header that causes a delayed redirect to the URL of the file.
  • The "Thank you" page will "redirect" to the file location, but since this causes the file to download, the page will not visibly change, only the download will be initiated.

Look at http://download.com for an example of this in action.

You can make the download location for the file be a script that only returns the file if the user is allowed to download the file. You can pass some temporary token between the "Thank you" page and the file download page to verify that the download is allowed.

司马昭之心 2024-11-07 07:28:18

我所知道的 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 重定向。

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

The only way in PHP I know of (to have a download, then to redirect) is to use a multi-part HTTP response. Something like that:

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();

In your case, you could just output the "Thanks for downloading" page content instead of the JavaScript redirect.

I'm unsure whether it works on all/major browsers or not.

隱形的亼 2024-11-07 07:28:18

好的,首先,浏览器需要知道文件位置才能下载它。任何打开 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-然后检查 download_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 在磁盘上读取数据时将其发送到浏览器,因此将使用更少的内存(并且将更快地开始发送数据)。

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

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

简而言之,文件下载后您不需要重定向,因为您已经位于感谢页面!我认为文件下载后甚至不可能重定向。只要看看当您单击指向网络服务器上的直接文件的链接时会发生什么。浏览器会提示下载,但不会中断您的导航。下载开始后,您可以愉快地点击链接离开页面。下载完成后,您可能会访问一个完全不同的网站。这就是为什么您之前只能显示感谢页面。但是,如果您为刷新标题/标签设置零,则页面加载后就会出现下载提示,因此几乎就像两者是同时发生的(在访问者看来)

Ok, first thing first, the browser need to know the file location to download it. Anyone opening a standard browser dev tool like Firebug will be able to see in plain text the URL of your file.

Now, I suppose you want to protect your file from unauthorised download. If that is what you want, there is a way for that using session.

On your first page, you will put your code to check if the download is authorized. You will then put in session the current with something that identify the file. Anything that is unique for the file will do, like the database id.

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

Then, you redirect to a page with a html meta like this

<meta http-equiv="refresh" content="5;/download.php?file=download_key" />

This is the page where you will say "Thank you fine lad for downloading my awesome file". Note that you can also put the content of the "content" attribute in a header file if you like, like this

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

Note that the 5 is the number of second until the download file dialog box appear.

Then on download.php you will do the following :

1- Check which file was requested using the $_GET['file'].

2- Then you check if the download_key exists in session. If not, you exit the script like that

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

3- Then you check if the timestamps is older than some arbitrary time limit. Here with 30 sec

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

4- Finally, if all check out, you send the file like that

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

After the readfile, you will put the code to set the download to 1 in the database.

And that's it, protected file download, and anybody using the URL directly will be greeted by a big "unauthorized" text.

I'd also like to add that if you have a big file (more than say a few kilobyte), you may be better off disabling output buffering, since that will mean that php will keep a copy of the file in memory for the whole duration of the download. With the readfile function, php will send it to the browser as it read it on the disk and thus will use less memory (and will start to send data sooner).

EDIT : What make it work is the following

I actually inverted the sequence : the visitor is first redirected to the thank you page which contain a Refresh header/tag. The magic of the Refresh header is that it redirect AFTER the content is loaded. Once on the thank you page, the browser seeing that header then wait for the specified time while showing the page, then redirect to the download. Once redirected, the browser see that its a file to be downloaded and instead of changing the page, just show the download file dialog. Once the user click OK, the download will start but he will stay on the same page.

In a nutshell, you don't need to redirect after the file download, since you are already on the thank you page! I don't think it's even possible to redirect after a file download. Just look at what happen when you click on a link that point to a direct file on the webserver. The browser prompt for download, but does not cut your navigation. Once the download is started, you can happily click away from the page with the link. By the time the download is over, you may be on a completely different Website. That is why you can only show the thank you page before. But if you put a zero for the refresh header/tag, the download prompt will appear as soon as the page is loaded, so it's almost as if the two were simultaneous (in the eye of the visitor)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文