让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 多维数组排序(usort,uasort)
Jun 30 PHP
PHP安全的URL字符串base64编码和解码
Jun 19 PHP
php数组随机排序实现方法
Jun 13 PHP
php里array_work用法实例分析
Jul 13 PHP
PHP的APC模块实现上传进度条
Oct 27 PHP
PHP实现从上往下打印二叉树的方法
Jan 18 PHP
PHP实现APP微信支付的实例讲解
Feb 10 PHP
thinkPHP框架整合tcpdf插件操作示例
Aug 07 PHP
PHP使用SOAP调用API操作示例
Dec 25 PHP
解决在laravel中auth建立时候遇到的问题
Oct 15 PHP
yii框架结合charjs统计上一年与当前年数据的方法示例
Apr 04 PHP
PHP实现Snowflake生成分布式唯一ID的方法示例
Aug 30 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实现多服务器共享SESSION数据的方法
2007/03/16 PHP
用phpmyadmin更改mysql5.0登录密码
2008/03/25 PHP
php函数array_merge用法一例(合并同类数组)
2013/02/03 PHP
自己写了一个php检测文件编码的函数
2014/04/21 PHP
php解析http获取的json字符串变量总是空白null
2015/03/02 PHP
ecshop后台编辑器替换成ueditor编辑器
2015/03/03 PHP
Zend Framework自定义Helper类相关注意事项总结
2016/03/14 PHP
ThinkPHP 在阿里云上的nginx.config配置实例详解
2017/10/11 PHP
JS option location 页面跳转实现代码
2008/12/27 Javascript
jQuery下扩展插件和拓展函数的写法(匿名函数使用的典型例子)
2010/10/20 Javascript
Jquery 表单验证类介绍与实例
2013/06/09 Javascript
IE中getElementsByName()对有些元素无效的解决方案
2014/09/28 Javascript
JS面向对象(3)之Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法
2016/02/25 Javascript
bootstrap中的 form表单属性role=&quot;form&quot;的作用详解
2017/01/20 Javascript
详解AngularJS中$filter过滤器使用(自定义过滤器)
2017/02/04 Javascript
jQuery插件HighCharts绘制简单2D折线图效果示例【附demo源码】
2017/03/21 jQuery
VUE中使用Vue-resource完成交互
2017/07/21 Javascript
js实现图片放大展示效果
2017/08/30 Javascript
JavaScript实现图片拖曳效果
2017/09/08 Javascript
Node.js自定义实现文件路由功能
2017/09/22 Javascript
小程序scroll-view安卓机隐藏横向滚动条的实现详解
2019/05/16 Javascript
JQuery发送ajax请求时中文乱码问题解决
2019/11/14 jQuery
[06:59]DOTA2-DPC中国联赛3月7日Recap集锦
2021/03/11 DOTA
数据清洗--DataFrame中的空值处理方法
2018/07/03 Python
Python使用matplotlib实现基础绘图功能示例
2018/07/03 Python
Python计算两个矩形重合面积代码实例
2019/09/16 Python
TensorFlow tensor的拼接实例
2020/01/19 Python
python手写均值滤波
2020/02/19 Python
Python Flask上下文管理机制实例解析
2020/03/16 Python
德国柯吉澳趣味家居:Koziol
2017/08/24 全球购物
Snapfish爱尔兰:在线照片打印和个性化照片礼品
2018/09/17 全球购物
彪马土耳其官网:PUMA土耳其
2019/07/14 全球购物
活动总结格式范文
2014/04/26 职场文书
大学团日活动新闻稿
2014/09/10 职场文书
社区个人对照检查材料(群众路线)
2014/09/26 职场文书
P站美图推荐——变身女主角特辑
2022/03/20 日漫