在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缩略图生成程式(需要GD库支持)
Mar 06 PHP
php strtotime 函数UNIX时间戳
Jan 14 PHP
PHP 设置MySQL连接字符集的方法
Jan 02 PHP
php实现的获取网站备案信息查询代码(360)
Sep 23 PHP
php 字符串压缩方法比较示例
Jan 23 PHP
关于js和php对url编码的处理方法
Mar 04 PHP
CI使用Tank Auth转移数据库导致密码用户错误的解决办法
Jun 12 PHP
PHP将字符分解为多个字符串的方法
Nov 22 PHP
ecshop实现smtp发送邮件
Feb 03 PHP
利用php操作memcache缓存的基础方法示例
Aug 02 PHP
PHP实现二维数组中的查找算法小结
Jun 09 PHP
PHP Swoole异步MySQL客户端实现方法示例
Oct 24 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中数组元素升序、降序以及重新排序的函数
2013/06/20 PHP
php生成rss类用法实例
2015/04/14 PHP
PHP全功能无变形图片裁剪操作类与用法示例
2017/01/10 PHP
深入理解PHP的远程多会话调试
2017/09/21 PHP
jQuery 动态酷效果实现总结
2009/12/27 Javascript
jquery.cookie() 方法的使用(读取、写入、删除)
2013/12/05 Javascript
jQuery实现瀑布流的取巧做法分享
2015/01/12 Javascript
JQuery异步获取返回值中文乱码的解决方法
2015/01/29 Javascript
js判断子窗体是否关闭的方法
2015/08/11 Javascript
辨析JavaScript中的Undefined类型与null类型
2016/05/26 Javascript
基于node.js之调试器详解
2017/08/22 Javascript
基于vue配置axios的方法步骤
2017/11/09 Javascript
zTree树形菜单交互选项卡效果的实现方法
2017/12/25 Javascript
详解vue项目打包后通过百度的BAE发布到网上的流程
2018/03/05 Javascript
JavaScript 中的12种循环遍历方法【总结】
2018/05/31 Javascript
JS/HTML5游戏常用算法之碰撞检测 像素检测算法实例详解
2018/12/12 Javascript
js中offset,client , scroll 三大元素知识点总结
2019/09/11 Javascript
Vue 自定义标签的src属性不能使用相对路径的解决
2019/09/17 Javascript
[01:32]TI奖金增速竟因它再创新高!DOTA2勇士令状不朽珍藏Ⅰ饰品欣赏
2018/05/18 DOTA
python的正则表达式re模块的常用方法
2013/03/09 Python
Python实现的简单算术游戏实例
2015/05/26 Python
Python 常用string函数详解
2016/05/30 Python
Scrapy的简单使用教程
2017/10/24 Python
Python编程之黑板上排列组合,你舍得解开吗
2017/10/30 Python
Python生成器以及应用实例解析
2018/02/08 Python
Python安装图文教程 Pycharm安装教程
2018/03/27 Python
关于Python 的简单栅格图像边界提取方法
2019/07/05 Python
python 5个实用的技巧
2020/09/27 Python
HTML5 Canvas实现平移/放缩/旋转deom示例(附截图)
2013/07/04 HTML / CSS
2014年计算机专业个人自我评价
2014/01/19 职场文书
房屋认购协议书
2015/01/29 职场文书
东京审判观后感
2015/06/01 职场文书
新娘婚礼致辞
2015/07/27 职场文书
2016民族团结先进个人事迹材料
2016/02/26 职场文书
python实现简单区块链结构
2021/04/25 Python
MySQL面试题讲解之如何设置Hash索引
2021/11/01 MySQL