让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 相关文章推荐
WINDOWS服务器安装多套PHP的另类解决方案
Oct 09 PHP
一键删除顽固的空文件夹 软件下载
Jan 26 PHP
IIS php环境配置PHP5 MySQL5 ZendOptimizer phpmyadmin安装与配置
Nov 18 PHP
phpMyAdmin链接MySql错误 个人解决方案
Dec 28 PHP
php中通过curl smtp发送邮件
Jun 05 PHP
php打开远程文件的方法和风险及解决方法
Nov 12 PHP
destoon官方标签大全
Jun 20 PHP
php上传中文文件名乱码问题处理方案
Feb 03 PHP
PHP创建PowerPoint2007文档的方法
Dec 10 PHP
Smarty模板简单配置与使用方法示例
May 23 PHP
微信支付开发告警通知实例
Jul 12 PHP
Laravel validate error处理,ajax,json示例
Oct 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
关于时间计算的结总
2006/12/06 PHP
FCKeditor的安装(PHP)
2007/01/13 PHP
功能齐全的PHP发送邮件类代码附详细说明
2008/07/10 PHP
php下关于中英数字混排的字符串分割问题
2010/04/06 PHP
PHP句法规则详解 入门学习
2011/11/09 PHP
javascript 写类方式之二
2009/07/05 Javascript
一个XML格式数据转换为图表的例子
2010/02/09 Javascript
基于jQuery的history历史记录插件
2010/12/11 Javascript
js查错流程归纳
2012/05/04 Javascript
onclick与listeners的执行先后问题详细解剖
2013/01/07 Javascript
jquery 快速回到页首的方法
2013/12/05 Javascript
Javascript判断文件是否存在(客户端/服务器端)
2014/09/16 Javascript
JavaScript定义变量和变量优先级问题探讨
2014/10/11 Javascript
Javascript函数式编程语言
2015/10/11 Javascript
webpack3之loader全解析
2017/10/26 Javascript
vue-cli 3.0 版本与3.0以下版本在搭建项目时的区别详解
2018/12/11 Javascript
JS实现二维数组元素的排列组合运算简单示例
2019/01/28 Javascript
vue 使用高德地图vue-amap组件过程解析
2019/09/07 Javascript
Python写的PHPMyAdmin暴力破解工具代码
2014/08/06 Python
Python实现统计文本文件字数的方法
2017/05/05 Python
Django实现快速分页的方法实例
2017/10/22 Python
特征脸(Eigenface)理论基础之PCA主成分分析法
2018/03/13 Python
django rest framework vue 实现用户登录详解
2019/07/29 Python
OpenCV python sklearn随机超参数搜索的实现
2020/01/17 Python
CK美国官网:Calvin Klein
2016/08/26 全球购物
波兰香水和化妆品购物网站:Notino.pl
2017/11/07 全球购物
Clarks西班牙官方在线商店:clarks鞋
2019/05/03 全球购物
机械制造与自动化应届生求职信
2013/11/16 职场文书
公司委托书格式范文
2014/04/04 职场文书
给孩子的新年寄语
2014/04/08 职场文书
《特殊的葬礼》教学反思
2014/04/27 职场文书
上班迟到检讨书300字
2014/10/18 职场文书
学习弘扬焦裕禄精神心得体会
2016/01/23 职场文书
文案策划岗位个人自我评价(范文)
2019/08/08 职场文书
nginx简单配置多个server的方法
2021/03/31 Servers
Redis实现订单自动过期功能的示例代码
2021/05/08 Redis