在实现开发过程中, 我们会遇到下载问题。 在我们考虑的前提是安全,所以大家都设置了用php来实现下载, 就是header的应用, 而header的普通应用在应付小文件时,比如20MB,40MB的还行。 但如果项目中增加了许可下载1GB 4GB呢?比如游戏文件, iso文件, 那就普通的header就有点力不从心。 根据测试, 文件下载过程还是会实现, 不过下载下来的文件是0字节,即空文件。 这就是大家一直讲的echo 大文件时速度慢,导致线程被中断等等问题怕造成的, 而我们这些应该要记住php还有一个缓存区,即ob_flush 也许用如下的函数可以解决大文件下载。 [code language=php]<?php $file_path = './download/download_cn.rar'; //使用方法 downFile($file_path); // 服务器文件路径,下载文件名字(默认为服务器文件名),是否许可用户下载方式(默认可选),速度限制(默认自动),文件类型(默认所有) function downFile($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). '"'); } header("Content-Transfer-Encoding: binary"); $bufferSize = 2048; if ($speedLimit != 0) { $packetTime = floor($bufferSize * 1000000 / $speedLimit); } $bytesSent = 0; $fp = fopen($fileName, "rb"); fseek($fp, $startPos); 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; } ?>[/code] |
利用PHP实现在线下载大文件
最新推荐文章于 2021-03-23 08:53:34 发布