让PHP更快的提供文件下载的代码


Posted in PHP onJune 13, 2012

但是, 这样做, 就没办法做一些统计, 权限检查, 等等的工作. 于是, 很多时候, 我们采用让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 = urlencode($filename); 
$encoded_filename = str_replace("+", "%20", $encoded_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-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 = urlencode($filename); 
$encoded_filename = str_replace("+", "%20", $encoded_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-Disposition: attachment; filename="' . basename($file) . '"'); 
//让Xsendfile发送文件 
header("X-Sendfile: $file");

X-Sendfile头将被Apache处理, 并且把响应的文件直接发送给Client.
Lighttpd和Nginx也有类似的模块, 大家有兴趣的可以去找找看
PHP 相关文章推荐
如何去掉文章里的 html 语法
Oct 09 PHP
mysql_fetch_row,mysql_fetch_array,mysql_fetch_assoc的区别
Apr 24 PHP
PHP循环语句笔记(foreach,list)
Nov 29 PHP
Eclipse中php插件安装及Xdebug配置的使用详解
Apr 25 PHP
浅析is_writable的php实现
Jun 18 PHP
跟我学Laravel之配置Laravel
Oct 15 PHP
使用PHP similar text计算两个字符串相似度
Nov 06 PHP
php获取文件后缀的9种方法
Mar 22 PHP
Thinkphp批量更新数据的方法汇总
Jun 29 PHP
PHP和MYSQL实现分页导航思路详解
Apr 11 PHP
Swoole 5将移除自动添加Event::wait()特性详解
Jul 10 PHP
Laravel + Elasticsearch 实现中文搜索的方法
Feb 02 PHP
深入理解PHP之数组(遍历顺序)  Laruence原创
Jun 13 #PHP
header中Content-Disposition的作用与使用方法
Jun 13 #PHP
php文件打包 下载之使用PHP自带的ZipArchive压缩文件并下载打包好的文件
Jun 13 #PHP
Php中文件下载功能实现超详细流程分析
Jun 13 #PHP
php异常处理技术,顶级异常处理器
Jun 13 #PHP
PHP的异常处理类Exception的使用及说明
Jun 13 #PHP
PHP抽象类 介绍
Jun 13 #PHP
You might like
很实用的一个完整email发送程序
2006/10/09 PHP
php基于session实现数据库交互的类实例
2015/08/03 PHP
PHP实现上传图片到 zimg 服务器
2016/10/19 PHP
PHP错误处理函数register_shutdown_function使用示例
2017/07/03 PHP
如何通过Apache在本地配置多个虚拟主机
2020/07/29 PHP
javascript CSS画图之基础篇
2009/07/29 Javascript
Javascript 作用域使用说明
2009/08/13 Javascript
分享十五个最佳jQuery 幻灯插件和教程
2010/03/27 Javascript
JavaScript面向对象程序设计三 原型模式(上)
2011/12/21 Javascript
怎样在JavaScript里写一个swing把数据插入数据库
2012/12/10 Javascript
js导出table到excel同时兼容FF和IE示例
2013/09/03 Javascript
关于js内存泄露的一个好例子
2013/12/09 Javascript
JavaScript利用构造函数和原型的方式模拟C#类的功能
2014/03/06 Javascript
按钮接受回车事件的三种实现方法
2014/06/06 Javascript
Jquery日期选择datepicker插件用法实例分析
2015/06/08 Javascript
小白谈谈对JS原型链的理解
2016/05/03 Javascript
JS二分查找算法详解
2017/11/01 Javascript
Vue 中如何正确引入第三方模块的方法步骤
2019/05/05 Javascript
js实现点击烟花特效
2020/10/14 Javascript
[03:03]DOTA2校园争霸赛 济南城市决赛欢乐发奖活动
2013/10/21 DOTA
[01:15]《辉夜杯》北京网鱼队巡礼
2015/10/26 DOTA
[03:43]TI9战队采访——PSG.LGD
2019/08/22 DOTA
Python变量和数据类型详解
2017/02/15 Python
Python模块WSGI使用详解
2018/02/02 Python
django 使用 request 获取浏览器发送的参数示例代码
2018/06/11 Python
Python实现的括号匹配判断功能示例
2018/08/25 Python
python 进程的几种创建方式详解
2019/08/29 Python
ubuntu16.04升级Python3.5到Python3.7的方法步骤
2020/08/20 Python
使用python tkinter开发一个爬取B站直播弹幕工具的实现代码
2021/02/07 Python
使用CSS3的ruby-position固定注音位置的用法示例
2016/07/05 HTML / CSS
365 Tickets英国:全球景点门票
2019/07/06 全球购物
优秀本科生求职推荐信
2014/02/24 职场文书
幼儿园教师教学反思
2016/03/02 职场文书
什么是执行力?9个故事告诉您:成功绝非偶然!
2019/07/05 职场文书
Mysql数据库表中为什么有索引却没有提高查询速度
2022/02/24 MySQL
netty 实现tomcat的示例代码
2022/06/05 Servers