分享一个超好用的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之第八天
Oct 09 PHP
最简单的PHP程序--记数器
Oct 09 PHP
linux系统下php安装mbstring扩展的二种方法
Jan 20 PHP
PHP判断远程图片是否存在的几种方法
May 04 PHP
PHP获取时间排除周六、周日的两个方法
Jun 30 PHP
php使用glob函数快速查询指定目录文件的方法
Nov 15 PHP
php单例模式实现方法分析
Mar 14 PHP
CodeIgniter删除和设置Cookie的方法
Apr 07 PHP
php 开发中加密的几种方法总结
Mar 22 PHP
kindeditor 加入七牛云上传的实例讲解
Nov 12 PHP
PHP 实现文件压缩解压操作的方法
Jun 14 PHP
详细分析PHP 命名空间(namespace)
Jun 30 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中file_get_contents与curl性能比较分析
2014/11/08 PHP
WordPress中登陆后关闭登陆页面及设置用户不可见栏目
2015/12/31 PHP
js获取图片大小的函数代码
2011/09/20 Javascript
js鼠标悬浮出现遮罩层的方法
2015/01/28 Javascript
js中获取jsp表单中radio类型的值简单实例
2016/08/15 Javascript
微信小程序(应用号)简单实例应用及实例详解
2016/09/26 Javascript
最常见和最有用的字符串相关的方法详解
2017/02/06 Javascript
javascript深拷贝和浅拷贝详解
2017/02/14 Javascript
原生JS实现左右箭头选择日期实例代码
2017/03/14 Javascript
AngularJS 的$timeout服务示例代码
2017/09/21 Javascript
vue获取input输入值的问题解决办法
2017/10/17 Javascript
为什么Vue3.0使用Proxy实现数据监听(defineProperty表示不背这个锅)
2019/10/14 Javascript
Vue实现base64编码图片间的切换功能
2019/12/04 Javascript
Vue如何使用混合Mixins和插件开发详解
2020/02/05 Javascript
原生js实现照片墙效果
2020/10/13 Javascript
查看Python安装路径以及安装包路径小技巧
2015/04/28 Python
Python中正则表达式的详细教程
2015/04/30 Python
Python中文分词实现方法(安装pymmseg)
2016/06/14 Python
[原创]pip和pygal的安装实例教程
2017/12/07 Python
python提取图像的名字*.jpg到txt文本的方法
2018/05/10 Python
通过python将大量文件按修改时间分类的方法
2018/10/17 Python
对python cv2批量灰度图片并保存的实例讲解
2018/11/09 Python
Python操作mongodb数据库的方法详解
2018/12/08 Python
Python pathlib模块使用方法及实例解析
2020/10/05 Python
建筑自我鉴定
2013/10/19 职场文书
函授本科自我鉴定
2013/11/03 职场文书
计算机应用专业应届毕业生中文求职信范文
2013/11/29 职场文书
校园自助餐厅的创业计划书
2013/12/26 职场文书
中专自我鉴定
2014/02/05 职场文书
正风肃纪剖析材料
2014/02/18 职场文书
2014爱耳日宣传教育活动总结
2014/03/09 职场文书
生日宴会策划方案
2014/06/03 职场文书
关于环保的标语
2014/06/13 职场文书
关于运动会广播稿50字
2014/10/18 职场文书
一年级语文上册复习计划
2015/01/17 职场文书
党员干部廉政承诺书
2015/04/28 职场文书