在PHP中使用X-SendFile头让文件下载更快


Posted in PHP onJune 01, 2014

一般来说, 我们可以通过直接让URL指向一个位于Document Root下面的文件, 来引导用户下载文件.

但是, 这样做, 就没办法做一些统计, 权限检查, 等等的工作. 于是, 很多时候, 我们采用让PHP来做转发, 为用户提供文件下载.

<?php
    $file = "/tmp/dummy.tar.gz";
    header("Content-type: application/octet-stream");
    header('Content-Disposition: attachment; filename="' . basename($file) . '"');
    header("Content-Length: ". filesize($file));
    readfile($file);

但是这个有一个问题, 就是如果文件是中文名的话, 有的用户可能下载后的文件名是乱码.

于是, 我们做一下修改:

<?php
    $file = "/tmp/中文名.tar.gz";    $filename = basename($file);
    header("Content-type: application/octet-stream");
    //处理中文文件名
    $ua = $_SERVER["HTTP_USER_AGENT"];
    $encoded_filename = rawurlencode($filename);
    if (preg_match("/MSIE/", $ua)) {
     header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
    } else if (preg_match("/Firefox/", $ua)) {
     header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
    } else {
     header('Content-Disposition: attachment; filename="' . $filename . '"');
    }
    header("Content-Length: ". filesize($file));
    readfile($file);

恩, 现在看起来好多了, 不过还有一个问题, 那就是readfile, 虽然PHP的readfile尝试实现的尽量高效, 不占用PHP本身的内存, 但是实际上它还是需要采用MMAP(如果支持), 或者是一个固定的buffer去循环读取文件, 直接输出.

输出的时候, 如果是Apache + PHP mod, 那么还需要发送到Apache的输出缓冲区. 最后才发送给用户. 而对于Nginx + fpm如果他们分开部署的话, 那还会带来额外的网络IO.

那么, 能不能不经过PHP这层, 直接让Webserver直接把文件发送给用户呢?

今天, 我看到了一个有意思的文章: How I PHP: X-SendFile.

我们可以使用Apache的module mod_xsendfile, 让Apache直接发送这个文件给用户:

<?php
    $file = "/tmp/中文名.tar.gz";    $filename = basename($file);
    header("Content-type: application/octet-stream");
    //处理中文文件名
    $ua = $_SERVER["HTTP_USER_AGENT"];
    $encoded_filename = rawurlencode($filename);
    if (preg_match("/MSIE/", $ua)) {
     header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
    } else if (preg_match("/Firefox/", $ua)) {
     header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
    } else {
     header('Content-Disposition: attachment; filename="' . $filename . '"');
    }
    //让Xsendfile发送文件
    header("X-Sendfile: $file");

X-Sendfile头将被Apache处理, 并且把响应的文件直接发送给Client.

Lighttpd和Nginx也有类似的模块, 大家有兴趣的可以去找找看

PHP 相关文章推荐
一个ORACLE分页程序,挺实用的.
Oct 09 PHP
PHP操作文件方法问答
Mar 16 PHP
PHP中对用户身份认证实现两种方法
Jun 04 PHP
php获取ip的三个属性区别介绍(HTTP_X_FORWARDED_FOR,HTTP_VIA,REMOTE_ADDR)
Sep 23 PHP
PHP中判断变量为空的几种方法分享
Aug 26 PHP
PHP异常处理浅析
May 12 PHP
Thinkphp关闭缓存的方法
Jun 26 PHP
php中实现字符串翻转的方法
Feb 22 PHP
CakePHP框架Model关联对象用法分析
Aug 04 PHP
php插件Xajax使用方法详解
Aug 31 PHP
Laravel框架学习笔记之批量更新数据功能
May 30 PHP
聊聊 PHP 8 新特性 Attributes
Aug 19 PHP
PHP is_subclass_of函数的一个BUG和解决方法
Jun 01 #PHP
PHP中数组的分组排序实例
Jun 01 #PHP
php_screw安装使用教程(另一个PHP代码加密实现)
May 29 #PHP
PHP Curl出现403错误的解决办法
May 29 #PHP
PHP的foreach中使用引用时需要注意的一个问题和解决方法
May 29 #PHP
神盾加密解密教程(一)PHP变量可用字符
May 28 #PHP
CI框架开发新浪微博登录接口源码完整版
May 28 #PHP
You might like
PHP中MD5函数使用实例代码
2008/06/07 PHP
PHP中数组定义的几种方法
2013/09/01 PHP
标准PHP的AES加密算法类
2015/03/12 PHP
php实现的任意进制互转类分享
2015/07/07 PHP
Zend Framework入门教程之Zend_Session会话操作详解
2016/12/08 PHP
TP框架实现上传一张图片和批量上传图片的方法分析
2020/04/23 PHP
javascript-TreeView父子联动效果保持节点状态一致
2007/08/12 Javascript
JavaScript随机排序(随即出牌)
2010/09/17 Javascript
jQuery中对节点进行操作的相关介绍
2013/04/16 Javascript
js+html5通过canvas指定开始和结束点绘制线条的方法
2015/06/05 Javascript
JavaScript中标识符提升问题
2015/06/11 Javascript
JS实现的仿淘宝交易倒计时效果
2015/11/27 Javascript
基于JavaScript实现自定义滚动条
2017/01/25 Javascript
js实现楼层导航功能
2017/02/23 Javascript
bootstrap select下拉搜索插件使用方法详解
2017/11/23 Javascript
在vue中获取微信支付code及code被占用问题的解决方法
2019/04/16 Javascript
JavaScript怎样在删除前添加确认弹出框?
2019/05/27 Javascript
中级前端工程师必须要掌握的27个JavaScript 技巧(干货总结)
2019/09/23 Javascript
详解Python3 中hasattr()、getattr()、setattr()、delattr()函数及示例代码数
2018/04/18 Python
Python全局变量与局部变量区别及用法分析
2018/09/03 Python
python+opencv 读取文件夹下的所有图像并批量保存ROI的方法
2019/01/10 Python
Python之time模块的时间戳,时间字符串格式化与转换方法(13位时间戳)
2019/08/12 Python
在Python中字符串、列表、元组、字典之间的相互转换
2019/11/15 Python
Python reversed函数及使用方法解析
2020/03/17 Python
Django Auth用户认证组件实现代码
2020/10/13 Python
python 简单的调用有道翻译
2020/11/25 Python
python实现scrapy爬虫每天定时抓取数据的示例代码
2021/01/27 Python
在css3中background-clip属性与background-origin属性的用法介绍
2012/11/13 HTML / CSS
html5 Canvas画图教程(9)—canvas中画出矩形和圆形
2013/01/09 HTML / CSS
linux面试题参考答案(5)
2016/11/05 面试题
模特职业生涯规划范文
2014/02/26 职场文书
《白鹅》教学反思
2014/04/13 职场文书
水利水电建筑施工应届生求职信
2014/07/04 职场文书
医院合作协议书
2014/08/19 职场文书
python 如何做一个识别率百分百的OCR
2021/05/29 Python
分析SQL窗口函数之排名窗口函数
2022/04/21 Oracle