首页 > 解决方案 > 是否可以从 PHP 文件发送标头,这完全没有任何作用

问题描述

在我提供音乐样本下载的页面上,我有几个<a>标签,其 href 指向 PHP 文件。作为 GET 变量包含的各种数据允许下载正确的文件。通常,PHP 会以典型的下载标头响应,然后是 readfile()。(代码如下,仅供参考)。这会导致干净的下载(或某些浏览器上的下载/播放对话框)。通过“干净”,我的意思是下载完成,访问者页面没有干扰。

但是,万一请求的文件不可用,我不知道该怎么办。我知道它不应该发生,但如果发生了,我希望下载链接什么也不做。不幸的是,因为它是一个<a>引用 PHP 文件的标签,所以什么都不做会导致浏览器清除页面,并在地址栏中显示 PHP 文件的 URL。游客体验不好!因此,如果有错误的请求,我想避免干扰页面并且什么都不做。我将使用 javascript 来提醒访问者出了什么问题,但我不能让错误的文件请求清除页面!

我以为我已经通过发出 header('Location: #'); 找到了解决方案。当脚本检测到不可能的文件下载时。但几秒钟后,浏览器清除了该页面并显示一条消息,指出该页面“重定向您太​​多次”。(事实上​​,我的脚本日志中有 100 多个条目,尽管我只单击了一次标签。)

到目前为止,我唯一可行的解​​决方案(如果请求“不可用”文件,则不会干扰访问者页面)是将我的下载标题指向“虚拟”文件。一个实际的“silence.mp3”或“nosong.mp3”文件。但是有没有办法调用一个对调用页面没有任何作用的 header() ?简单地调用 exit 或 exit() 将不起作用(访问者页面被重定向为空白。)

没关系,但这是我通常为响应​​ d/l 请求而调用的代码......

function downloadFile($path) {
    $path_parts = pathinfo($path);
    $ext = strtolower($path_parts["extension"]); // don't need this.
    $fsize =fileExists($path);
    if ($fsize == 0) 
        {
         header('Location: #'); // this doesn't work!!! (too many redirectcts)
         exit;
         }

    //$dlname = $path_parts['filename'] . "." . strtolower($path_parts["extension"]);


    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header("Content-Disposition: filename=\"" . $path_parts["basename"]."\"");
    header("Content-Type: application/x-file-to-save");
    header("Content-Transfer-Encoding: binary");
    if($fsize) header("Content-length: $fsize");
    $bytesRead = readfile($path);
    return $bytesRead;
    }   

标签: phprequest-headers

解决方案


如果您使用带有标准锚标记的 HTTP/1.x,没有 JavaScript 或其他客户端拦截。当单击返回 204 状态标头的HTTP/1.0 204 No Content链接时,状态标头将导致用户代理看起来像没有发生任何事情。

HTTP/1.0 204 No Content
服务器已完成请求,但没有新信息要发回。如果客户端是用户代理,它不应该改变 导致请求生成的文档视图。这个响应主要是为了允许脚本的输入或其他动作发生,而不会导致用户代理的 活动文档视图发生变化。响应可能包含实体标题形式的新元信息,它应该应用于当前在用户代理的活动视图中的文档。
来源:https ://www.w3.org/Protocols/HTTP/1.0/spec.html#Code204

这也与HTTP/1.1协议兼容。

我建议使用输出缓冲来确保您的应用程序不会错误地发送其他内容。此外,应该不需要发送Content-Length标头。

function downloadFile($path) {
    if (!is_file($path) || !($fsize = filesize($path))) {
        header('HTTP/1.0 204 No Content');
        exit;
    }
    $path_parts = pathinfo($path);
    header('Cache-Control: public');
    header('Content-Description: File Transfer');
    header('Content-Disposition: filename="' . $path_parts['basename'] . '"');
    header('Content-Type: application/x-file-to-save');
    header('Content-Transfer-Encoding: binary');
    header('Content-length: ' . $fsize); //fsize already validated above.

    return readfile($path);
}

推荐阅读