分享一个超好用的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 相关文章推荐
Apache2 httpd.conf 中文版
Nov 17 PHP
PHP 编程的 5个良好习惯
Feb 20 PHP
关于url地址传参数时字符串有回车造成页面脚本赋值失败的解决方法
Jun 28 PHP
php中并发读写文件冲突的解决方案
Oct 25 PHP
memcache命令启动参数中文解释
Jan 13 PHP
PHP计算百度地图两个GPS坐标之间距离的方法
Jan 09 PHP
ThinkPHP的常用配置选项汇总
Mar 24 PHP
php实现不通过扩展名准确判断文件类型的方法【finfo_file方法与二进制流】
Apr 18 PHP
PHP实现深度优先搜索算法(DFS,Depth First Search)详解
Sep 16 PHP
PHP微信H5支付开发实例
Jul 25 PHP
PHP PDOStatement::getAttribute讲解
Feb 01 PHP
php设计模式之正面模式实例分析【星际争霸游戏案例】
Mar 24 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 set_time_limit(0) 设置程序执行时间的函数
2010/05/26 PHP
使用JSON实现数据的跨域传输的php代码
2011/12/20 PHP
PHP判断搜索引擎蜘蛛并自动记忆到文件的代码
2012/02/04 PHP
自己在做项目过程中学到的PHP知识收集
2012/08/20 PHP
PHP中file_exists函数不支持中文名的解决方法
2014/07/26 PHP
thinkphp中html:list标签传递多个参数实例
2014/10/30 PHP
十大使用PHP框架的理由
2015/09/26 PHP
JavaScript 产生不重复的随机数三种实现思路
2012/12/13 Javascript
javascript框架设计之浏览器的嗅探和特征侦测
2015/06/23 Javascript
在javascript中创建对象的各种模式解析
2016/05/16 Javascript
Bootstrap基本插件学习笔记之按钮(21)
2016/12/08 Javascript
Bootstrap fileinput文件上传组件使用详解
2017/06/06 Javascript
Webpack如何引入bootstrap的方法
2017/06/17 Javascript
vue父子组件的嵌套的示例代码
2017/09/08 Javascript
Vue实现底部侧边工具栏的实例代码
2018/09/03 Javascript
解决js相同的正则多次调用test()返回的值却不同的问题
2018/10/10 Javascript
JavaScript页面倒计时功能完整示例
2019/05/15 Javascript
React+TypeScript+webpack4多入口配置详解
2019/08/08 Javascript
layui的表单验证支持ajax判断用户名是否重复的实例
2019/09/06 Javascript
微信小程序自定义波浪组件使用方法详解
2019/09/21 Javascript
Vue 图片压缩并上传至服务器功能
2020/01/15 Javascript
VUE子组件向父组件传值详解(含传多值及添加额外参数场景)
2020/09/01 Javascript
使用Python的Zato发送AMQP消息的教程
2015/04/16 Python
对python中return和print的一些理解
2017/08/18 Python
Python模拟键盘输入自动登录TGP
2020/11/27 Python
css3 column实现卡片瀑布流布局的示例代码
2018/06/22 HTML / CSS
localStorage、sessionStorage使用总结
2017/11/17 HTML / CSS
宝拉珍选官方旗舰店:2%水杨酸精华液,收缩毛孔粗大和祛痘
2018/07/01 全球购物
世界上最好的野生海鲜和有机食品:Vital Choice
2020/01/16 全球购物
班组长安全生产职责
2013/12/16 职场文书
园林资料员岗位职责
2013/12/30 职场文书
校长新学期致辞
2015/07/30 职场文书
2016社区平安家庭事迹材料
2016/02/26 职场文书
导游词之太湖
2019/10/08 职场文书
2019年亲子运动会口号
2019/10/11 职场文书
详解Vue的options
2021/05/15 Vue.js