x-sendfile 让PHP实现更快的文件下载

X-Sendfile 是一种将文件下载请求由后端应用转交给前端 web 服务器处理的机制,它可以消除后端程序既要读文件又要处理发送的压力,从而显著提高服务器效率,特别是处理大文件下载的情形下。

X-Sendfile 通过一个特定的 HTTP header 来实现:在 X-Sendfile 头中指定一个文件的地址来通告前端 web 服务器。当 web 服务器检测到后端发送的这个 header 后,它将忽略后端的其他输出,而使用自身的组件(包括 缓存头 和 断点重连 等优化)机制将文件发送给用户。

不过,在使用 X-Sendfile 之前,我们必须明白这并不是一个标准特性,在默认情况下它是被大多数 web 服务器禁用的。而不同的 web 服务器的实现也不一样,包括规定了不同的 X-Sendfile 头格式。如果配置失当,用户可能下载到 0 字节的文件。

使用 X-Sendfile 将允许下载非 web 目录中的文件(例如/root/),即使文件在 .htaccess 保护下禁止访问,也会被下载。

不同的 web 服务器实现了不同的 HTTP 头

SENDFILE 头 使用的 WEB 器
X-Sendfile Apache, Lighttpd v1.5, Cherokee
X-LIGHTTPD-send-file Lighttpd v1.4
X-Accel-Redirect Nginx, Cherokee

使用 X-SendFile 的缺点是你失去了对文件传输机制的控制。例如如果你希望在完成文件下载后执行某些操作,比如只允许用户下载文件一次,这个 X-Sendfile 是没法做到的,因为后台的 php 脚本并不知道下载是否成功。

Apache 请参考mod_xsendfile模块。下面我介绍 Nginx 的用法。

Nginx 默认支持该特性,不需要加载额外的模块。只是实现有些不同,需要发送的 HTTP 头为 X-Accel-Redirect。另外,需要在配置文件中做以下设定

location /download/ {
 internal;
 root  /some/path;
}

在这里插入图片描述
表示这个路径只能在 Nginx 内部访问,不能用浏览器直接访问防止未授权的下载。
于是 PHP 发送 X-Accel-Redirect 给 Nginx:


function downloadFile($name)
{
    if(true) //有下载权限
    {
        $filePath = "/download/$name"; //注意这个路径跟上面nginx的配置
        header('Content-type: application/octet-stream');//告诉浏览器这是一个文件
        header('Content-Disposition: attachment; filename="'.$name.'"');//文件描述,页面下载用的文件名,可以实现用不同的文件名下载同一个文件
        header("X-Accel-Redirect:  $filePath");
    }
    else {
        echo "无下载权限";
    }
}

$file = 'iso.jpg';
downloadFile($file);

这样用户就会下载到 /some/path/download/iso.jpg 这个路径下的文件。
如果你想发送的是 /some/path/iso.img 文件,那么 Nginx 配置应该是

location /download/ {
 internal;
 alias  /some/path/; # 注意最後的斜杠
}

猜你喜欢

转载自blog.csdn.net/qq_40339262/article/details/87456621