在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动态分页函数,PHP开发分页必备啦
Nov 07 PHP
php加密算法之实现可逆加密算法和解密分享
Jan 21 PHP
兼容ie6浏览器的php下载文件代码分享
Jul 14 PHP
php实现的验证码文件类实例
Jun 18 PHP
Zend Framework入门知识点小结
Mar 19 PHP
PHP读取zip文件的方法示例
Nov 17 PHP
phpstudy的php版本自由修改的方法
Oct 18 PHP
PHP 实现人民币小写转换成大写的方法及大小写转换函数
Nov 17 PHP
PHP操作Redis常用技巧总结
Apr 24 PHP
PHP数组常用函数实例小结
Aug 20 PHP
php中的buffer缓冲区用法分析
May 31 PHP
如何通过Apache在本地配置多个虚拟主机
Jul 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
PHP中substr函数字符串截取用法分析
2016/01/07 PHP
阿里云Win2016安装Apache和PHP环境图文教程
2018/03/11 PHP
PHP+Ajax实现上传文件进度条动态显示进度功能
2018/06/04 PHP
PHP关于foreach复制知识点总结
2019/01/28 PHP
jQuery使用hide方法隐藏元素自身用法实例
2015/03/30 Javascript
js实现仿京东2级菜单效果(带延时功能)
2015/08/27 Javascript
js密码强度校验
2015/11/10 Javascript
js随机生成26个大小写字母
2016/02/12 Javascript
jQuery常用的一些技巧汇总
2016/03/26 Javascript
使用Angular.js实现简单的购物车功能
2016/11/21 Javascript
详解微信小程序开发—你期待的分享功能来了,微信小程序序新增5大功能
2016/12/23 Javascript
树结构之JavaScript
2017/01/24 Javascript
Javascript for in的缺陷总结
2017/02/03 Javascript
js前端日历控件(悬浮、拖拽、自由变形)
2017/03/02 Javascript
easyui-edatagrid.js实现回车键结束编辑功能的实例
2017/04/12 Javascript
bootstrap常用组件之头部导航实现代码
2017/04/20 Javascript
JS 调试中常见的报错问题解决方法
2017/05/20 Javascript
js验证身份证号码记录的方法
2019/04/26 Javascript
element-ui中按需引入的实现
2019/12/25 Javascript
基于better-scroll 实现歌词联动功能的代码
2020/05/07 Javascript
解决vue安装less报错Failed to compile with 1 errors的问题
2020/10/22 Javascript
vscode自定义vue模板的实现
2021/01/27 Vue.js
Windows下实现Python2和Python3两个版共存的方法
2015/06/12 Python
python定向爬取淘宝商品价格
2018/02/27 Python
详解python多线程之间的同步(一)
2019/04/03 Python
python实现猜数字游戏
2020/03/25 Python
如何基于python操作excel并获取内容
2019/12/24 Python
浅谈Django QuerySet对象(模型.objects)的常用方法
2020/03/28 Python
5个你不知道的HTML5的接口介绍
2013/08/07 HTML / CSS
利用HTML5 Canvas API绘制矩形的超级攻略
2016/03/21 HTML / CSS
将世界上最美丽的摄影作品转化为艺术作品:Photos.com
2017/11/28 全球购物
ECCO爱步官方旗舰店:丹麦鞋履品牌
2018/01/02 全球购物
简历自我评价模版
2014/01/31 职场文书
小学见习报告
2014/10/31 职场文书
mysql中数据库覆盖导入的几种方式总结
2022/03/25 MySQL
速龙x4-860k处理器相当于i几
2022/04/20 数码科技