让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 删除记录同时删除图片文件的实现代码
May 12 PHP
php获取从百度搜索进入网站的关键词的详细代码
Jan 08 PHP
yii上传文件或图片实例
Apr 01 PHP
php实现的CSS更新类实例
Sep 22 PHP
ThinkPHP基于PHPExcel导入Excel文件的方法
Oct 15 PHP
PHP中把对象转换为关联数组代码分享
Apr 09 PHP
微信支付PHP SDK之微信公众号支付代码详解
Dec 09 PHP
PHP+MySQL统计该库中每个表的记录数并按递减顺序排列的方法
Feb 15 PHP
PHP中list方法用法示例
Dec 01 PHP
php安装扩展mysqli的实现步骤及报错解决办法
Sep 23 PHP
php封装db类连接sqlite3数据库的方法实例
Dec 19 PHP
php操作mongodb封装类与用法实例
Sep 01 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/10/09 PHP
PHP中防止SQL注入攻击和XSS攻击的两个简单方法
2010/04/15 PHP
PHP读取RSS(Feed)简单实例
2014/06/12 PHP
Yii2框架RESTful API 格式化响应,授权认证和速率限制三部分详解
2016/11/10 PHP
为Yahoo! UI Extensions Grid增加内置的可编辑器
2007/03/10 Javascript
腾讯与新浪的通过IP地址获取当前地理位置(省份)的接口
2010/07/26 Javascript
JavaScript中几种常见排序算法小结
2011/02/22 Javascript
jquery全选/全不选/反选另一种实现方法(配合原生js)
2013/04/07 Javascript
JavaScript数组常用操作技巧汇总
2014/11/17 Javascript
基于Node.js实现nodemailer邮件发送
2016/01/26 Javascript
Adapter适配器模式在JavaScript设计模式编程中的运用分析
2016/05/18 Javascript
Bootstrap 最常用的JS插件系列总结(图片轮播、标签切换等)
2016/07/14 Javascript
详解Sea.js中Module.exports和exports的区别
2017/02/12 Javascript
Js apply方法详解
2017/02/16 Javascript
vue.js多页面开发环境搭建过程
2019/04/24 Javascript
在vue项目中封装echarts的步骤
2020/12/25 Vue.js
python转换字符串为摩尔斯电码的方法
2015/07/06 Python
python 接收处理外带的参数方法
2018/12/03 Python
python根据文章标题内容自动生成摘要的实例
2019/02/21 Python
Django单元测试工具test client使用详解
2019/08/02 Python
python爬虫之爬取百度音乐的实现方法
2019/08/24 Python
pytorch+lstm实现的pos示例
2020/01/14 Python
详解Python3.8+PyQt5+pyqt5-tools+Pycharm配置详细教程
2020/11/02 Python
Coltorti Boutique官网:来自意大利的设计师品牌买手店
2018/11/09 全球购物
Solid & Striped官网:美国泳装品牌
2019/06/19 全球购物
美国第一大药店连锁机构:Walgreens(沃尔格林)
2019/10/10 全球购物
Linux如何压缩可执行文件
2013/10/21 面试题
学习“七一”讲话精神体会
2014/07/08 职场文书
2014年团支书工作总结
2014/11/14 职场文书
工作经验交流材料
2014/12/30 职场文书
团代会邀请函
2015/02/02 职场文书
小学总务工作总结
2015/08/13 职场文书
用Python远程登陆服务器的步骤
2021/04/16 Python
Java并发编程之Executor接口的使用
2021/06/21 Java/Android
css 边框添加四个角的实现代码
2021/10/16 HTML / CSS
postgresql之greenplum字符串去重拼接方式
2023/05/08 PostgreSQL