分享一个超好用的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中的一个中文字符串截取函数
Feb 14 PHP
php5 mysql分页实例代码
Apr 10 PHP
基于PHP服务端图片生成缩略图的方法详解
Jun 20 PHP
PHP输出一个等腰三角形的方法
May 12 PHP
php实现CSV文件导入和导出
Oct 24 PHP
php+redis在实际项目中HTTP 500: Internal Server Error故障排除
Feb 05 PHP
php curl上传、下载、https登陆实现代码
Jul 23 PHP
PHP实现转盘抽奖算法分享
Apr 15 PHP
Laravel获取所有的数据库表及结构的方法
Oct 10 PHP
laravel通过a标签从视图向控制器实现传值
Oct 15 PHP
PHP如何通过date() 函数格式化显示时间
Nov 13 PHP
如何用PHP实现多线程编程
May 26 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编码规范
2015/09/28 PHP
smarty学习笔记之常见代码段用法总结
2016/03/19 PHP
Thinkphp3.2实用篇之计算型验证码示例
2017/02/09 PHP
php实现的mongoDB单例模式操作类
2018/01/20 PHP
php设计模式之策略模式应用案例详解
2019/06/17 PHP
JavaScript Timer实现代码
2010/02/17 Javascript
用js实现判断当前网址的来路如果不是指定的来路就跳转到指定页面
2011/05/02 Javascript
基于JQUERY的多级联动代码
2012/01/24 Javascript
JQuery切换显示的效果实例代码
2013/02/27 Javascript
jQuery查询数据返回object和字符串影响原因是什么
2013/08/09 Javascript
变量声明时命名与变量作为对象属性时命名的区别解析
2013/12/06 Javascript
jquery实现上下左右滑动的方法
2015/02/09 Javascript
JS特效实现图片自动播放并可控的效果
2015/07/31 Javascript
JS实现的文字与图片定时切换效果代码
2015/10/06 Javascript
Bootstrap3学习笔记(三)之表格
2016/05/20 Javascript
微信小程序 石头剪刀布实例代码
2017/01/04 Javascript
js实现二级菜单点击显示当前内容效果
2018/04/28 Javascript
vue自定义插件封装,实现简易的elementUi的Message和MessageBox的示例
2020/11/20 Vue.js
[44:43]完美世界DOTA2联赛决赛日 FTD vs GXR 第一场 11.08
2020/11/11 DOTA
Python脚本实现DNSPod DNS动态解析域名
2015/02/14 Python
解析Mac OS下部署Pyhton的Django框架项目的过程
2016/05/03 Python
解决Pycharm中import时无法识别自己写的程序方法
2018/05/18 Python
python实现pdf转换成word/txt纯文本文件
2018/06/07 Python
Pytorch之contiguous的用法
2019/12/31 Python
中国旅游网站:同程旅游
2016/09/11 全球购物
万得城电器土耳其网站:欧洲第一大电子产品零售商
2016/10/07 全球购物
标记环介质访问控制协议
2016/03/27 面试题
养成教育经验材料
2014/05/26 职场文书
节约用电标语
2014/06/17 职场文书
2015年学校保卫部工作总结
2015/05/11 职场文书
钱学森观后感
2015/06/04 职场文书
健康教育主题班会
2015/08/14 职场文书
考研经验交流会策划书
2015/11/02 职场文书
如何解决php-fpm启动不了问题
2021/11/17 PHP
python中出现invalid syntax报错的几种原因分析
2022/02/12 Python
vue特效之翻牌动画
2022/04/20 Vue.js