一个发送文件的函数

转自: http://www.ugia.cn/?p=109

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

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

demo: 下载:周杰伦-《千里之外》

<?php
sendFile
(‘./wp-data/jay_chou_-_outside_great_distance.mp3’, ‘outside_great_distance.mp3’);
?>

相关文章

发表评论

返回顶部