在微博上偶然看到一篇介绍php更快下载文件的方法,其实就是利用web服务器的xsendfile特性,鸟哥的博客中只说了apache的实现方式,我找到了介绍nginx实现方式的文章,整理一下!

let's go!

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

nginx中也有对应的xsendfile模块,默认已经包含了senfile模块了,你如果安装完nginx你会在nginx.conf文件会看到“sendfile on;”

配置部分:

server {
listen 80;
server_name demo.markdream.com; root /var/vhost/demo;
index index.php; # 这个是定义读取你的文件的目录的url开头 直接访问是不可以的 只能通过
location /protected {
internal;
alias /var/vhost/demo/uploadfiles;
} location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
}
}

downloads.php

<?php

//eg: http://demo.markdream.com/xsendfile/downloads.php?filename=hello.docx

// 获取文件名
$filename = $_GET["filename"]; // 你可以在这里写下你的查询数据库等你所想的功能 …… header ( "Content-type: application/octet-stream" );
// 处理中文文件名
$ua = $_SERVER ["HTTP_USER_AGENT"];
if (preg_match ( "/MSIE/", $ua )) {
$encoded_filename = rawurlencode ( $filename );
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 . '"' );
} // 就这么简单一句话搞定 注意“protected”是和nginx配置文件的 protected要一致
header("X-Accel-Redirect: /protected/" . $filename); ?>

这里是使用的别名的方式,也可以使用直接访问的方式,具体看nginx官网的关于xsendfile的说明,一看就懂了!

参考和摘抄:

1.鸟哥:http://www.laruence.com/2012/05/02/2613.html

2.nginx 实现:https://www.markdream.com/technologies/programs/nginx-x-accel- redirect-php-practise.shtml?utm_source=tuicool&utm_medium=referral

3.nginx xsendfile官网说明:http://wiki.nginx.org/XSendfile

php提供更快的文件下载的更多相关文章

  1. 如何为终端用提供更快的解决方案?让IT技术员具备更高的效率?

  2. SharePoint 2010中使用SPListItemCollectionPosition更快的结果

    转:http://www.16kan.com/article/detail/318657.html Introduction介绍 In this article we will explore the ...

  3. 更快的Maven来了,我的天,速度提升了8倍!

    周末被 maven-mvnd 刷屏了,于是我也下载了一个 mvnd 体验了一把.虽然测试的数据都是基于我本地项目,不具备普适性和权威性,但也足以说明问题.它的测试结果远远超出我的预期,下面一起来看. ...

  4. 更快的Maven构建工具mvnd和Gradle哪个更快?

    Maven 作为经典的项目构建工具相信很多人已经用很久了,但如果体验过 Gradle,那感觉只有两个字"真香". 前段时间测评了更快的 Maven 构建工具 mvnd,感觉性能挺高 ...

  5. 海量数据分析更快、更稳、更准。GaussDB(for MySQL) HTAP只读分析特性详解

    本文作者康祥,华为云数据库内核开发工程师,研究生阶段主要从事SPARQL查询优化相关工作.目前在华为公司参与华为云GaussDB(for MySQL) HTAP只读内核功能设计和研发. 1. 引言 H ...

  6. QList介绍(QList比QVector更快,这是由它们在内存中的存储方式决定的。QStringList是在QList的基础上针对字符串提供额外的函数。at()操作比操作符[]更快,因为它不需要深度复制)非常实用

    FROM:http://apps.hi.baidu.com/share/detail/33517814 今天做项目时,需要用到QList来存储一组点.为此,我对QList类的说明进行了如下翻译. QL ...

  7. 更轻更快的Vue.js 2.0与其他框架对比(转)

    更轻更快的Vue.js 2.0 崭露头角的JavaScript框架Vue.js 2.0版本已经发布,在狂热的JavaScript世界里带来了让人耳目一新的变化. Vue创建者尤雨溪称,Vue 2.0  ...

  8. 精通Web Analytics 2.0 (9) 第七章:失败更快:爆发测试与实验的能量

    精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第七章:失败更快:爆发测试与实验的能量 欢迎来到实验和测试这个棒极了的世界! 如果Web拥有一个超越所有其他渠道的巨大优势,它就 ...

  9. ubuntu 12.04 LTS 如何使用更快的更新源

    装好ubuntu系统后的第一见事就是替换自带的更新源,原因是系统自带的源有些在中国访问不了,可以访问的速度又特别慢.幸好国内的一些公司和大学提供了速度不错的更新源.下面介绍如何使用更快的更新源 方法/ ...

随机推荐

  1. 开发人员必读openstack网络基础

    云计算中的网络非常复杂,需要对网络的基础理论有一定的认识和了解,转载网上针对openstack中涉及到网络概念的文章 开发人员必读openstack网络基础1:什么是L2.L3 开发人员必读opens ...

  2. Vim自动补全神器–YouCompleteMe

    一.简介 YouCompleteMe是Vim的自动补全插件,与同类插件相比,具有如下优势 1.基于语义补全 2.整合实现了多种插件 clang_complete.AutoComplPop .Super ...

  3. Memcached在windows下安装与使用

    建议:windows系统下仅为测试所有,生产环境下服务端应使用Linux系统. 本文最后更新于:2014-08-03 18:24 原文:http://www.yaosansi.com/post/mem ...

  4. Kibana+Logstash+Elasticsearch 日志查询系统

    搭建该平台的目的就是为了运维.研发很方便的进行日志的查询.Kibana一个免费的web壳:Logstash集成各种收集日志插件,还是一个比较优秀的正则切割日志工具:Elasticsearch一个开源的 ...

  5. 好压(HaoZip)的命令行模式用法介绍

    好压压缩软件,又叫“2345好压”,是一款国产的优秀压缩软件,目前是免费的,据官网介绍,该软件永久免费.官网地址:http://haozip.2345.com/ 本文主要对该软件的命令行模式用法进行介 ...

  6. spark dataframe unionall

    今天本来想写一个spark dataframe unionall的demo,由于粗心报下面错误: Exception in thread "main" org.apache.spa ...

  7. MIT研发的新型匿名网络Riffle,下一个Tor

    现在的隐私问题是一个网络热词,如果你担心你上网的隐私会泄露,最有效的解决办法就是使用Tor.这款免费的匿名通信软件,能够让人们在与其他人通信时隐藏自己真实的信息. 虽然Tor是一个很好的匿名网络系统, ...

  8. codevs 2924 数独挑战

    2924 数独挑战 http://codevs.cn/problem/2924/ 题目描述 Description "芬兰数学家因卡拉,花费3个月时间设计出了世界上迄今难度最大的数独游戏,而 ...

  9. 如何重新划分linux分区大小

    1.下载脚本文件,将脚本文件内容复制 chmod +x resize.sh sudo ./resize.sh 输入上面命令后会看到下面的结果 root@odroid:~# sudo ./resize. ...

  10. Matlab

    Q:workspace没有显示变量的值 A:这是因为子程序里的变量是局部变量,他们的作用域就是子函数内部,会在流程控制回到主调函数前被系统自动释放掉,所以,一旦子程序运行完,你是不可能再查看子程序里的 ...