分享一个超好用的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 相关文章推荐
文件上传程序的全部源码
Oct 09 PHP
php 网页播放器用来播放在线视频的代码(自动判断并选择视频文件类型)
Jun 03 PHP
通过缓存数据库结果提高PHP性能的原理介绍
Sep 05 PHP
关于更改Zend Studio/Eclipse代码风格主题的介绍
Jun 23 PHP
php 魔术方法详解
Nov 11 PHP
浅谈php提交form表单
Jul 01 PHP
php文件扩展名判断及获取文件扩展名的N种方法
Sep 12 PHP
PHP5.2中PDO的简单使用方法
Mar 25 PHP
thinkPHP简单遍历数组方法分析
May 16 PHP
PHP常用排序算法实例小结【基本排序,冒泡排序,快速排序,插入排序】
Feb 07 PHP
TP5框架model常见操作示例小结【增删改查、聚合、时间戳、软删除等】
Apr 05 PHP
PHP ob缓存以及ob函数原理实例解析
Nov 13 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中记录用户访问过的产品,在cookie记录产品id,id取得产品信息
2011/05/04 PHP
PHP 二维数组根据某个字段排序的具体实现
2014/06/03 PHP
浅谈php优化需要注意的地方
2014/11/27 PHP
PHP list() 将数组中的值赋给变量的简单实例
2016/06/13 PHP
AJAX PHP无刷新form表单提交的简单实现(推荐)
2016/09/09 PHP
LBS blog sql注射漏洞[All version]-官方已有补丁
2007/08/26 Javascript
JavaScript CSS修改学习第二章 样式
2010/02/19 Javascript
关闭ie窗口清除Session的解决方法
2014/01/10 Javascript
浏览器窗口加载和大小改变事件示例
2014/02/27 Javascript
JavaScript获取table中某一列的值的方法
2014/05/06 Javascript
nodejs命令行参数处理模块commander使用实例
2014/09/17 NodeJs
BootStrap 弹出层代码
2017/02/09 Javascript
AngularJS实现表格的增删改查(仅限前端)
2017/07/04 Javascript
Vue中v-show添加表达式的问题(判断是否显示)
2018/03/26 Javascript
详解vue-cli中模拟数据的两种方法
2018/07/03 Javascript
ES6模板字符串和标签模板的应用实例分析
2019/06/25 Javascript
javascript中正则表达式语法详解
2020/08/07 Javascript
Vue.js暴露方法给WebView的使用操作
2020/09/07 Javascript
[02:44]DOTA2英雄基础教程 魅惑魔女
2014/01/07 DOTA
[01:27:43]VGJ.S vs TNC Supermajor 败者组 BO3 第三场 6.6
2018/06/07 DOTA
[57:41]Secret vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
python使用pandas实现数据分割实例代码
2018/01/25 Python
Python有参函数使用代码实例
2020/01/06 Python
利用Python自动化操作AutoCAD的实现
2020/04/01 Python
CSS3中Animation动画属性用法详解
2016/07/04 HTML / CSS
市场营销专业推荐信
2013/11/03 职场文书
五型班组建设方案
2014/02/10 职场文书
2014年十一国庆向国旗敬礼寄语
2014/04/11 职场文书
团队队名口号大全
2014/06/06 职场文书
协会周年庆活动方案
2014/08/26 职场文书
邹越感恩父母演讲稿
2014/08/28 职场文书
社区创先争优承诺书
2014/08/30 职场文书
电影建国大业观后感
2015/06/01 职场文书
计算机实训心得体会
2016/01/14 职场文书
(开源)微信小程序+mqtt,esp8266温湿度读取
2021/04/02 Javascript
MySQL 重命名表的操作方法及注意事项
2021/05/21 MySQL