是否可以从 PHP 文件发送 header,这绝对什么都不做

Is it possible to send a header from a PHP file, that does absolutely nothing

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

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

我想我已经通过发出 header('Location: #') 找到了解决方案;当脚本检测到无法下载文件时。但几秒钟后,浏览器清除了页面并显示了一条消息,指示页面 "redirected you too many times."(事实上,我的脚本日志充满了 100 多个条目,即使我只单击了一次标签。)

到目前为止,我唯一可行的解​​决方案(在请求 "unavailable" 文件时不会打扰访问者页面的意义上是可行的)是将我的下载 headers 指向 "dummy" 文件。实际的 "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;
    }   

如果您使用带有标准锚标记的 HTTP/1.x,没有 JavaScript 或其他 client-side 拦截。 HTTP/1.0 204 No Content 状态 header 将导致 user-agent 在单击 link 和 returns 204 状态 header 时似乎什么都没发生。 =15=]

HTTP/1.0 204 No Content
The server has fulfilled the request but there is no new information to send back. If the client is a user agent, it should not change its document view from that which caused the request to be generated. This response is primarily intended to allow input for scripts or other actions to take place without causing a change to the user agent's active document view. The response may include new metainformation in the form of entity headers, which should apply to the document currently in the user agent's active view.
Source: https://www.w3.org/Protocols/HTTP/1.0/spec.html#Code204

这也与 HTTP/1.1 协议兼容。

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

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

在创建链接之前执行文件检查是最简单的方法。

如果我正确理解了您的请求,您有希望允许客户端下载的文件,以及指向下载特定文件的 PHP 脚本的链接。

你的实现的问题是,当文件为空时,PHP 脚本仍然必须加载和更改客户端页面的内容(从加载脚本的动作),这是 不正确的行为(正确的是根本不采取任何行动)。

由于您在主下载页面上使用标签,在文件丢失的情况下不更改页面内容的唯一方法是提前计算标签的内容。使用简单的 PHP 函数,您可以检查文件及其目录列表的内容,然后为存在的文件生成链接,为不存在的文件生成空白链接。

总的来说,我认为将检查文件是否存在的功能与实际将文件下载到客户端的功能分开是实现您想要的功能的唯一方法。