分享一个超好用的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 相关文章推荐
PHP4实际应用经验篇(8)
Oct 09 PHP
IP攻击升级,程序改进以对付新的攻击
Nov 23 PHP
初品cakephp 入门基础
Feb 16 PHP
php中使用addslashes函数报错问题的解决方法
Feb 06 PHP
php构造函数实例讲解
Nov 13 PHP
解析PHP强制转换类型及远程管理插件的安全隐患
Jun 30 PHP
ThinkPHP模型详解
Jul 27 PHP
twig模板常用语句实例小结
Feb 04 PHP
php中使用GD库做验证码
Mar 31 PHP
手把手编写PHP框架 深入了解MVC运行流程
Sep 19 PHP
PHP与服务器文件系统的简单交互
Oct 21 PHP
thinkphp自定义权限管理之名称判断方法
Apr 01 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设计模式 Decorator(装饰模式)
2011/06/26 PHP
PHP内核探索:变量概述
2014/01/30 PHP
php实现批量删除挂马文件及批量替换页面内容完整实例
2016/07/08 PHP
简单实现PHP留言板功能
2016/12/21 PHP
docker-compose部署php项目实例详解
2019/07/30 PHP
php+jQuery ajax实现的实时刷新显示数据功能示例
2019/09/12 PHP
PHP实现Markdown文章上传到七牛图床的实例内容
2020/02/11 PHP
Laravel框架数据库迁移操作实例详解
2020/04/06 PHP
一个轻量级的javascript库 pj介绍
2010/12/19 Javascript
jQuery前台数据获取实现代码
2011/03/16 Javascript
JS正则中的RegExp对象对象
2012/11/07 Javascript
JavaScript判断用户名和密码不能为空的实现代码
2016/05/16 Javascript
解析JavaScript中的字符串类型与字符编码支持
2016/06/24 Javascript
vue.js初学入门教程(1)
2016/11/03 Javascript
Vue.js中用webpack合并打包多个组件并实现按需加载
2017/02/17 Javascript
nodejs实现邮件发送服务实例分享
2017/03/29 NodeJs
关于foreach循环中遇到的问题小结
2017/05/08 Javascript
基于jquery trigger函数无法触发a标签的两种解决方法
2018/01/06 jQuery
基于vue和react的spa进行按需加载的实现方法
2018/09/29 Javascript
详解Node.js中path模块的resolve()和join()方法的区别
2018/10/29 Javascript
NodeJs入门教程之定时器和队列
2019/03/08 NodeJs
微信小程序第三方框架对比 之 wepy / mpvue / taro
2019/04/10 Javascript
node静态服务器实现静态读取文件或文件夹
2019/12/03 Javascript
Python实现从订阅源下载图片的方法
2015/03/11 Python
利用python打开摄像头及颜色检测方法
2018/08/03 Python
pytorch 预训练层的使用方法
2019/08/20 Python
Python实现将蓝底照片转化为白底照片功能完整实例
2019/12/13 Python
Django REST 异常处理详解
2020/07/15 Python
3分钟看懂Python后端必须知道的Django的信号机制
2020/07/26 Python
Python selenium实现断言3种方法解析
2020/09/08 Python
python中Pexpect的工作流程实例讲解
2021/03/02 Python
美国东北部户外服装和设备零售商:Eastern Mountain Sports
2016/10/05 全球购物
墨尔本最受欢迎的复古风格品牌:Princess Highway
2018/12/21 全球购物
市场营销专业推荐信
2013/11/03 职场文书
2015年医药代表工作总结
2015/04/25 职场文书
警示教育观后感
2015/06/17 职场文书