Nginx和apache服务下载大文件,PHP X-sendfile扩展实现文件下载

网站中下载文件是一个经常用到的功能,可是看起来很简单的,做的时候各种问题出现,内心崩溃的有没有。。。

不多说我们进入正题

 

往往网上答案千篇一律是这样的:

//源文件路径 
$thefile='test.text'; 

//文件下载 
$fileinfo = pathinfo($filename); 
header('Content-type: application/x-'.$fileinfo['extension']);
header('Content-Disposition: attachment; 
filename='.$fileinfo['basename']);
header('Content-Length: '.filesize($filename));
readfile($thefile); exit();


或是这样的

//源文件路径
$thefile='test.text';
$filename=$thefile;
$file  =  fopen($filename, "rb");
Header( "Content-type:  application/octet-stream ");
Header( "Accept-Ranges:  bytes ");
Header( "Content-Disposition:  attachment;  filename= 4.doc");
$contents = "";
while (!feof($file)) {
    $contents .= fread($file, 8192);
}
fclose($file);

 

以上下载小文件完全没有问题,但是我要的是下载大文件,大文件,大文件,你就粘贴给我看这个???

于是我放弃了 某度,用了google。

 

1.首先 打开php.ini 查找 memory_limit  修改 你想占用内存,我服务器内存大所以调的高,看情况调整。

memory_limit = 1024M

好了我们来试试下载大文件

$file = fopen($file_dir,"r"); 

// 输入文件标签
Header("Content-type: application/octet-stream");
Header("Accept-Ranges: bytes");Header("Accept-Length: ".filesize($file_dir));
Header("Content-Disposition: attachment;
filename=" . $attach['name']);

// 输出文件内容
echo fread($file,filesize($file_dir));
fclose($file);
exit();

真的能下载几百兆文件了,好开心。但是我的网站怎么打不开了呢?what?什么鬼?你玩我吧?崩溃的边缘

 

好吧!我发现个问题:

这种方式可以实现文件的下载,但是这种下载方式相当耗资源,长期占用服务端脚本资源和服务器内存资源,消耗很大。 

php函数下载文件把php内存占用完了,怎么解决?

 

查阅资料,我们可以借助X-sendfile模块来实现更高效率的文件下载。 
 X-sendfile是现代操作系统支持的一种高性能网络IO方式,服务端脚本程序比如php负责构造请求头信息,然后下载的时候不需要php参与,web服务器直接处理X-Sendfile头信息,并且把响应的文件直接发送给浏览器客户端;这样避免了内存占用。

Nginx

Demo下载

<?php
/*
 * 使用说明:
 * 以phpStudy环境为例子
 * 在 Nginx 的配置文件 'vhosts.conf' 中修改,如没有vhosts.conf请在nginx.conf 中设置
 * 在对应的网站 server 中加入 "location"
server {

}

location /data/ {
    internal;   #禁止直接访问资源文件,如果要让正常访问请在 internal 前加上 # 号。
    alias	E:\dome\XSendfile\static\;  #挂载虚拟目录,"E:\dome\XSendfile\static\" 为真实存在的目录,"/data/"为虚拟网站目录
}
#也可以不使用虚拟目录
location /static/ {
    internal;   #禁止直接访问资源文件,如果要让正常访问请在 internal 前加上 # 号。
    root	E:\dome\;  #网站根目录
}

实例:
server {
    listen       80;
    server_name  127.0.0.2
    #####
    ~我省略就不写了~
    #####
    location /data/ {
        internal;
        alias	E:\dome\XSendfile\static\;
    }
}

!!!!配置完重启服务!!!
*/


//文件地址
$realPath = "/data/test_img.jpg";
//测试限速100KB
NginxDownloadFile($realPath,'', 100);

/**
 * @param string $realPath 文件路径
 * @param string $fileName 文件名,默认自动获取文件路径的文件名称
 * @param int $rate 下载速度限制Kb计算,默认1M/s, 0为不限速
 */
function NginxDownloadFile($realPath,$fileName='',$rate=1024){

    if (!$fileName){
        //获取文件名并处理文件名称
        $fileName = basename($realPath);
    }
    //处理ie中文文件名,避免文件名乱码
    $encoded_filename = rawurlencode($fileName);

    $ua = $_SERVER["HTTP_USER_AGENT"];
    header('Content-type: application/octet-stream');
    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-Accel-Redirect: ' . $realPath);

    //限制下载速度 按字节计算 100KB = 1024 * 100,为0不限速
    if($rate){
        header('X-Accel-Limit-Rate: ' . 1024 * $rate);
    }
    //是否开启缓冲 yes|no
    //header('X-Accel-Buffering: yes' );
    //字符集
    //header('X-Accel-Charset: utf-8' );
    exit;
}

 

Apache

首先我们要查看Apache的版本信息:phpinfo();

然后下载对应的X-sendfile模块包(下载地址:https://github.com/nmaier/mod_xsendfile)。

Linux安装方法:

我的是centos

参考地址:http://blogs.isb.bj.edu.cn/miles/2014/02/20/installing-mod_xsendfile-on-centos-6/

yum install mod_xsendfile

1.打开如下路劲,里面有个xsendfile.conf(前提是你安装mod成功后)

> cd /etc/httpd/conf.modules.d

2.vi打开xsendfile.conf,添加如下两行,保存退出(:wq),重启httpd(systemctl restart httpd)

 

windows安装方法

1、将解压出来的mod_xsendfile.so文件拷贝到Apache的modules目录下,一定要选择相应的版本24就是2.4,22就是2.2


2、配置Apache的conf目录下的httpd.conf文件,加入以下代码:

LoadModule xsendfile_module modules/mod_xsendfile.so

XSendFile on
XSendFilePath F:/网站路径(或你的文件目录)

3、重启Apache服务,重启成功。

这些工作完成之后我们就可以借助X-sendfile来实现文件下载了:

$ua = $_SERVER["HTTP_USER_AGENT"];

$filename = $attach['name'];
$encoded_filename = urlencode($filename);
$encoded_filename = str_replace("+", "%20", $encoded_filename);

// 输入文件标签
$realpath =  realpath($file_dir);
header('Content-Type: application/octet-stream');


//处理中文文件名,避免文件名乱码
$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: $realpath");
exit();

 

好激动赶紧试试,下载大文件没问题,网站可以正常访问,要的就是这效果,嘎嘎嘎。

吐槽一下:某度很多都是复制粘贴一个字不多一个字不少,一毛一样,关键是他还没试过这代码有没有用,我真不知道这有什么意思

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值