让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 相关文章推荐
消息持续发送的完整例子
Oct 09 PHP
Smarty模板快速入门
Jan 04 PHP
web站点获取用户IP的安全方法 HTTP_X_FORWARDED_FOR检验
Jun 01 PHP
如何在php中正确的使用json
Aug 06 PHP
php堆排序(heapsort)练习
Nov 13 PHP
php中调用其他系统http接口的方法说明
Feb 28 PHP
PHP+javascript制作带提示的验证码源码分享
May 28 PHP
php 伪造ip以及url来路信息方法汇总
Nov 25 PHP
PHP经典面试题之设计模式(经常遇到)
Oct 15 PHP
PHP MSSQL 分页实例
Apr 13 PHP
微信公众号开发之语音消息识别php代码
Aug 08 PHP
PHP中文字符串截断无乱码解决方法
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
Linux下实现PHP多进程的方法分享
2012/08/16 PHP
thinkphp框架下404页面设置 仅三步
2016/05/14 PHP
php中请求url的五种方法总结
2017/07/13 PHP
js与运算符和或运算符的妙用
2014/02/14 Javascript
jquery attr方法获取input的checked属性问题
2014/05/26 Javascript
jQuery使用fadeout实现元素渐隐效果的方法
2015/03/27 Javascript
Javascript 跨域知识详细介绍
2016/10/30 Javascript
jQuery Validate表单验证插件的基本使用方法及功能拓展
2017/01/04 Javascript
原生javascript AJAX 三级联动的实现代码
2018/05/04 Javascript
elementUI vue this.$confirm 和el-dialog 弹出框 移动 示例demo
2019/07/03 Javascript
layer ui插件显示tips时,修改字体颜色的实现方法
2019/09/11 Javascript
如何手写一个简易的 Vuex
2020/10/10 Javascript
Python删除空文件和空文件夹的方法
2015/07/14 Python
python 禁止函数修改列表的实现方法
2017/08/03 Python
使用python将大量数据导出到Excel中的小技巧分享
2018/06/14 Python
python批量下载网站马拉松照片的完整步骤
2018/12/05 Python
python爬取酷狗音乐排行榜
2019/02/20 Python
Python小白必备的8个最常用的内置函数(推荐)
2019/04/03 Python
Python中format()格式输出全解
2019/04/12 Python
python 工具 字符串转numpy浮点数组的实现
2020/03/14 Python
为什么说python适合写爬虫
2020/06/11 Python
Python基于Socket实现简易多人聊天室的示例代码
2020/11/29 Python
python里glob模块知识点总结
2021/01/05 Python
aec加密 php_php aes加密解密类(兼容php5、php7)
2021/03/14 PHP
使用CSS3制作倾斜导航条和毛玻璃效果
2017/09/12 HTML / CSS
CSS实现定位元素居中的方法
2015/06/23 HTML / CSS
详解使用postMessage解决iframe跨域通信问题
2019/11/01 HTML / CSS
意大利文具和办公产品在线商店:Y-Office
2020/02/27 全球购物
消防安全管理制度
2014/02/01 职场文书
入党综合考察材料
2014/06/02 职场文书
信访稳定工作汇报
2014/10/27 职场文书
2014年销售部工作总结
2014/12/01 职场文书
幼儿园中秋节活动总结
2015/03/23 职场文书
工程资料员岗位职责
2015/04/13 职场文书
物业工程部主管岗位职责
2015/04/16 职场文书
朝花夕拾读书笔记
2015/06/29 职场文书