在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 相关文章推荐
GD输出汉字的函数的分析
Oct 09 PHP
php+javascript的日历控件
Nov 19 PHP
PHP函数篇详解十进制、二进制、八进制和十六进制转换函数说明
Dec 05 PHP
PHP5.4中json_encode中文转码的变化小结
Jan 30 PHP
php中如何判断一个网页请求是ajax请求还是普通请求
Aug 10 PHP
一组PHP可逆加密解密算法实例代码
Jan 21 PHP
ThinkPHP连接数据库的方式汇总
Dec 05 PHP
php进行支付宝开发中return_url和notify_url的区别分析
Dec 22 PHP
部署PHP时的4个配置修改说明
Oct 19 PHP
php结合web uploader插件实现分片上传文件
May 10 PHP
PHP实现的字符串匹配算法示例【sunday算法】
Dec 19 PHP
php使用filter_var函数判断邮箱,url,ip格式示例
Jul 06 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
域名和cookie问题(域名后缀)
2012/10/10 PHP
PHP中操作ini配置文件的方法
2013/04/25 PHP
php实现购物车功能(下)
2016/01/05 PHP
详解PHP处理密码的几种方式
2016/11/30 PHP
详解Laravel设置多态关系模型别名的方式
2019/10/17 PHP
零基础学JavaScript最新动画教程+iso光盘下载
2008/01/22 Javascript
JavaScript 设计模式 富有表现力的Javascript(一)
2010/05/26 Javascript
javascript真的不难-回顾一下基础知识
2013/01/15 Javascript
《JavaScript DOM 编程艺术》读书笔记之JavaScript 简史
2015/01/09 Javascript
JavaScript用select实现日期控件
2015/07/17 Javascript
jquery实现漂亮的二级下拉菜单代码
2015/08/26 Javascript
jQuery实现可编辑的表格实例讲解(2)
2015/09/17 Javascript
JS常用字符串方法(推荐)
2021/01/15 Javascript
原生js实现可拖拽效果
2017/02/28 Javascript
BootstrapValidator实现注册校验和登录错误提示效果
2017/03/10 Javascript
基于jquery实现五星好评
2017/11/18 jQuery
vue 优化CDN加速的方法示例
2018/09/19 Javascript
Vue CLI 3搭建vue+vuex最全分析(推荐)
2018/09/27 Javascript
教你完全理解ReentrantLock重入锁
2019/06/03 Javascript
Node.js API详解之 readline模块用法详解
2020/05/22 Javascript
JavaScript实现点击切换功能
2021/01/27 Javascript
[42:23]完美世界DOTA2联赛PWL S3 Forest vs Rebirth 第二场 12.10
2020/12/13 DOTA
Python实现统计给定列表中指定数字出现次数的方法
2018/04/11 Python
Python计算开方、立方、圆周率,精确到小数点后任意位的方法
2018/07/17 Python
python用for循环求和的方法总结
2019/07/08 Python
Django集成celery发送异步邮件实例
2019/12/17 Python
如何使用pandas读取txt文件中指定的列(有无标题)
2020/03/05 Python
Python中return函数返回值实例用法
2020/11/19 Python
移动端html5 meta标签的神奇功效
2016/01/06 HTML / CSS
麦当劳印度网上订餐:McDelivery
2020/03/16 全球购物
声明struct x1 { . . . }; 和typedef struct { . . . }x2;有什么不同
2012/06/02 面试题
党支部书记岗位责任制
2014/02/11 职场文书
书法大赛策划方案
2014/06/04 职场文书
软件研发工程师岗位职责
2014/09/30 职场文书
小学优秀教师材料
2014/12/15 职场文书
python实现web邮箱扫描的示例(附源码)
2021/03/30 Python