【问题标题】:PHP, X-SendFile: Sending file together with outputting text to the browser (via echo)PHP,X-SendFile:将文件与输出文本一起发送到浏览器(通过回显)
【发布时间】:2013-11-27 16:03:38
【问题描述】:

我使用X-SendFile Apache Module 从服务器下载大文件。下载运行良好。但是,当下载开始时,我需要向浏览器输出一些文本,例如:“Thanks for download the file....”

我的问题是,我不能在一个脚本中同时完成这两项工作。我可以下载文件,然后没有文本输出到屏幕上。或者,我可以将文本输出到屏幕,但下载脚本不会启动。

如何在一个 php 脚本中完成这两项任务 - 下载文件并将文本内容发送到浏览器/网页? 问题可能源于 HTTP 输出标头,但我不知道如何解决它。

这是我用来通过 X-SendFile 下载文件的示例代码(独立工作):

                header('Content-Description: File Transfer');
                header("Content-Disposition: attachment; filename=\"". basename($filePath) . "\"");
                header('Content-Transfer-Encoding: binary');
                header('Expires: 0');
                header('Cache-Control: no-store, no-cache, must-revalidate');
                header('Pragma: no-cache');
                header('Content-Length: ' . filesize($filePath));
                header("X-Sendfile: $filePath");

为了完成,这是我的测试echo"" 字符串。如果它放在 X-Sendfile 代码之上,它会得到输出,但不会开始下载。如果将其放在 X-Sendfile 代码下方,则会下载文件,但不会向浏览器回显:

echo "SUCCESS!!!";
ob_flush();

约束:

我需要能够通过 URL 轻松下载文件。例如,www.mydomain.com/?fileID=asl523n53twteHLfga。也就是说,PHP 下载脚本在index.php 内。当用户输入www.mydomain.com 时,将显示域登录页面。但是,当传递了额外的$_GET 变量时,PHP 脚本会识别出这一点,并且应该显示感谢您下载...而不是登录页面。

欢迎提供解决方法。重要的是在保持上述约束的同时达到预期的结果。非常感谢你。

【问题讨论】:

  • 不可能。大多数浏览器根本不支持(或很好地支持)HTTP 多部分。响应通常由一个数据流组成。大多数人通过弹出一个包含谢谢的中间页面来解决问题,然后是指向实际下载链接的元刷新。
  • 马克 B,感谢您的回答。我明白你的意思。这是一个可行的解决方案。我会等待收集更多的回复,如果没有更好的结果,我会朝着你指出的方向前进。谢谢和 +1。

标签: javascript php html x-sendfile


【解决方案1】:

如何添加一个单独的下载页面来下载文件(即download.php?fileID=XYZ)并让您的索引页面显示如下消息:

<?php

function homeScreen() {
  // your home content
}

function downloadFileScreen ($id) {
?>
<h2>Thank you for your download!</h2>
Your download should start automatically, if it does not, click 
<a href="download.php?fileID=<?php print $id; ?>">here</a>
<script type="text/javascript">
window.setTimeout('location.href="download.php?fileID=<?php print $id; ?>"',3000);
</script>
<?php
}

if (isset($_GET['fileID'])) {
  $id= $_GET['fileID'];
  downloadFileScreen ($id);
?>
} else {
  // no ID passed, show home screen
  homeScreen();
}
?>

我还没有听说任何浏览器支持在单个请求中同时显示下载和 HTTP 内容显示,但我会看看是否可以使用 ob_start()ob_flush() 来实现。

【讨论】:

  • 嗨,Sascha,我已经实施了您的解决方案(以适合我的方式)并且效果很好。让我感谢您的回答,并将其标记为已接受的答案。谢谢。
  • 非常感谢,很高兴它可以帮助您入门!
【解决方案2】:

有解决方法。您可以在其中创建下载文件的 iframe。详情见代码。

感谢页面:(例如 www.mydomain.com/?fileID=asl523n53twteHLfga)

<p>Thank you!</p>
<?php
$fileID = $_REQUEST['fileID'];
// csrf code individual for visitor, so visitor can's send direct link to friend
$csrf = md5(uniqid(rand(), true));
$_SESSION['csrf'] = $csrf;
// with iframe file will be downloaded 'in background'
echo '<iframe src="downloadFile.php?fileID=' . urlencode($fileID) . '&csrf=' . urlencode($csrf) . '" width="0" height="0"></iframe>';
?>

downloadFile.php(例如 www.mydomain.com/downloadFile.php?fileID=asl523n53twteHLfga)

<?php
$fileID = $_REQUEST['fileID'];
if ($_REQUEST['csrf'] == $_SESSION['csrf'])
{
    // download file
    header('Content-Description: File Transfer');
    header("Content-Disposition: attachment; filename=\"". basename($filePath) . "\"");
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('Pragma: no-cache');
    header('Content-Length: ' . filesize($filePath));
    header("X-Sendfile: $filePath");
    die();
}
else
{
    // csrf from request not equal csrf saved in session, so probably this is direct link to file received from other user
    // redirect to 'thank you' page
    header('Location: /?fileID=' . urlencode($fileID));
    die();
}
?>

【讨论】:

  • 您好,感谢您的回复。您的答案包含很好的示例,我相信它会完美地工作。 Sascha 的上述解决方案是另一个很好的例子。我尝试了 Sascha 的解决方案,对我来说效果很好。由于我必须做出决定,我会将哪个答案标记为已接受的答案,我将为 Sascha 做出决定,因为我已经实际实施了他的回应。我会给你 +1 的小费。谢谢。
猜你喜欢
  • 2012-07-03
  • 1970-01-01
  • 2023-04-02
  • 2013-09-10
  • 1970-01-01
  • 2010-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多