在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 相关文章推荐
PHP+DBM的同学录程序(2)
Oct 09 PHP
php的access操作类
Apr 09 PHP
PHP实现对站点内容外部链接的过滤方法
Sep 10 PHP
在Win7 中为php扩展配置Xcache
Oct 08 PHP
php中mail函数发送邮件失败的解决方法
Dec 24 PHP
php实现mysql事务处理的方法
Dec 25 PHP
PHP中FTP相关函数小结
Jul 15 PHP
Yii框架弹出窗口组件CJuiDialog用法分析
Jan 07 PHP
PHP经典实用正则表达式小结
May 04 PHP
PHP设计模式之观察者模式定义与用法分析
Apr 04 PHP
PHP+redis实现微博的拉模型案例详解
Jul 10 PHP
Yii框架小部件(Widgets)用法实例详解
May 15 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产生随机数的两种方法实例代码 输出随机IP
2011/04/08 PHP
使用图灵api创建微信聊天机器人
2015/07/23 PHP
php自定义函数实现二维数组排序功能
2016/07/20 PHP
PHP如何根据文件头检测文件类型实例代码
2018/10/14 PHP
Javascript Select操作大集合
2009/05/26 Javascript
用JavaScript将从数据库中读取出来的日期型格式化为想要的类型。
2009/08/15 Javascript
js动态调用css属性的小规律及实例说明
2013/12/28 Javascript
Javascript保存网页为图片借助于html2canvas库实现
2014/09/05 Javascript
jQuery实现HTML5 placeholder效果实例
2014/12/09 Javascript
深入理解(function(){... })();
2016/08/16 Javascript
常用jQuery选择器汇总
2017/02/02 Javascript
ReactNative页面跳转Navigator实现的示例代码
2017/08/02 Javascript
JS设计模式之数据访问对象模式的实例讲解
2017/09/30 Javascript
微信小程序url传参写变量的方法
2018/08/09 Javascript
react 国际化的实现代码示例
2018/09/14 Javascript
nodejs检测因特网是否断开的解决方案
2019/04/17 NodeJs
微信小程序云开发如何使用云函数生成二维码
2019/05/18 Javascript
JavaScript遍历查找数组中最大值与最小值的方法示例
2019/05/24 Javascript
vue实现购物车选择功能
2020/01/10 Javascript
Vue组件基础用法详解
2020/02/05 Javascript
vue+swiper实现左右滑动的测试题功能
2020/10/30 Javascript
[13:21]DOTA2国际邀请赛采访专栏:RSnake战队国士无双,Fnatic.Fly
2013/08/06 DOTA
python 专题九 Mysql数据库编程基础知识
2017/03/16 Python
python如何为创建大量实例节省内存
2018/03/20 Python
Python字符串匹配之6种方法的使用详解
2019/04/08 Python
手把手教你pycharm专业版安装破解教程(linux版)
2019/09/26 Python
Django crontab定时任务模块操作方法解析
2020/09/10 Python
新秀丽拉杆箱美国官方网站:Samsonite美国
2016/07/25 全球购物
柒牌官方商城:中国男装优秀品牌
2017/06/30 全球购物
swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
2013/03/30 面试题
论文指导教师评语
2014/04/28 职场文书
前台接待岗位职责
2015/02/03 职场文书
2015年六一儿童节活动方案
2015/05/05 职场文书
中国汉字听写大会观后感
2015/06/02 职场文书
创业不要错过,这4种餐饮新模式
2019/07/18 职场文书
分享node.js实现简单登录注册的具体代码
2022/04/26 NodeJs