让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 相关文章推荐
Oracle Faq(Oracle的版本)
Oct 09 PHP
PHP初学者头疼问题总结
Oct 09 PHP
php下将图片以二进制存入mysql数据库中并显示的实现代码
May 27 PHP
php表单转换textarea换行符的方法
Sep 10 PHP
PHP开发中常用的字符串操作函数
Feb 08 PHP
PHP中批量生成静态html(命令行下运行PHP)
Apr 19 PHP
php多次include后导致全局变量global失效的解决方法
Feb 28 PHP
php支付宝手机网页支付类实例
Mar 04 PHP
详解PHP对数组的定义以及数组的创建方法
Nov 27 PHP
微信公众号OAuth2.0网页授权问题浅析
Jan 21 PHP
Laravel框架集合用法实例浅析
May 14 PHP
PHP8.0新功能之Match表达式的使用
Jul 19 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+DBM的同学录程序(2)
2006/10/09 PHP
木翼下载系统中说明的PHP安全配置方法
2007/06/16 PHP
php实现过滤字符串中的中文和数字实例
2015/07/29 PHP
基于PHP微信红包的算法探讨
2016/07/21 PHP
php微信开发之自定义菜单实现
2016/11/18 PHP
jquery 获取json数据实现代码
2009/04/27 Javascript
用jquery实现输入框获取焦点消失文字
2013/04/27 Javascript
jquery实现标题字体变换的滑动门菜单效果
2015/09/07 Javascript
如何根据百度地图计算出两地之间的驾驶距离(两种语言js和C#)
2015/10/29 Javascript
jQuery Easyui学习之datagrid 动态添加、移除editor
2016/01/27 Javascript
基于JavaScript实现回到页面顶部动画代码
2016/05/24 Javascript
javascript简单实现等比例缩小图片的方法
2016/07/27 Javascript
微信小程序实现banner图轮播效果
2020/06/28 Javascript
node.JS的crypto加密模块使用方法详解(MD5,AES,Hmac,Diffie-Hellman加密)
2020/02/06 Javascript
JavaScript设计模式之门面模式原理与实现方法分析
2020/03/09 Javascript
Python中的Numpy入门教程
2014/04/26 Python
Python中的defaultdict与__missing__()使用介绍
2018/02/03 Python
Python for循环生成列表的实例
2018/06/15 Python
python 中字典嵌套列表的方法
2018/07/03 Python
Python远程视频监控程序的实例代码
2019/05/05 Python
python发送多人邮件没有展示收件人问题的解决方法
2019/06/21 Python
pandas的qcut()方法详解
2019/07/06 Python
Python如何调用外部系统命令
2019/08/07 Python
numpy:找到指定元素的索引示例
2019/11/26 Python
用python介绍4种常用的单链表翻转的方法小结
2020/02/24 Python
python实现提取str字符串/json中多级目录下的某个值
2020/02/27 Python
Python 输出详细的异常信息(traceback)方式
2020/04/08 Python
python与pycharm有何区别
2020/07/01 Python
python接入支付宝的实例操作
2020/07/20 Python
Champs Sports加拿大:北美最大的以商场为基础的专业运动鞋和服装零售商之一
2018/05/01 全球购物
实习求职信
2013/12/01 职场文书
中专生求职自荐信范文
2013/12/22 职场文书
认真学习保证书
2015/02/26 职场文书
2015年维修工作总结
2015/04/25 职场文书
Django显示可视化图表的实践
2021/05/10 Python
Windows server 2016服务器基本设置
2022/08/14 Servers