在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 相关文章推荐
使用eAccelerator加密PHP程序
Oct 03 PHP
PHP递归算法的详细示例分析
Feb 19 PHP
PHP 清空varnish 缓存的详解(包括指定站点下的)
Jun 20 PHP
Yii框架中 find findAll 查找出制定的字段的方法对比
Sep 10 PHP
php单一接口的实现方法
Jun 20 PHP
PHP 9 大缓存技术总结
Sep 17 PHP
Zend Framework教程之Zend_Layout布局助手详解
Mar 04 PHP
mysql查找删除重复数据并只保留一条实例详解
Sep 24 PHP
浅谈PHP发送HTTP请求的几种方式
Jul 25 PHP
laravel 实现设置时区的简单方法
Oct 10 PHP
在Laravel中实现使用AJAX动态刷新部分页面
Oct 15 PHP
详解no input file specified 三种解决方法
Nov 29 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
备份mysql数据库的php代码(一个表一个文件)
2010/05/28 PHP
PHP代码实现表单数据验证类
2015/07/28 PHP
jquery不支持toggle()高(新)版本的问题解决
2016/09/24 PHP
PHP操作Postgresql封装类与应用完整实例
2018/04/24 PHP
PHP hebrev()函数用法讲解
2019/02/21 PHP
PHP实现微信公众号验证Token的示例代码
2019/12/16 PHP
javascript firefox不显示本地预览图片问题的解决方法
2008/11/12 Javascript
Prototype Template对象 学习
2009/07/19 Javascript
url 编码 js url传参中文乱码解决方案
2010/04/11 Javascript
jQuery基础知识filter()和find()实例说明
2010/07/06 Javascript
JQuery实现绚丽的横向下拉菜单
2013/12/19 Javascript
js禁止回车提交表单的示例代码
2013/12/23 Javascript
js鼠标点击图片实现随机变换图片的方法
2015/02/16 Javascript
jQuery实现伸展与合拢panel的方法
2015/04/30 Javascript
AngularJS constant和value区别详解
2017/02/28 Javascript
vuejs项目打包之后的首屏加载优化及打包之后出现的问题
2018/04/01 Javascript
解决vue 界面在苹果手机上滑动点击事件等卡顿问题
2018/11/27 Javascript
详解webpack4.x之搭建前端开发环境
2019/03/28 Javascript
layui上传图片到服务器的非项目目录下的方法
2019/09/26 Javascript
[29:23]2014 DOTA2国际邀请赛中国区预选赛 LGD-GAMING VS CIS 第一场1
2014/05/23 DOTA
python中OrderedDict的使用方法详解
2017/05/05 Python
Python实现可自定义大小的截屏功能
2018/01/20 Python
Python cookbook(数据结构与算法)字典相关计算问题示例
2018/02/18 Python
Python语言快速上手学习方法
2018/12/14 Python
利用python将图片版PDF转文字版PDF
2019/05/03 Python
Python3中的f-Strings增强版字符串格式化方法
2020/03/04 Python
python3代码中实现加法重载的实例
2020/12/03 Python
聊聊python在linux下与windows下导入模块的区别说明
2021/03/03 Python
Lee牛仔裤澳大利亚官网:美国著名牛仔裤品牌
2017/09/02 全球购物
可打印的优惠券、杂货和优惠券代码:Coupons.com
2018/06/12 全球购物
Myprotein西班牙官网:欧洲第一大运动营养品牌
2020/02/24 全球购物
贝佳斯官方网站:Borghese
2020/05/08 全球购物
高二英语教学反思
2014/01/19 职场文书
弘扬焦裕禄精神践行三严三实心得体会
2014/10/13 职场文书
道歉短信大全
2015/05/12 职场文书
深入理解margin塌陷和margin合并的解决方案
2021/06/26 HTML / CSS