分享一个超好用的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 相关文章推荐
对Session和Cookie的区分与解释
Mar 16 PHP
比较简单实用的PHP无限分类源码分享(思路不错)
Oct 13 PHP
调试一段PHP程序时遇到的三个问题
Jan 17 PHP
php 多关键字 高亮显示实现代码
Apr 23 PHP
php调用C代码的实现方法
Mar 11 PHP
PHP中使用imagick生成PSD文件缩略图教程
Jan 26 PHP
php使用cookie保存用户登录的用户名实例
Jan 26 PHP
php实现字符串翻转的方法
Mar 27 PHP
php结合安卓客户端实现查询交互实例
May 05 PHP
PHP魔术方法以及关于独立实例与相连实例的全面讲解
Oct 18 PHP
PHP设置images目录不充许http访问的方法
Nov 01 PHP
PHP终止脚本运行三种实现方法详解
Sep 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
德生S2000电路分析
2021/03/02 无线电
PHP生成带有雪花背景的验证码
2006/10/09 PHP
php中神奇的fastcgi_finish_request
2011/05/02 PHP
thinkPHP3.1验证码的简单实现方法
2016/04/22 PHP
php 从一个数组中随机的取出若干个不同的数实例
2016/12/31 PHP
php获取微信基础接口凭证Access_token
2018/08/23 PHP
Yii框架数据库查询、增加、删除操作示例
2019/10/14 PHP
一个用js实现的页内搜索代码
2007/05/23 Javascript
JQuery与JSon实现的无刷新分页代码
2011/09/13 Javascript
Ajax搜索结果页面下方的分页按钮的生成
2012/04/05 Javascript
Javascript学习笔记之函数篇(四):arguments 对象
2014/11/23 Javascript
javascript中数组array及string的方法总结
2014/11/28 Javascript
jquery自定义右键菜单、全选、不连续选择
2016/03/01 Javascript
js实现浏览器倒计时跳转页面效果
2016/08/12 Javascript
AngularJs html compiler详解及示例代码
2016/09/01 Javascript
Vue2 Vue-cli中使用Typescript的配置详解
2017/07/24 Javascript
基于AngularJS实现表单验证功能
2017/07/28 Javascript
Vue中引入样式文件的方法
2017/08/18 Javascript
JavaScript实现区块链
2018/03/14 Javascript
vue2.0使用v-for循环制作多级嵌套菜单栏
2018/06/25 Javascript
vue实现计算器功能
2020/02/22 Javascript
Vue 数据响应式相关总结
2021/01/28 Vue.js
python3简单实现微信爬虫
2015/04/09 Python
深入解析Python中函数的参数与作用域
2016/03/20 Python
Python教程之全局变量用法
2016/06/27 Python
python解析html提取数据,并生成word文档实例解析
2018/01/22 Python
python实现NB-IoT模块远程控制
2018/06/20 Python
Win8.1下安装Python3.6提示0x80240017错误的解决方法
2018/07/31 Python
浅析HTML5 Landmark
2020/09/11 HTML / CSS
MAC Cosmetics官方网站:魅可专业艺术彩妆
2019/04/10 全球购物
英国手工制作的现代与经典的沙发和床:Love Your Home
2020/09/26 全球购物
店长岗位职责
2013/11/21 职场文书
八一演出活动方案
2014/02/03 职场文书
调解协议书
2014/04/16 职场文书
企业党员个人自我评价
2014/09/20 职场文书
未来,这5大方向都很适合创业
2019/07/22 职场文书