分享一个超好用的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 相关文章推荐
用PHP 快速生成 Flash 动画的方法
Mar 06 PHP
PHP6 先修班 JSON实例代码
Aug 23 PHP
php中$_SERVER[PHP_SELF] 和 $_SERVER[SCRIPT_NAME]之间的区别
Sep 05 PHP
ezSQL PHP数据库操作类库
May 16 PHP
PHP乱码问题,UTF-8乱码常见问题小结
Apr 09 PHP
smarty获得当前url的方法分享
Feb 14 PHP
PHP实现把MySQL数据库导出为.sql文件实例(仿PHPMyadmin导出功能)
May 10 PHP
Thinkphp批量更新数据的方法汇总
Jun 29 PHP
PHP编写文件多服务器同步程序
Jul 02 PHP
深入讲解PHP的对象注入(Object Injection)
Mar 01 PHP
PHP数组实际占用内存大小原理解析
Dec 11 PHP
PHP 判断字符串是中文还是英文, 或者是中英混合
Mar 09 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应用程序来获取Web服务器的状态信息
2006/10/09 PHP
php中使用redis队列操作实例代码
2013/02/07 PHP
php双层循环(九九乘法表)
2017/10/23 PHP
使用 PHP Masked Package 屏蔽敏感数据的实现方法
2019/10/15 PHP
PHP pthreads v3下的Volatile简介与使用方法示例
2020/02/21 PHP
php如何获取Http请求
2020/04/30 PHP
jQuery+PHP实现图片上传并提交功能
2020/07/27 PHP
ASP小贴士/ASP Tips javascript tips可以当桌面
2009/12/10 Javascript
jquery多选项卡效果实例代码(附效果图)
2013/03/23 Javascript
node.js中的fs.closeSync方法使用说明
2014/12/17 Javascript
详解JavaScript节流函数中的Throttle
2016/07/16 Javascript
Vuejs第九篇之组件作用域及props数据传递实例详解
2016/09/05 Javascript
JQuery实现列表中复选框全选反选功能封装(推荐)
2016/11/24 Javascript
详解基于webpack和vue.js搭建开发环境
2017/04/05 Javascript
解决Vue中引入swiper,在数据渲染的时候,发生不滑动的问题
2018/09/27 Javascript
vue+iview 兼容IE11浏览器的实现方法
2019/01/07 Javascript
vue 实现 rem 布局或vw 布局的方法
2019/11/13 Javascript
[55:39]DOTA2-DPC中国联赛 正赛 VG vs LBZS BO3 第二场 1月19日
2021/03/11 DOTA
Python中MySQL数据迁移到MongoDB脚本的方法
2016/04/28 Python
详解Python开发中如何使用Hook技巧
2017/11/01 Python
python 多线程中子线程和主线程相互通信方法
2018/11/09 Python
在主流系统之上安装Pygame的方法
2020/05/20 Python
HTML5里的placeholder属性使用实例和美化显示效果的方法
2014/04/23 HTML / CSS
HTML5实现签到 功能
2018/10/09 HTML / CSS
Nike西班牙官方网站:Nike.com (ES)
2017/10/30 全球购物
英国创新设计文具、卡片和礼品包装网站:Paperchase
2018/07/14 全球购物
StubHub澳大利亚:购买或出售您的门票
2019/08/01 全球购物
八一建军节活动方案
2014/02/10 职场文书
十八届三中全会学习方案
2014/02/16 职场文书
幼儿教师寄语集锦
2014/04/03 职场文书
群众路线教育实践活动方案
2014/10/31 职场文书
世界地球日活动总结
2015/02/09 职场文书
Python基本数据类型之字符串str
2021/07/21 Python
ORM模型框架操作mysql数据库的方法
2021/07/25 MySQL
设置IIS Express并发数
2022/07/07 Servers
LyScript实现绕过反调试保护的示例详解
2022/08/14 Python