让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的五种设计模式
Sep 05 PHP
安装apache2.2.22配置php5.4(具体操作步骤)
Jun 26 PHP
php中的ini配置原理详解
Oct 14 PHP
php中使用session_set_save_handler()函数把session保存到MySQL数据库实例
Nov 06 PHP
PHP封装的Twitter访问类实例
Jul 18 PHP
四个常见html网页乱码问题及解决办法
Sep 08 PHP
学习php设计模式 php实现抽象工厂模式
Dec 07 PHP
根据key删除数组中指定的元素实现方法
Mar 02 PHP
yii2.0整合阿里云oss上传单个文件的示例
Sep 19 PHP
PHP5.0 TIDY_PARSE_FILE缓冲区溢出漏洞的解决方案
Oct 14 PHP
PHP实现函数内修改外部变量值的方法示例
Dec 28 PHP
php DES加密算法实例分析
Sep 18 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制作图形验证码代码分享
2014/10/23 PHP
PHP简单生成缩略图相册的方法
2015/07/29 PHP
ThinkPHP的常用配置选项汇总
2016/03/24 PHP
浅析PHP echo 和 print 语句
2020/06/30 PHP
javascript实现动态增加删除表格行(兼容IE/FF)
2007/04/02 Javascript
js获取当前select 元素值的代码
2010/04/19 Javascript
jQuery 名称冲突的解决方法
2011/04/08 Javascript
jQuery 获取URL的GET参数值的小例子
2013/04/18 Javascript
JavaScript中的标签语句用法分析
2015/02/10 Javascript
Vue.js实现移动端短信验证码功能
2017/03/29 Javascript
微信小程序自定义导航隐藏和显示功能
2017/06/13 Javascript
bootstrap table实现x-editable的行单元格编辑及解决数据Empty和支持多样式问题
2017/08/10 Javascript
基于JavaScript实现前端数据多条件筛选功能
2020/08/19 Javascript
详解如何去除vue项目中的#——History模式
2017/10/13 Javascript
微信小程序websocket聊天室的实现示例代码
2019/02/12 Javascript
JavaScript 常见的继承方式汇总
2020/09/17 Javascript
antd日期选择器禁止选择当天之前的时间操作
2020/10/29 Javascript
[02:23]2018DOTA2亚洲邀请赛趣味视频——反应测试
2018/04/04 DOTA
Python升级提示Tkinter模块找不到的解决方法
2014/08/22 Python
跟老齐学Python之一个免费的实验室
2014/09/14 Python
浅谈终端直接执行py文件,不需要python命令
2017/01/23 Python
Python实现的文本简单可逆加密算法示例
2017/05/18 Python
python学生信息管理系统(初级版)
2018/10/17 Python
利用ctypes获取numpy数组的指针方法
2019/02/12 Python
python制作抽奖程序代码详解
2021/01/15 Python
iframe与window.onload如何使用详解
2020/05/07 HTML / CSS
物业经理求职自我评价
2013/09/22 职场文书
2013年办公室秘书的个人自我鉴定
2013/10/24 职场文书
技校毕业生自荐书
2014/05/23 职场文书
会计学专业自荐信
2014/06/25 职场文书
装修施工安全责任书
2014/07/24 职场文书
挂职学习心得体会
2014/09/09 职场文书
师德师风整改措施
2014/10/24 职场文书
小浪底导游词
2015/02/12 职场文书
《少年闰土》教学反思
2016/02/18 职场文书
vue3使用vue-router的完整步骤记录
2021/06/20 Vue.js