让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初学入门
Nov 19 PHP
php session 预定义数组
Mar 16 PHP
PHP 缓存实现代码及详细注释
May 16 PHP
PHP url 加密解密函数代码
Aug 26 PHP
PHP转换文件夹下所有文件编码的实现代码
Jun 06 PHP
php实现的太平洋时间和北京时间互转的自定义函数分享
Aug 19 PHP
PHP类的反射用法实例
Nov 03 PHP
PHP生成各种常见验证码和Ajax验证过程
Jan 10 PHP
Ajax提交表单时验证码自动验证 php后端验证码检测
Jul 20 PHP
微信红包随机生成算法php版
Jul 21 PHP
PHP实现向关联数组指定的Key之前插入元素的方法
Jun 06 PHP
PHP生成短网址的思路以及实现方法的详解
Mar 25 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
一键删除顽固的空文件夹 软件下载
2007/01/26 PHP
php 判断访客是否为搜索引擎蜘蛛的函数代码
2011/07/29 PHP
apache mysql php 源码编译使用方法
2012/05/03 PHP
php define的第二个参数使用方法
2013/11/04 PHP
codeigniter中实现一次性加载多个view的方法
2015/03/20 PHP
Yii扩展组件编写方法实例分析
2015/06/29 PHP
php mysql_list_dbs()函数用法示例
2017/03/29 PHP
php实现用户注册密码的crypt加密
2017/06/08 PHP
php安装扩展mysqli的实现步骤及报错解决办法
2017/09/23 PHP
Javascript入门学习资料收集整理篇
2008/07/06 Javascript
jquery插件开发注意事项小结
2013/06/04 Javascript
js控制href内容的连接内容的变化示例
2014/04/30 Javascript
利用jquery实现瀑布流3种案例
2016/09/18 Javascript
概述如何实现一个简单的浏览器端js模块加载器
2016/12/07 Javascript
jQuery.cookie.js实现记录最近浏览过的商品功能示例
2017/01/23 Javascript
vue.js表单验证插件(vee-validate)的使用教程详解
2019/05/23 Javascript
javascript实现评分功能
2020/06/24 Javascript
使用纯前端JavaScript实现Excel导入导出方法过程详解
2020/08/07 Javascript
[01:47]2018年度DOTA2最具人气解说-完美盛典
2018/12/16 DOTA
python Django连接MySQL数据库做增删改查
2013/11/07 Python
在Python中操作时间之strptime()方法的使用
2020/12/30 Python
教你用python3根据关键词爬取百度百科的内容
2016/08/18 Python
Python中的单继承与多继承实例分析
2018/05/10 Python
Jupyter notebook在mac:linux上的配置和远程访问的方法
2019/01/14 Python
Python dict和defaultdict使用实例解析
2020/03/12 Python
Python DES加密实现原理及实例解析
2020/07/17 Python
Sephora丝芙兰澳洲官方网站:国际知名化妆品购物
2016/10/27 全球购物
小学运动会表扬稿
2014/01/19 职场文书
债务授权委托书范本
2014/10/17 职场文书
2015婚礼主持词开场白
2015/05/28 职场文书
MySQL索引篇之千万级数据实战测试
2021/04/05 MySQL
SONY AN-LP1 短波有源天线放大器
2021/04/22 无线电
Python预测分词的实现
2021/06/18 Python
MySQL8.0升级的踩坑历险记
2021/11/01 MySQL
使用RedisTemplat实现简单的分布式锁
2021/11/20 Redis
Innodb存储引擎中的后台线程详解
2022/04/03 MySQL