让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写UltraEdit插件脚本实现方法
Dec 26 PHP
深入理解ob_flush和flush的区别(ob_flush()与flush()使用方法)
Feb 06 PHP
PHP中Fatal error session_start()错误解决步骤
Aug 05 PHP
PHP Reflection API详解
May 12 PHP
php生成4位数字验证码的实现代码
Nov 23 PHP
php简单实现批量上传图片的方法
May 09 PHP
Laravel重写用户登录简单示例
Oct 08 PHP
thinkPHP显示不出验证码的原因与解决方法分析
May 20 PHP
php使用str_replace替换多维数组的实现方法分析
Jun 15 PHP
PHP7.1实现的AES与RSA加密操作示例
Jun 15 PHP
PHP实现的函数重载功能示例
Aug 03 PHP
使用composer 安装 laravel框架的方法图文详解
Aug 02 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程序
2012/02/04 PHP
thinkphp使用phpmailer发送邮件的方法
2014/11/24 PHP
PHP hebrev()函数用法讲解
2019/02/21 PHP
利用XMLHTTP传递参数在另一页面执行并刷新本页
2006/10/26 Javascript
关于query Javascript CSS Selector engine
2013/04/12 Javascript
node.js中的querystring.escape方法使用说明
2014/12/10 Javascript
TypeScript Type Innference(类型判断)
2016/03/10 Javascript
使用vue.js编写蓝色拼图小游戏
2017/03/17 Javascript
JavaScript数据结构之二叉树的遍历算法示例
2017/04/13 Javascript
nodejs6下使用koa2框架实例
2017/05/18 NodeJs
元素全屏的设置与监听实例
2017/11/28 Javascript
vue源码入口文件分析(推荐)
2018/01/30 Javascript
七行JSON代码把你的网站变成移动应用过程详解
2019/07/09 Javascript
JavaScript剩余操作符Rest Operator详解
2019/07/20 Javascript
微信小程序实现页面分享onShareAppMessage
2019/08/12 Javascript
vue 子组件watch监听不到prop的解决
2020/08/09 Javascript
javascript实现数字时钟效果
2021/02/06 Javascript
[00:57]林俊杰助阵DOTA2亚洲邀请赛
2015/01/28 DOTA
Python中的单继承与多继承实例分析
2018/05/10 Python
Win10下Python3.7.3安装教程图解
2019/07/08 Python
python scrapy爬虫代码及填坑
2019/08/12 Python
selenium+Chrome滑动验证码破解二(某某网站)
2019/12/17 Python
Python更换pip源方法过程解析
2020/05/19 Python
HTML5 history新特性pushState、replaceState及两者的区别
2015/12/26 HTML / CSS
新百伦折扣店:Joe’s New Balance Outlet
2016/08/20 全球购物
Omio俄罗斯:一次搜索公共汽车、火车和飞机的机票
2018/11/17 全球购物
欧洲最大的高尔夫零售商:American Golf
2019/09/02 全球购物
物流专业大学生职业生涯规划书范文
2014/01/15 职场文书
班级德育工作实施方案
2014/02/21 职场文书
预备党员2014全国两会学习心得体会
2014/03/10 职场文书
触电现场处置方案
2014/05/14 职场文书
化学专业大学生职业生涯规划范文
2014/09/13 职场文书
我的职业生涯规划:打造自己的运动帝国
2014/09/18 职场文书
党的群众路线教育实践活动实施方案
2014/10/31 职场文书
导游词之四川熊猫基地
2020/01/13 职场文书
opencv 分类白天与夜景视频的方法
2021/06/05 Python