Bookmark and Share

Lee's 程序人生

HTML CSS Javascript XML AJAX ATLAS C# C++ 数据结构 软件工程 设计模式 asp.net Java 数字图象处理 Sql 数据库
  博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

一个发送文件的函数

Posted on 2008-06-13 10:08  analyzer  阅读(267)  评论(0)    收藏  举报

这是前段时间在live-share.com上使用的文件发送函数,后来由于这种方式在高并发下负载过大,而放弃使用。此函数支持多线及断点续传,在非windows服务器下可限制速度,windows服务器因为不支持usleep函数,但用sleep函数效果不理想,所以放弃。此函数并不完全符合HTTP1.1标准,其中的断点续传部分没有考虑多个range的情况(事实上我还没见过哪个下载软件这么变态)。


  1<?php 
  2/**    
  3* 发送文件    
  4*    
  5* @author: legend(legendsky@hotmail.com)    
  6* @link: http://www.ugia.cn/?p=109    
  7* @description: send file to client    
  8* @version: 1.0    
  9*    
 10* @param string   $fileName      文件名称或路径    
 11* @param string   $fancyName     自定义的文件名,为空则使用filename    
 12* @param boolean  $forceDownload 是否强制下载    
 13* @param integer  $speedLimit    速度限制,单位为字节,0为不限制,不支持windows服务器    
 14* @param string   $$contentType  文件类型,默认为application/octet-stream    
 15*    
 16* @return boolean    
 17*/     
 18function sendFile($fileName, $fancyName = '', $forceDownload = true, $speedLimit = 0, $contentType = '')     
 19{     
 20    if (!is_readable($fileName))     
 21    {     
 22        header("HTTP/1.1 404 Not Found");     
 23        return false;     
 24    }     
 25      
 26    $fileStat = stat($fileName);     
 27    $lastModified = $fileStat['mtime'];     
 28        
 29    $md5 = md5($fileStat['mtime'.'='. $fileStat['ino'.'='. $fileStat['size']);     
 30    $etag = '"' . $md5 . '-' . crc32($md5. '"';     
 31      
 32    header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $lastModified. ' GMT');     
 33    header("ETag: $etag");     
 34        
 35    if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModified)     
 36    {     
 37        header("HTTP/1.1 304 Not Modified");     
 38        return true;     
 39    }     
 40      
 41    if (isset($_SERVER['HTTP_IF_UNMODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_UNMODIFIED_SINCE']) < $lastModified)     
 42    {     
 43        header("HTTP/1.1 304 Not Modified");     
 44        return true;     
 45    }     
 46      
 47    if (isset($_SERVER['HTTP_IF_NONE_MATCH']) &&  $_SERVER['HTTP_IF_NONE_MATCH'== $etag)     
 48    {     
 49        header("HTTP/1.1 304 Not Modified");     
 50        return true;     
 51    }     
 52      
 53    if ($fancyName == '')     
 54    {     
 55        $fancyName = basename($fileName);     
 56    }     
 57        
 58    if ($contentType == '')     
 59    {     
 60        $contentType = 'application/octet-stream';     
 61    }     
 62      
 63    $fileSize = $fileStat['size'];       
 64        
 65    $contentLength = $fileSize;     
 66    $isPartial = false;     
 67      
 68    if (isset($_SERVER['HTTP_RANGE']))     
 69    {     
 70        if (preg_match('/^bytes=(\d*)-(\d*)$/', $_SERVER['HTTP_RANGE'], $matches))     
 71        {        
 72            $startPos = $matches[1];     
 73            $endPos = $matches[2];     
 74      
 75            if ($startPos == '' && $endPos == '')     
 76            {     
 77                return false;     
 78            }     
 79                
 80            if ($startPos == '')     
 81            {     
 82                $startPos = $fileSize - $endPos;     
 83                $endPos = $fileSize - 1;     
 84            }     
 85            else if ($endPos == '')     
 86            {     
 87                $endPos = $fileSize - 1;     
 88            }     
 89      
 90            $startPos = $startPos < 0 ? 0 : $startPos;     
 91            $endPos = $endPos > $fileSize - 1 ? $fileSize - 1 : $endPos;     
 92      
 93            $length = $endPos - $startPos + 1;     
 94      
 95            if ($length < 0)     
 96            {     
 97                return false;     
 98            }     
 99      
100            $contentLength = $length;     
101            $isPartial = true;     
102        }     
103    }     
104        
105    // send headers     
106    if ($isPartial)     
107    {     
108        header('HTTP/1.1 206 Partial Content');     
109        header("Content-Range: bytes $startPos-$endPos/$fileSize");     
110            
111    }     
112    else     
113    {     
114        header("HTTP/1.1 200 OK");     
115        $startPos = 0;     
116        $endPos = $contentLength - 1;     
117    }     
118      
119    header('Pragma: cache');     
120    header('Cache-Control: public, must-revalidate, max-age=0');     
121    header('Accept-Ranges: bytes');     
122    header('Content-type: ' . $contentType);     
123    header('Content-Length: ' . $contentLength);     
124        
125    if ($forceDownload)     
126    {     
127        header('Content-Disposition: attachment; filename="' . rawurlencode($fancyName). '"');     
128    }     
129      
130    header("Content-Transfer-Encoding: binary");     
131        
132    $bufferSize = 2048;     
133      
134    if ($speedLimit != 0)     
135    {     
136        $packetTime = floor($bufferSize * 1000000 / $speedLimit);     
137    }     
138      
139    $bytesSent = 0;     
140    $fp = fopen($fileName, "rb");     
141    fseek($fp, $startPos);     
142      
143    //fpassthru($fp);     
144        
145    while ($bytesSent < $contentLength && !feof($fp&& connection_status() == 0 )     
146    {     
147        if ($speedLimit != 0)     
148        {     
149            list($usec, $sec= explode(" ", microtime());     
150            $outputTimeStart = ((float)$usec + (float)$sec);     
151        }     
152      
153        $readBufferSize = $contentLength - $bytesSent < $bufferSize ? $contentLength - $bytesSent : $bufferSize;     
154        $buffer = fread($fp, $readBufferSize);            
155      
156        echo $buffer;     
157      
158        ob_flush();     
159        flush();     
160      
161        $bytesSent += $readBufferSize;     
162            
163        if ($speedLimit != 0)     
164        {     
165            list($usec, $sec= explode(" ", microtime());     
166            $outputTimeEnd = ((float)$usec + (float)$sec);     
167                
168            $useTime = ((float$outputTimeEnd - (float$outputTimeStart* 1000000;     
169            $sleepTime = round($packetTime - $useTime);     
170            if ($sleepTime > 0)     
171            {     
172                usleep($sleepTime);     
173            }     
174        }     
175    }     
176        
177      
178    return true;     
179}     
180   
181demo: 下载:周杰伦-《千里之外》    
182   
183<?php    
184sendFile('./wp-data/jay_chou_-_outside_great_distance.mp3', 'outside_great_distance.mp3');    
185?>    
186