分享一个超好用的php header下载函数


Posted in PHP onJanuary 31, 2014
<?php
/**
 * 发送文件
 *
 * @author: legend(legendsky@hotmail.com)
 * @link: http://www.ugia.cn/?p=109
 * @description: send file to client
 * @version: 1.0
 *
 * @param string   $fileName      文件名称或路径
 * @param string   $fancyName     自定义的文件名,为空则使用filename
 * @param boolean  $forceDownload 是否强制下载
 * @param integer  $speedLimit    速度限制,单位为字节,0为不限制,不支持windows服务器
 * @param string   $$contentType  文件类型,默认为application/octet-stream
 *
 * @return boolean
 */
function sendFile($fileName, $fancyName = '', $forceDownload = true, $speedLimit = 0, $contentType = '')
{
    if (!is_readable($fileName))
    {
        header("HTTP/1.1 404 Not Found");
        return false;
    }
    $fileStat = stat($fileName);
    $lastModified = $fileStat['mtime'];
    $md5 = md5($fileStat['mtime'] .'='. $fileStat['ino'] .'='. $fileStat['size']);
    $etag = '"' . $md5 . '-' . crc32($md5) . '"';
    header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $lastModified) . ' GMT');
    header("ETag: $etag");
    if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModified)
    {
        header("HTTP/1.1 304 Not Modified");
        return true;
    }
    if (isset($_SERVER['HTTP_IF_UNMODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_UNMODIFIED_SINCE']) < $lastModified)
    {
        header("HTTP/1.1 304 Not Modified");
        return true;
    }
    if (isset($_SERVER['HTTP_IF_NONE_MATCH']) &&  $_SERVER['HTTP_IF_NONE_MATCH'] == $etag)
    {
        header("HTTP/1.1 304 Not Modified");
        return true;
    }
    if ($fancyName == '')
    {
        $fancyName = basename($fileName);
    }
    if ($contentType == '')
    {
        $contentType = 'application/octet-stream';
    }
    $fileSize = $fileStat['size'];   
    $contentLength = $fileSize;
    $isPartial = false;
    if (isset($_SERVER['HTTP_RANGE']))
    {
        if (preg_match('/^bytes=(d*)-(d*)$/', $_SERVER['HTTP_RANGE'], $matches))
        {    
            $startPos = $matches[1];
            $endPos = $matches[2];
            if ($startPos == '' && $endPos == '')
            {
                return false;
            }
            if ($startPos == '')
            {
                $startPos = $fileSize - $endPos;
                $endPos = $fileSize - 1;
            }
            else if ($endPos == '')
            {
                $endPos = $fileSize - 1;
            }
            $startPos = $startPos < 0 ? 0 : $startPos;
            $endPos = $endPos > $fileSize - 1 ? $fileSize - 1 : $endPos;
            $length = $endPos - $startPos + 1;
            if ($length < 0)
            {
                return false;
            }
            $contentLength = $length;
            $isPartial = true;
        }
    }
    // send headers
    if ($isPartial)
    {
        header('HTTP/1.1 206 Partial Content');
        header("Content-Range: bytes $startPos-$endPos/$fileSize");
    }
    else
    {
        header("HTTP/1.1 200 OK");
        $startPos = 0;
        $endPos = $contentLength - 1;
    }
    header('Pragma: cache');
    header('Cache-Control: public, must-revalidate, max-age=0');
    header('Accept-Ranges: bytes');
    header('Content-type: ' . $contentType);
    header('Content-Length: ' . $contentLength);
    if ($forceDownload)
    {
        header('Content-Disposition: attachment; filename="' . rawurlencode($fancyName). '"');//汉字自动转为URL编码
  header('Content-Disposition: attachment; filename="' . $fancyName. '"');
    }
    header("Content-Transfer-Encoding: binary");
    $bufferSize = 2048;
    if ($speedLimit != 0)
    {
        $packetTime = floor($bufferSize * 1000000 / $speedLimit);
    }
    $bytesSent = 0;
    $fp = fopen($fileName, "rb");
    fseek($fp, $startPos);
    //fpassthru($fp);
    while ($bytesSent < $contentLength && !feof($fp) && connection_status() == 0 )
    {
        if ($speedLimit != 0)
        {
            list($usec, $sec) = explode(" ", microtime()); 
            $outputTimeStart = ((float)$usec + (float)$sec);
        }
        $readBufferSize = $contentLength - $bytesSent < $bufferSize ? $contentLength - $bytesSent : $bufferSize;
        $buffer = fread($fp, $readBufferSize);        
        echo $buffer;
        ob_flush();
        flush();
        $bytesSent += $readBufferSize;
        if ($speedLimit != 0)
        {
            list($usec, $sec) = explode(" ", microtime()); 
            $outputTimeEnd = ((float)$usec + (float)$sec);
            $useTime = ((float) $outputTimeEnd - (float) $outputTimeStart) * 1000000;
            $sleepTime = round($packetTime - $useTime);
            if ($sleepTime > 0)
            {
                usleep($sleepTime);
            }
        }
    }
    
    return true;
}
 ?>
PHP 相关文章推荐
Oracle 常见问题解答
Oct 09 PHP
phpMyAdmin 安装配置方法和问题解决
Jun 08 PHP
几个实用的PHP内置函数使用指南
Nov 27 PHP
PHP面向对象自动加载机制原理与用法分析
Oct 14 PHP
php使用file函数、fseek函数读取大文件效率对比分析
Nov 04 PHP
php 二维数组时间排序实现代码
Nov 19 PHP
PHP面向对象程序设计类的定义与用法简单示例
Dec 27 PHP
浅谈ThinkPHP中initialize和construct的区别
Apr 01 PHP
php简单生成一组与多组随机字符串的方法
May 09 PHP
Laravel 5.4.36中session没有保存成功问题的解决
Feb 19 PHP
PHP下载文件函数与用法示例
Sep 27 PHP
TP5框架model常见操作示例小结【增删改查、聚合、时间戳、软删除等】
Apr 05 PHP
preg_match_all使用心得分享
Jan 31 #PHP
基于preg_match_all采集后数据处理的一点心得笔记(编码转换和正则匹配)
Jan 31 #PHP
php curl_init函数用法
Jan 31 #PHP
curl实现站外采集的方法和技巧
Jan 31 #PHP
php使用curl检测网页是否被百度收录的示例分享
Jan 31 #PHP
php使用百度翻译api示例分享
Jan 31 #PHP
php比较两个绝对时间的大小
Jan 31 #PHP
You might like
PHP 加密与解密的斗争
2009/04/17 PHP
php中++i 与 i++ 的区别
2012/08/08 PHP
PHP编写学校网站上新生注册登陆程序的实例分享
2016/03/21 PHP
Yii2 rbac权限控制之rule教程详解
2016/06/23 PHP
PHP获取当前日期及本周一是几月几号的方法
2017/03/28 PHP
基于PHP实现解密或加密Cloudflar邮箱保护
2020/06/24 PHP
Code:loadScript( )加载js的功能函数
2007/02/02 Javascript
Prototype 工具函数 学习
2009/07/23 Javascript
jqGrid jQuery 表格插件测试代码
2011/08/23 Javascript
《JavaScript函数式编程》读后感
2015/08/07 Javascript
使用bootstrap typeahead插件实现输入框自动补全之问题及解决办法
2016/07/07 Javascript
详谈JS中实现种子随机数及作用
2016/07/19 Javascript
购物车前端开发(jQuery和bootstrap3)
2016/08/27 Javascript
深入理解vue.js双向绑定的实现原理
2016/12/05 Javascript
mongoose中利用populate处理嵌套的方法
2017/05/26 Javascript
lhgcalendar时间插件限制只能选择三个月的实现方法
2017/07/03 Javascript
Node.JS更改Windows注册表Regedit的方法小结
2017/08/18 Javascript
vue实现跨域的方法分析
2019/05/21 Javascript
[01:19:54]DOTA2上海特级锦标赛主赛事日 - 2 败者组第二轮#1Alliance VS EHOME
2016/03/03 DOTA
python通过scapy获取局域网所有主机mac地址示例
2014/05/04 Python
python的构建工具setup.py的方法使用示例
2017/10/23 Python
Python FTP两个文件夹间的同步实例代码
2018/05/25 Python
CentOS7安装Python3的教程详解
2019/04/10 Python
Python Web框架之Django框架Model基础详解
2019/08/16 Python
对Python中一维向量和一维向量转置相乘的方法详解
2019/08/26 Python
基于Python 中函数的 收集参数 机制
2019/12/21 Python
Python模块的制作方法实例分析
2019/12/21 Python
定义css设备类型-Media Queries图表简介及使用方法
2013/01/21 HTML / CSS
文明礼仪事迹材料
2014/01/09 职场文书
腾讯广告词
2014/03/19 职场文书
联片教研活动总结
2014/07/01 职场文书
护理专科学生自荐书
2014/07/05 职场文书
国际贸易系求职信
2014/08/09 职场文书
小学家长意见怎么写
2015/06/03 职场文书
2015年暑期见闻
2015/07/14 职场文书
民间借贷纠纷起诉书
2015/08/03 职场文书