分享一个超好用的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学习 计数器实例代码
Jun 15 PHP
PHP生成sitemap.xml地图函数
Nov 13 PHP
php压缩和解压缩字符串的方法
Mar 14 PHP
php实现zip文件解压操作
Nov 03 PHP
给WordPress中的留言加上楼层号的PHP代码实例
Dec 14 PHP
分享php多功能图片处理类
May 15 PHP
PHP实现页面静态化的超简单方法
Sep 06 PHP
ThinkPHP使用getlist方法实现数据搜索功能示例
May 08 PHP
PHP基于堆栈实现的高级计算器功能示例
Sep 15 PHP
php5与php7的区别点总结
Oct 11 PHP
零基础php编程好学吗
Oct 11 PHP
PHP使用gearman进行异步的邮件或短信发送操作详解
Feb 27 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之第八天
2006/10/09 PHP
phpstrom使用xdebug配置方法
2013/12/17 PHP
PHP+MySQL删除操作实例
2015/01/21 PHP
在Laravel 的 Blade 模版中实现定义变量
2019/10/14 PHP
javascript学习笔记(二十) 获得和设置元素的特性(属性)
2012/06/20 Javascript
jquery得到font-size属性值实现代码
2013/09/30 Javascript
jquery ajax实现下拉框三级无刷新联动,且保存保持选中值状态
2013/10/29 Javascript
jQuery选择器全集详解
2014/11/24 Javascript
javascript异步处理工作机制详解
2015/04/13 Javascript
js简单实现标签云效果实例
2015/08/06 Javascript
浅谈JavaScript中的对象及Promise对象的实现
2015/11/15 Javascript
详解本地Node.js服务器作为api服务器的解决办法
2017/02/28 Javascript
JavaScript比较两个数组的内容是否相同(推荐)
2017/05/02 Javascript
微信小程序实现导航栏选项卡效果
2020/06/19 Javascript
js实现购物车功能
2018/06/12 Javascript
jQuery插件实现的日历功能示例【附源码下载】
2018/09/07 jQuery
axios 封装上传文件的请求方法
2018/09/26 Javascript
vue router动态路由设置参数可选问题
2019/08/21 Javascript
浅谈es6中的元编程
2020/12/01 Javascript
[02:09:59]火猫TV国士无双dota2 6.82版本详解(下)
2014/09/29 DOTA
[05:59]2018DOTA2国际邀请赛寻真——只为胜利的Secret
2018/08/13 DOTA
python使用正则搜索字符串或文件中的浮点数代码实例
2014/07/11 Python
Python中DJANGO简单测试实例
2015/05/11 Python
python脚本作为Windows服务启动代码详解
2018/02/11 Python
Python装饰器原理与简单用法实例分析
2018/04/29 Python
Python使用selenium + headless chrome获取网页内容的方法示例
2019/10/16 Python
使用Python制作缩放自如的圣诞老人(圣诞树)
2019/12/25 Python
Python基于pip实现离线打包过程详解
2020/05/15 Python
python 使用递归的方式实现语义图片分割功能
2020/07/16 Python
python3.7.3版本和django2.2.3版本是否可以兼容
2020/09/01 Python
旅游管理专业学生求职信
2013/09/28 职场文书
数控个人求职信范文
2014/02/03 职场文书
中层干部考核评语
2015/01/04 职场文书
2015年城乡环境综合治理工作总结
2015/07/24 职场文书
2019安全宣传标语大全
2019/08/14 职场文书
MySQL 覆盖索引的优点
2021/05/19 MySQL