让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中使用全局变量的几种方法
Jun 24 PHP
解析wamp5下虚拟机配置文档
Jun 27 PHP
浅析PHP安装扩展mcrypt以及相关依赖项(PHP安装PECL扩展的方法)
Jul 05 PHP
php与java通过socket通信的实现代码
Oct 21 PHP
PHP使用正则表达式清除超链接文本
Nov 12 PHP
php 判断网页是否是utf8编码的方法
Jun 06 PHP
php保存二进制原始数据为图片的程序代码
Oct 14 PHP
php自动加载方式集合
Apr 04 PHP
PHP实现的方程求解示例分析
Nov 11 PHP
redirect_uri参数错误的解决方法(必看)
Feb 16 PHP
php strftime函数获取日期时间(switch用法)
May 16 PHP
php中文语义分析实现方法示例
Sep 28 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
require(),include(),require_once()和include_once()区别
2008/03/27 PHP
PHP-MySQL教程归纳总结
2008/06/07 PHP
让codeigniter与swfupload整合的最佳解决方案
2014/06/12 PHP
PHP回溯法解决0-1背包问题实例分析
2015/03/23 PHP
PHP实现找出有序数组中绝对值最小的数算法分析
2017/08/07 PHP
JAVASCRIPT style 中visibility和display之间的区别
2010/01/22 Javascript
防止页面被iframe(兼容IE,Firefox火狐)
2010/07/04 Javascript
javascript 广告后加载,加载完页面再加载广告
2010/11/25 Javascript
js下关于onmouseout、事件冒泡的问题经验小结
2010/12/09 Javascript
js实现的跟随鼠标移动的时钟效果(中英文日期显示)
2011/01/17 Javascript
分析Node.js connect ECONNREFUSED错误
2013/04/09 Javascript
jquery实现的导航固定效果
2014/04/28 Javascript
原生的html元素选择器类似jquery选择器
2014/10/15 Javascript
jquery实现浮动在网页右下角的彩票开奖公告窗口代码
2015/09/04 Javascript
node.js+jQuery实现用户登录注册AJAX交互
2017/04/28 jQuery
Vue组件之Tooltip的示例代码
2017/10/18 Javascript
基于cropper.js封装vue实现在线图片裁剪组件功能
2018/03/01 Javascript
Node.js + express基本用法教程
2019/03/14 Javascript
使用python将mdb数据库文件导入postgresql数据库示例
2014/02/17 Python
举例讲解Python中metaclass元类的创建与使用
2016/06/30 Python
Python开发中爬虫使用代理proxy抓取网页的方法示例
2017/09/26 Python
Django框架教程之正则表达式URL误区详解
2018/01/28 Python
python实现在IDLE中输入多行的方法
2018/04/19 Python
Python mutiprocessing多线程池pool操作示例
2019/01/30 Python
Python3.7 dataclass使用指南小结
2019/02/22 Python
深入解析神经网络从原理到实现
2019/07/26 Python
python解析yaml文件过程详解
2019/08/30 Python
Python如何在DataFrame增加数值
2020/02/14 Python
linux系统下pip升级报错的解决方法
2021/01/31 Python
利用Canvas模仿百度贴吧客户端loading小球的方法示例
2017/08/13 HTML / CSS
雅诗兰黛(Estee Lauder)英国官方网站:世界顶级化妆品牌
2016/12/29 全球购物
在C#中如何实现多态
2014/07/02 面试题
英文版区域经理求职信
2013/10/23 职场文书
《最后的姿势》教学反思
2014/02/27 职场文书
园林设计专业毕业生求职信
2014/03/23 职场文书
苹果M1芯片安装nginx 并且部署vue项目步骤详解
2021/11/20 Servers