让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 相关文章推荐
PHP实现域名whois查询的代码(数据源万网、新网)
Feb 22 PHP
php批量缩放图片的代码[ini参数控制]
Feb 11 PHP
使用Linux五年积累的一些经验技巧
Jun 20 PHP
php获取网页中图片、DIV内容的简单方法
Jun 19 PHP
PHP中new static()与new self()的区别异同分析
Aug 22 PHP
yii中widget的用法
Dec 03 PHP
Laravel 5框架学习之向视图传送数据
Apr 08 PHP
PHP访问数据库集群的方法小结
Mar 14 PHP
php微信开发自定义菜单
Aug 27 PHP
[原创]php实现 data url的图片生成与保存
Dec 04 PHP
什么是PHP文件?如何打开PHP文件?
Jun 27 PHP
phpinfo的知识点总结
Oct 10 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
PHP进阶学习之依赖注入与Ioc容器详解
2019/06/19 PHP
JavaScript DOM 学习第三章 内容表格
2010/02/19 Javascript
javascript中使用css需要注意的地方小结
2010/09/01 Javascript
iframe如何动态创建及释放其所占内存
2014/09/03 Javascript
nodejs 整合kindEditor实现图片上传
2015/02/03 NodeJs
JS实现判断碰撞的方法
2015/02/11 Javascript
jQuery实现hover合成事件的方法
2015/08/06 Javascript
jQuery中$.ajax()和$.getJson()同步处理详解
2015/08/12 Javascript
JavaScript实现的伸展收缩型菜单代码
2015/10/14 Javascript
js判断手机访问或者PC的几个例子(常用于手机跳转)
2015/12/15 Javascript
利用jquery给指定的table动态添加一行、删除一行的方法
2016/10/12 Javascript
socket.io实现在线群聊功能
2017/04/07 Javascript
JS库之Highlight.js的用法详解
2017/09/13 Javascript
JavaScript使用享元模式实现文件上传优化操作示例
2018/08/07 Javascript
Angular使用cli生成自定义文件、组件的方法
2018/09/04 Javascript
javascript移动端 电子书 翻页效果实现代码
2019/09/07 Javascript
使用layer.msg 时间设置不起作用的解决方法
2019/09/12 Javascript
前端开发基础javaScript的六大作用
2020/08/06 Javascript
[15:58]DOTA2国际邀请赛采访专栏:Tongfu.Sansheng&KingJ,DK.rOtk
2013/08/08 DOTA
[01:21:58]守擂赛DOTA2第一周决赛
2020/04/22 DOTA
python开发之基于thread线程搜索本地文件的方法
2015/11/11 Python
python爬虫 正则表达式使用技巧及爬取个人博客的实例讲解
2017/10/20 Python
Django JWT Token RestfulAPI用户认证详解
2019/01/23 Python
使用Pyhton集合set()实现成果查漏的例子
2019/11/24 Python
python3实现弹弹球小游戏
2019/11/25 Python
python Plotly绘图工具的简单使用
2020/03/03 Python
使用Python获取当前工作目录和执行命令的位置
2020/03/09 Python
解决python3中os.popen()出错的问题
2020/11/19 Python
使用HTML5 Canvas API控制字体的显示与渲染的方法
2016/03/24 HTML / CSS
美国亚马逊旗下男装网站:East Dane(支持中文)
2019/09/25 全球购物
办公室助理岗位职责
2013/12/25 职场文书
你懂得怎么写自荐信吗?
2013/12/27 职场文书
励志演讲稿大全
2014/08/21 职场文书
公司员工体检通知
2015/04/21 职场文书
入党介绍人意见怎么写
2015/06/03 职场文书
英雄儿女观后感
2015/06/09 职场文书