在PHP中使用X-SendFile头让文件下载更快


Posted in PHP onJune 01, 2014

一般来说, 我们可以通过直接让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);

但是这个有一个问题, 就是如果文件是中文名的话, 有的用户可能下载后的文件名是乱码.

于是, 我们做一下修改:

<?php
    $file = "/tmp/中文名.tar.gz";    $filename = basename($file);
    header("Content-type: application/octet-stream");
    //处理中文文件名
    $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 . '"');
    }
    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 = 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 . '"');
    }
    //让Xsendfile发送文件
    header("X-Sendfile: $file");

X-Sendfile头将被Apache处理, 并且把响应的文件直接发送给Client.

Lighttpd和Nginx也有类似的模块, 大家有兴趣的可以去找找看

PHP 相关文章推荐
PHP的array_diff()函数在处理大数组时的效率问题
Nov 27 PHP
smarty基础之拼接字符串的详解
Jun 18 PHP
PHP对象相互引用的内存溢出实例分析
Aug 28 PHP
php之curl设置超时实例
Nov 03 PHP
php实现猴子选大王问题算法实例
Apr 20 PHP
WordPress中注册菜单与调用菜单的方法详解
Dec 18 PHP
PHP7之Mongodb API使用详解
Dec 26 PHP
php实现base64图片上传方式实例代码
Feb 22 PHP
php文件上传类的分享
Jul 06 PHP
PDO::commit讲解
Jan 27 PHP
PHP中“=&gt;
Mar 01 PHP
php 中的信号处理操作实例详解
Mar 04 PHP
PHP is_subclass_of函数的一个BUG和解决方法
Jun 01 #PHP
PHP中数组的分组排序实例
Jun 01 #PHP
php_screw安装使用教程(另一个PHP代码加密实现)
May 29 #PHP
PHP Curl出现403错误的解决办法
May 29 #PHP
PHP的foreach中使用引用时需要注意的一个问题和解决方法
May 29 #PHP
神盾加密解密教程(一)PHP变量可用字符
May 28 #PHP
CI框架开发新浪微博登录接口源码完整版
May 28 #PHP
You might like
一些操作和快捷键的理解和讨论
2020/03/04 星际争霸
PHP中文URL编解码(urlencode()rawurlencode()
2010/07/03 PHP
php流量统计功能的实现代码
2012/09/29 PHP
编写安全 PHP应用程序的七个习惯深入分析
2013/06/08 PHP
解析centos中Apache、php、mysql 默认安装路径
2013/06/25 PHP
从零开始学YII2框架(一)通过Composer安装Yii2框架
2014/08/20 PHP
ThinkPHP在新浪SAE平台的部署实例
2014/10/31 PHP
PHP生成随机字符串(3种方法)
2015/09/25 PHP
php微信公众号开发(3)php实现简单微信文本通讯
2016/12/15 PHP
PHP检查URL包含特定字符串实例方法
2019/02/11 PHP
jQuery 获取对象 基本选择与层级
2010/05/31 Javascript
js 输出内容到新窗口具体实现代码
2013/05/31 Javascript
Angular 应用技巧总结
2016/09/14 Javascript
Node.js使用gm拼装sprite图片
2017/07/04 Javascript
浅谈vue路径优化之resolve
2017/10/13 Javascript
webpack将js打包后的map文件详解
2018/02/22 Javascript
JavaScript继承的特性与实践应用深入详解
2018/12/30 Javascript
v-slot和slot、slot-scope之间相互替换实例
2020/09/04 Javascript
全局安装 Vue cli3 和 继续使用 Vue-cli2.x操作
2020/09/08 Javascript
python+requests+unittest API接口测试实例(详解)
2017/06/10 Python
Python+selenium实现截图图片并保存截取的图片
2018/01/05 Python
在Python 中实现图片加框和加字的方法
2019/01/26 Python
python @classmethod 的使用场合详解
2019/08/23 Python
python读取word 中指定位置的表格及表格数据
2019/10/23 Python
Python values()与itervalues()的用法详解
2019/11/27 Python
Python3 A*寻路算法实现方式
2019/12/24 Python
Django Admin后台添加数据库视图过程解析
2020/04/01 Python
关于老式浏览器兼容HTML5和CSS3的问题
2016/06/01 HTML / CSS
受希腊女神灵感的晚礼服、鸡尾酒礼服和婚纱:THEIA
2018/04/15 全球购物
美国知名眼镜网站:Target Optical
2020/04/04 全球购物
2014端午节活动策划方案
2014/01/27 职场文书
教师现实表现材料
2014/02/14 职场文书
大学生简短的自我评价
2014/09/12 职场文书
2014房屋登记授权委托书
2014/10/13 职场文书
拉贝日记观后感
2015/06/05 职场文书
2015年学校总务工作总结
2015/07/20 职场文书