分享一个超好用的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程序效率优化的一些策略小结
Jul 17 PHP
php获取ip的三个属性区别介绍(HTTP_X_FORWARDED_FOR,HTTP_VIA,REMOTE_ADDR)
Sep 23 PHP
PHPMailer使用教程(PHPMailer发送邮件实例分析)
Dec 06 PHP
PHP中单引号与双引号的区别分析
Aug 19 PHP
php使用$_POST或$_SESSION[]向js函数传参
Sep 16 PHP
ThinkPHP实现非标准名称数据表快速创建模型的方法
Nov 29 PHP
Laravel5.1数据库连接、创建数据库、创建model及创建控制器的方法
Mar 29 PHP
php构造方法中析构方法在继承中的表现
Apr 12 PHP
Smarty简单生成表单元素的方法示例
May 23 PHP
Laravel框架实现的rbac权限管理操作示例
Jan 16 PHP
解决tp5在nginx下修改配置访问的问题
Oct 16 PHP
gearman管理工具GearmanManager的安装与php使用方法示例
Feb 27 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 array_unique之后json_encode需要注意
2011/01/02 PHP
PHP通过正则表达式下载图片到本地的实现代码
2011/09/19 PHP
Mysql中分页查询的两个解决方法比较
2013/05/02 PHP
老生常谈PHP面向对象之命令模式(必看篇)
2017/05/24 PHP
PHP PDOStatement::fetchAll讲解
2019/01/31 PHP
JS面向对象、prototype、call()、apply()
2009/05/14 Javascript
JS读取cookies信息(记录用户名)
2012/01/10 Javascript
js动态删除div元素基本思路及实现代码
2014/05/08 Javascript
JS给超链接加确认对话框的方法
2015/02/24 Javascript
Vue.js每天必学之方法与事件处理器
2016/09/06 Javascript
详解基于webpack和vue.js搭建开发环境
2017/04/05 Javascript
node.js+captchapng+jsonwebtoken实现登录验证示例
2017/08/17 Javascript
jqueryUI tab标签页代码分享
2017/10/09 jQuery
Vue cli构建及项目打包以及出现的问题解决
2018/08/27 Javascript
详解javascript 变量提升(Hoisting)
2019/03/12 Javascript
jQuery添加新内容的四个常用方法分析【append,prepend,after,before】
2019/03/19 jQuery
使用vue-router切换页面时,获取上一页url以及当前页面url的方法
2019/05/06 Javascript
VueCli4项目配置反向代理proxy的方法步骤
2020/05/17 Javascript
[14:25]教你分分钟做大人:主宰(HEROS)
2014/12/08 DOTA
pygame加载中文名mp3文件出现error
2017/03/31 Python
解决Jupyter Notebook开始菜单栏Anaconda下消失的问题
2020/04/13 Python
如何基于python把文字图片写入word文档
2020/07/31 Python
Python 串口通信的实现
2020/09/29 Python
python代码实现猜拳小游戏
2020/11/30 Python
Reebok官方旗舰店:美国知名健身品牌锐步
2019/01/07 全球购物
生产总经理岗位职责
2013/12/19 职场文书
毕业证丢失证明
2014/01/15 职场文书
2014年小学元旦活动方案
2014/02/12 职场文书
高中美术教师事迹材料
2014/08/22 职场文书
党员群众路线学习心得体会
2014/11/04 职场文书
2015年班组长工作总结
2015/04/10 职场文书
监理中标通知书
2015/04/16 职场文书
学术会议领导致辞
2015/07/29 职场文书
小学语文教师研修感悟
2015/11/18 职场文书
Python中的xlrd模块使用整理
2021/06/15 Python
Win11运行cmd提示“请求的操作需要提升”的两种解决方法
2022/07/07 数码科技