让php更快的提供文件下载 - 风雪之隅


本站和网页 http://www.laruence.com/2012/05/02/2613.html 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

让PHP更快的提供文件下载 - 风雪之隅
Press "Enter" to skip to content
风雪之隅 左手代码右手诗 open menu
mobile menu toggle button
主页
PHP源码分析
PHP应用
JS/CSS
随笔
留言
博客地图
让PHP更快的提供文件下载
Published on
2 May 2012
by
laruence
作者:
Laruence
-->
本文地址:
https://www.laruence.com/2012/05/02/2613.html
转载请注明出处
一般来说, 我们可以通过直接让URL指向一个位于Document Root下面的文件, 来引导用户下载文件.
但是, 这样做, 就没办法做一些统计, 权限检查, 等等的工作.
于是,
很多时候,
我们采用让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);
但是这个有一个问题, 就是如果文件是中文名的话, 有的用户可能下载后的文件名是乱码.
于是, 我们做一下修改(参考: :
$file = "/tmp/中文名.tar.gz";
$filename = basename($file);
//处理中文文件名
$ua = $_SERVER["HTTP_USER_AGENT"];
$encoded_filename = rawurlencode($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 . '"');
恩, 现在看起来好多了, 不过还有一个问题,
那就是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直接发送这个文件给用户:
//让Xsendfile发送文件
header("X-Sendfile: $file");
X-Sendfile头将被Apache处理, 并且把响应的文件直接发送给Client.
Lighttpd和Nginx也有类似的模块,
大家有兴趣的可以去找找看 🙂
Filed in
PHP
Xsendfile
下载文件
中文文件名
Previous Post
如何为PHP贡献代码
Next Post
PHP的Calling Scope
81 Comments
飛天
April 18, 2020
大佬,请教个问题,为什么通过向360、迅雷等下载工具下载的时候,显示大小为0 ,但是并不影响下载,还是能正常下载,资料也完整的,我想请教下,文件大小怎么和下载工具检测的大小一致呢?尝试了好多方法,都没有成功!
jsoma
March 11, 2019
下载下来文件为0字节
Gonzalo
October 18, 2018
Thanks for finally writing about >让PHP更快的提供文件下载 | 风雪之隅 <Liked it!
《转载》让PHP更快的提供文件下载 – 猫の家
May 30, 2018
[…] 本文地址: http://www.laruence.com/2012/05/02/2613.html […]
徐吉武
March 9, 2017
$file = “/tmp/中文名.tar.gz”;
basename获取中文的文件名获取不到
plansze szkolne
March 10, 2016
If some one desires expert view about blogging afterward i propose him/her to pay a visit this web site, Keep up the nice work.
winter outfits
December 15, 2015
What’s up, for all time i used to check blog posts here in the early hours in the
dawn, because i like to gain knowledge of more and more.
让PHP更快的提供文件下载-APIHTML
November 19, 2015
[…] 文章来源:http://www.laruence.com/2012/05/02/2613.html […]
水平凡’s Blog-APIHTML
nginx+php-fpm环境下php输出图片、js、css等文件出现异常问题的原因及解决办法 | 缺氧空间
September 25, 2015
[…]
http://www.laruence.com/2012/05/02/2613.html
PHP实现文件下载 | 谷子
March 19, 2015
[…] 让PHP更快的提供文件下载
类别 未分类 | […]
Theda
January 11, 2015
Very shortly this web site will be famous amid all blogging and site-building users,
due too it’s fastidious articles or reviews
http://Videosflax.com/
October 4, 2014
Si estamos pensando en adoptar un Rottweiler, contamos
con que tener en consideración que es un cánido de raza
considerada peligrosa.
my web blog
nginx使用XSendfile模块让php更快下载文件实战 – markdream
September 26, 2014
[…] 最近有点闲暇时间了,不小心看了@风雪之隅的一篇的文章《让PHP更快的提供文件下载》后,利用实际项目中的业务场景觉得有必须要去优化附件下载功能了。鸟哥的文章里面主要介绍的基于apache来做XSendfile讲解的,我有点强迫症,我对我的生产环境《顶岗实习管理系统》进行升级改造,我的webserver是nginx,所以基于nginx官方网站的XSendfile说明特做此改造笔记。 […]
使用 Nginx 的 X-Sendfile 机制提升 PHP 文件下载性能 | 脑袋博客
July 31, 2014
[…] Nginx 官方 XSendfile 文档 让PHP更快的提供文件下载 Yii Framework 对 XSendfile 的支持 站长推荐PHP判断字符串中是否含有中文Ubuntu […]
PHP利用Apache,Nginx,Lighttpd的X-sendfile功能提升下载效率 | Jken空间,技术交流,开放共享
May 28, 2014
[…] 让PHP更快的提供文件下载 […]
share112
May 20, 2014
见到一些网站 采用 下载 实体文件加上 token的方式 来下载 如xxxx.mp3?uijsd2342ewijl234, 感觉这种处理方法也能统计
比 X-Sendfile 更直接 些,但也说不上有什么优势。。
如何让PHP文件下载效率更高 | Nice团队官方站点
January 14, 2014
[…] 今天做空号检测系统的结果下载的时候碰到了这个问题。就Google了一番,发现鸟哥的这篇文章不错,果然是大神,哈哈。 […]
Apache2借助X-Sendfile实现文件下载控制 | grace
October 31, 2013
[PHP征文]使用 Nginx 的 X-Sendfile 机制提升 PHP 文件下载性能 - Sina App Engine - 开发者第965088个问答
August 12, 2013
[…] Nginx 官方 XSendfile 文档 让PHP更快的提供文件下载 Yii Framework 对 XSendfile […]
2013 at 4:41 pm
June 22, 2013
Hey! I’m at work surfing around your blog from my new apple iphone! Just wanted to say I love reading through your blog and look forward to all your posts! Keep up the great work!
Luis
May 6, 2013
Very nice article, just what I wanted to find.
I am greatful that you taking a moment to see my information.
You are free to consider a look at my very own web site also for
more information and facts and effective suggestions:
Pest Control Charlotte
May 2, 2013
I know this if off topic but I’m looking into starting my own weblog and was curious what all is required to get set up? I’m assuming having a blog like yours would cost a pretty
penny? I’m not very web smart so I’m not 100% sure. Any suggestions or advice would be greatly appreciated. Appreciate it
I appreciate you currently taking a time period to evaluation my account. You are free to take a glimpse at my personal webpage also for extra info and valuable ideas …
罗迦费升格
January 2, 2013
忽然间跑到大神这里来了。
让PHP更快的提供文件下载 | 种花生的黄土地
December 13, 2012
[…] 并且把响应的文件直接发送给Client. 本文转自 风雪之隅
php 应用PHP文件下载
← PHP生成ZIP文件 用PclZip压缩和解压缩zip文件 […]
21个常用的PHP函数代码段 | 阿飞-justdoit
December 6, 2012
[…] 注:
http://www.laruence.com/2012/05/02/2613.html有关于下载时出现乱码情况的解决办法。
PHP部分 | 刘永飞-justdoit
November 14, 2012
This entry was posted in 有用的集合 by 管理. Bookmark the permalink. […]
[转]让PHP更快的提供文件下载 « Ming BLOG
November 8, 2012
[…] [转]让PHP更快的提供文件下载
作者: Laruence本文地址:
http://www.laruence.com/2012/05/02/2613.html转载请注明出处
让PHP更快的提供文件下载树林/咖啡 成都专业php网站制作 | 树林/咖啡 成都专业php网站制作
October 5, 2012
[…] 风雪之隅 » PHP应用
Posted in: php / Tagged: 让PHP更快的提供文件下载 […]
test
September 11, 2012
大家有试下nginx的X-Accel-Redirect,当文件不存的情况吗,是不是会请求很多次?
September 5, 2012
header(“Location: “.$uri);和该方法的区别何在?
奇言妙事-文学奇谈小小说阅读xlinblog.sinaapp.com » PHP & “Data” URL scheme
August 30, 2012
0xFP
August 22, 2012
对于简单的字符串查找应避免使用正则表达式!
##################################################
// 处理中文文件名
if (strpos($ua, 'MSIE') !== false) {
} else if (strpos($ua, 'Firefox') !== false) {
// 博主的代码有误,这里的文件名需要编码
header("Content-Disposition: attachment; filename*=\"utf8''" . $encoded_filename . '"');
// 注意: 如果文件名包含双引号, 可能会丢失文件名中的第一个双引号开始的内容
// 博主的代码有误,这行代码已被上面那段代替了, 应该注释掉
//header('Content-Disposition: attachment; filename="' . basename($file) . '"');
…
雪候鸟
August 20, 2012
@Anonymous 已更正, thanks
Anonymous
这段更简洁,验证过没问题。
奇言妙事-文学奇谈小小说阅读xlinblog.sinaapp.com » Blog Archive » 让PHP更快的提供文件下载
August 9, 2012
[…] 本文地址:
奇言妙事-文学奇谈小小说阅读xlinblog.sinaapp.com » Blog Archive » Yaf的一些资源
mark35
July 27, 2012
$encoded_filename = urlencode($filename);
$encoded_filename = str_replace(“+”, “%20”, $encoded_filename);
===========================
可否直接用
来替代呢
杨进春
July 16, 2012
…不好意思哈哈。。。去掉if else 下面那条 ——–header(‘Content-Disposition: attachment; filename=”‘ . $filename . ‘”‘); —– 后就正常了。
谢谢博主了哈。
Laruence 您好,我用了你的这段代码,在IE下,中文文件名还是出问题了。IE版本是9.0。谷歌正确
天天
July 11, 2012
以后就来这里学习了!博主很强大
KIVU » Blog Archive » 不经过PHP这层, 直接让Webserver直接把文件发送给用户
July 10, 2012
[…] 来源于http://www.laruence.com/2012/05/02/2613.html […]
小人物 » 让PHP更快的提供文件下载[转]
July 5, 2012
[…] 原文地址:
uffy
July 4, 2012
好文,以后一定用的上
adophper
June 29, 2012
啊!看了回复原来还有不足的地方,前两天做excel导出的时候就遇到中文名了!
dtbsky
June 12, 2012
额,用上了!
0xFP: 请问博主为啥提交内容 "{?PHP 1 ?} {?PHP 2 ?}" ("{"、 "}" 分别为小于号、大于号) 后没显示? 诡异的被过滤了
June 11, 2012
请问博主为啥提交内容 “{?PHP 1 ?} {?PHP 2 ?}” (“{“、 “}” 分别为小于号、大于号) 后没显示? 诡异的被过滤了
Test
0xFP (Reply: kakalong)
晕,代码再次被过滤了
测试代码(PHP 5.4.0-3):
header(‘Content-Type: text/plain’);
header(‘Content-Disposition: attachment; filename*=”UTF-8\’\’this%20is%20a%20filename”‘);
Retry
怪了,测试代码发不上
Firefox 识别出的文件名(Firefox 14.0a2 for linux):
this is a filename
经测试文件名是需要经过 URL 编码
====================================================================
修正代码:
//$encoded_filename = urlencode($filename);
//$encoded_filename = str_replace("+", "%20", $encoded_filename);
//if (preg_match("/MSIE/", $ua)) {
//} else if (preg_match("/Firefox/", $ua)) {
//header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
// 这行代码已被上面的代码代替了, 应该注释掉
//……
d.p
June 8, 2012
大婶你好,我是一个开发新手,刚开始拜读您的文章,你能不能做一篇关于php制作验证码的深度分析?我们网站历经几次验证码修改,到现在防刷效果还算可以,但是用户肉眼识别也变得困难。我看过腾讯的验证码,识别很简单,您能分析下他们这个验证码是怎么做的吗,既保证体验性又防刷?
包头网站建设
June 7, 2012
厉害啊 你是我的偶像
让PHP更快的提供文件下载(转) | 南门有只猫 | Blog
June 5, 2012
[…] 转自:
此条目是由 admin 发表在 PHP 分类目录的。将固定链接加入收藏夹。 […]
Chon81
June 4, 2012
无法判断是否支持是个问题呀.
kakalong
reply 0xFP:
1.博主处理firefox部分代码没有错误,确实不要用url编码
2.文件名是不允许有引号的,所以你的else里面多虑了
我觉得
可以换为rawurlencode
太阳镜品牌排名
May 29, 2012
这个太高深了,我点看不明白
0xFP (Fix Bug)
May 25, 2012
if (preg_match(“/MSIE/”, $ua)) {
header(‘Content-Disposition: attachment; filename=”‘ .$encoded_filename . ‘”‘);
} else if (preg_match(“/Firefox/”, $ua)) {
// 博主的代码有误,这里的文件名需经过 URL 编码
header(“Content-Disposition: attachment; filename*=\”utf8”” . $encoded_filename . ‘”‘);
// 这里如何处理文件名包含双引号的情况?
header(‘Content-Disposition: attachment; filename=”‘ . $filename . ‘”‘
);
Nokia
May 22, 2012
nginX的类似模块是:
http://wiki.nginx.org/NginxXSendfile
if (preg_match(“/Firefox/”, $ua)) {
// 这里的 $filename 也需要经过 RFC1738 的 URL Encoding
header(“Content-Disposition: attachment; filename*=\”utf8”” . $filename . ‘”‘);
// 如果 $filename 包含 `”‘ 会导致文件名部分丢失
header(‘Content-Disposition: attachment; filename=”‘ . $filename . ‘”‘);
让PHP更快的提供文件下载 | 花 生
May 11, 2012
标签:PHP文件下载
上一篇:PHP生成ZIP文件 […]
wclssdn
May 9, 2012
额.. 看到有人说通过PHP函数获取apache模块列表了.
不知道其他服务端软件是不是这种方式..
如何判断apache是否支持那个X-Sendfile…
[转] 让PHP更快的提供文件下载 | 风中了了也
lly
学习了。。
yegle
这个方案的好处是默认就支持断点续传了
另一个好处是,可以实现对静态文件的ACL访问控制
不过悲剧的是手头的虚拟主机不提供mod_xsendfile…
leoliu
鸟哥
foreach($arr AS $i){
echo <<<HTML
$i
HTML;
syntax error, unexpected $end
这个报错是什么原因
借助X-sendfile模块实现文件下载速度和性能优化方案 « 技术支持和经验交流分享型博客
May 4, 2012
[…]    php5.4新功能Traits »
借助X-sendfile模块实现文件下载速度和性能优化方案 本文的灵感来自于:让PHP更快的提供文件下载 […]
stou
恩,非常不错的做法,刚刚尝试可以正常运行。
十一文
请问哈鸟哥,如果这个要求支持断点续传了?怎么改进
tanglement
呃,不熟悉php,但是这样不会增加产品对环境的依赖么?如果做迁移,就会有代码修改的成本吧。
wamper
May 3, 2012
Apache的Sendfile模块好像是需要另外安装的,所以可能并不是很通用,我之前的框架里边就采用了这种方法,
$contentType = $contentType ? $contentType : ‘application/octet-stream’;
header(“Pragma:public”);
header(“Expires:0”);
header(“Content-type:” . $contentType . ‘;charset=UTF-8’);
header(“Accept-Ranges:bytes”);
$charset = Config::get(‘charset’);
if ($charset != ‘UTF-8’) {
$mbEncodings = array(‘GBK’=>’CP936’, ‘GB2312’=>’CP936’);
if(isset($mbEncodings[$charset])) $charset = $mbEncodings[$charset];
$fileName = mb_convert_encoding($fileName, $charset, ‘UTF-8’);
if (” != $fileCfg[‘contents’]) {
ob_clean();
$fileSize = strlen($fileCfg[‘contents’]);
} else if (” != $fileCfg[‘filepath’]){
$fileSize = filesize($fileCfg[‘filepath’]);
if($fileSize > 0)
header(“Accept-Length:”.$fileSize);
$ua = $_SERVER[‘HTTP_USER_AGENT’];
if(preg_match(‘/firefox/i’, $ua)) {
$fileName = str_replace(‘+’, ‘%20’, urlencode($fileName));
$fileName = “utf8”” . $fileName;
header(“Content-Disposition:attachment; filename*=\”{$fileName}\””);
} else if(preg_match(‘/msie/i’, $ua)){
header(“Content-Disposition:attachment; filename=\”{$fileName}\””);
echo $fileCfg[‘contents’];
} else if(” != $fileCfg[‘filepath’]) {
$serverSoft = $_SERVER[‘SERVER_SOFTWARE’];
if(preg_match(‘/apache/i’, $serverSoft)) {
readfile($fileCfg[‘filepath’]);
} else if (preg_match(‘/lighttpd/i’, $serverSoft)) {
header(‘X-LIGHTTPD-Send-file:’ . $fileCfg[‘filepath’]);
} else if (preg_match(‘/nginx/i’, $serverSoft)) {
$nginxSendfileMaps = Config::get(‘NGINX_SENDFILE_MAP’);
if(false == $nginxSendfileMaps) {
$filePath = $fileCfg[‘filepath’];
foreach($nginxSendfileMaps as $map) {
if(0 === strpos($filePath, $map[0])) {
$filePath = str_replace($map[0], $map[1], $filePath);
break;
header(‘X-Accel-Redirect:’ . $filePath);
Gang
May 2, 2012
呃…好吧,不支持代码片段,代码也被截断了,看这里吧
http://pastie.org/3848723
鸟哥写的很好,小弟在这里也班门弄斧一下,一个从Ruby On Rails中迁移过来的send_file()方法,具体使用参见
http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_file
[code=’php’]
‘application/octet-stream’,
‘disposition’ => ‘attachment’
$options = array_merge($defaults, $options);
foreach (array(‘type’, ‘disposition’) as $arg) {
if (is_null($options[$arg])) {
throw new InvalidArgumentException(“{$arg} option required”);
$disposition = $options[‘disposition’];
if (isset($options[‘filename’])) {
$disposition .= “; filename=\”{$options[‘filename’]}\””;
if (! headers_sent()) {
header(“Content-Type: {$options[‘type’]}”);
header(“Content-Disposition: {$disposition}”);
header(“Content-Transfer-Encoding: binary”);
$x_sendfile_supported = $options[‘x_sendfile’] && in_array(‘mod_xsendfile’, apache_get_modules());
if (! headers_sent() && $x_sendfile_supported) {
header(“X-Sendfile: {$path}”);
@readfile($path);
?>
[/code]
轩脉刃
原来还有这么个好东西,查了下:
nginx的模块是:http://wiki.nginx.org/XSendfile
shirne
nginx的是这个吧
http://wiki.nginx.org/X-accel
我试了下,可以用
header(‘Content-Disposition: attachment; filename=”test.zip”‘);
#http://wiki.nginx.org/X-accel
header(‘X-Accel-Redirect:/test.zip’);
流氓
大牛哥, 你好
最近遇到一个mysql索引的很离奇的问题
create table t1(x char(10), y char(10), key hs using(x,y))
describe select * from t1 where x>’dfd’
显示查询使用了索引并且type为range
我不明白为什么hash索引会有这样的行为, 去百度, google, 各大论坛仔细找了都没结果
非常希望能得到你的帮助, 谢谢
anylzer
android系统的浏览器上中文名的文件的下载多有问题
GaRY
为啥PHP不调用系统底层sendfile调用?直接省掉open,read,write的内核上下文切换。相对会好一点, webserver就做了这些。
treesky
不错,以前readfile的时候就总害怕文件太大出问题。回家测试测试。
Comments are closed.
Sidebar
开发组核心成员,
Zend
顾问, PHP7及PHP8 JIT核心作者. Yaf等开源项目作者.
Search
开源项目
Yaf
:  PHP Framework in PHP extension
Yar
:  Light, concurrent RPC framework
Yac
:  PHP Contents cache
Yaconf
:  PHP Configurations Container
Taint
:  XSS code sniffer
Lua
:  Embedded lua interpreter
MsgPack
:  MessagePack in PHP extension
Couchbase
:  Libcouchbase wrapper
See also:  
laruence@github
最新评论
Hengist Wang
on
关于调用约定(cdecl、fastcall、stcall、thiscall) 的一点知识
拍黄瓜
PHP 8新特性之Attributes(注解)
陶路
博客迁移到腾讯云
tattvamretreat
深入理解Zend SAPIs(Zend SAPI Internals)
Sobha Town Park
PHP 8新特性之JIT简介
个人公众号
标签
Apache
apc
bug
C++
core
curl
Extension
IE
javascript
js
json
mysql
nginx
opcache
Performance
PHP5.4
PHP5.4新特性
PHP7
PHP8
PHP 8
PHP extension
php原理
PHP扩展
php源码
php源码分析
SAPI
session
valgrind
vim
yac
Yaf_Loader
zval
优化
低概率core
内核
原理
开发php扩展
性能
性能优化
扩展开发
正则
分类
Select Category
GNU C/C++  (11)
Js/CSS  (24)
Linux/Unix  (15)
MySQL/PostgreSQL  (7)
PHP Extension  (19)
PHP7  (9)
PHP8  (5)
PHP应用  (188)
PHP源码分析  (86)
转载  (34)
随笔  (111)
Links
Licence
Sitemaps
Site Feed
Yaf Manual
SSE Intrinsics Guide
X86 Instruction Reference
Realsee
访客地图
©
博客声明
京ICP备15032766号
PHP 8.1.0-NTS(JIT)
/ Theme By
Compete Themes