慕容的工作随笔

慕容的工作随笔

记录学习和工作

php下载大文件,支持断点续传案例 转

转自https://www.jianshu.com/p/db9531baee4e
思路 1.设置header头信息 2.使用php的输出缓冲ob_flush,flush 2.下载速度*fread(size) ,sleep(1)达到限制下载速度效果 3.通过每次传输的大小,剩余的大小来偏移读取文件的指针位置达到断点续传 4.只能限制到最大的下载速度,具体的速度根据实际的网络环境会有偏差
/**
 *  @param [string] $[file] [文件路径]
 *  @param [int] $[rate] [下载速度]
 *  @param boole $[forceDownload] [文件名是否中文处理]
 */

function downFile($file,$rate=100,$forceDownload=true)
{

<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">file_exists</span><span class="token punctuation">(</span><span class="token variable">$file</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"HTTP/1.1 404 Not Found"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token boolean constant">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">is_readable</span><span class="token punctuation">(</span><span class="token variable">$file</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"HTTP/1.1 404 Not Found"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token boolean constant">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token shell-comment comment">#读取文件的信息</span>
<span class="token variable">$fileStat</span> <span class="token operator">=</span> <span class="token function">stat</span><span class="token punctuation">(</span><span class="token variable">$file</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$lastModified</span> <span class="token operator">=</span> <span class="token variable">$fileStat</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'mtime'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token shell-comment comment">#拼成etag,防止文件发生修改</span>
<span class="token variable">$md5</span> <span class="token operator">=</span> <span class="token function">md5</span><span class="token punctuation">(</span><span class="token variable">$fileStat</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'mtime'</span><span class="token punctuation">]</span> <span class="token punctuation">.</span> <span class="token single-quoted-string string">'='</span> <span class="token punctuation">.</span> <span class="token variable">$fileStat</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'ino'</span><span class="token punctuation">]</span> <span class="token punctuation">.</span> <span class="token single-quoted-string string">'='</span> <span class="token punctuation">.</span> <span class="token variable">$fileStat</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'size'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$etag</span> <span class="token operator">=</span> <span class="token single-quoted-string string">'"'</span> <span class="token punctuation">.</span> <span class="token variable">$md5</span> <span class="token punctuation">.</span> <span class="token single-quoted-string string">'-'</span> <span class="token punctuation">.</span> <span class="token function">crc32</span><span class="token punctuation">(</span><span class="token variable">$md5</span><span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token single-quoted-string string">'"'</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$_SERVER</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'HTTP_IF_MODIFIED_SINCE'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">strtotime</span><span class="token punctuation">(</span><span class="token variable">$_SERVER</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'HTTP_IF_MODIFIED_SINCE'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&gt;=</span> <span class="token variable">$lastModified</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"HTTP/1.1 304 Not Modified"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token boolean constant">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$_SERVER</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'HTTP_IF_UNMODIFIED_SINCE'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">strtotime</span><span class="token punctuation">(</span><span class="token variable">$_SERVER</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'HTTP_IF_UNMODIFIED_SINCE'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&lt;</span> <span class="token variable">$lastModified</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"HTTP/1.1 304 Not Modified"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token boolean constant">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$_SERVER</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'HTTP_IF_NONE_MATCH'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token variable">$_SERVER</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'HTTP_IF_NONE_MATCH'</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token variable">$etag</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"HTTP/1.1 304 Not Modified"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token boolean constant">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>


<span class="token variable">$fileSize</span> <span class="token operator">=</span> <span class="token variable">$fileStat</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'size'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token variable">$contentLength</span> <span class="token operator">=</span> <span class="token variable">$fileSize</span><span class="token punctuation">;</span><span class="token comment">//文件大小</span>
<span class="token variable">$isPartial</span> <span class="token operator">=</span> <span class="token boolean constant">false</span><span class="token punctuation">;</span><span class="token comment">//是否断点续传</span>
<span class="token variable">$fancyName</span> <span class="token operator">=</span> <span class="token function">basename</span><span class="token punctuation">(</span><span class="token variable">$file</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">//计算断点续传的开始位置</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$_SERVER</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'HTTP_RANGE'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">preg_match</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'/^bytes=(\d*)-(\d*)$/'</span><span class="token punctuation">,</span> <span class="token variable">$_SERVER</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'HTTP_RANGE'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token variable">$matches</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token variable">$startPos</span> <span class="token operator">=</span> <span class="token variable">$matches</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token variable">$endPos</span> <span class="token operator">=</span> <span class="token variable">$matches</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$startPos</span> <span class="token operator">==</span> <span class="token single-quoted-string string">''</span> <span class="token operator">&amp;&amp;</span> <span class="token variable">$endPos</span> <span class="token operator">==</span> <span class="token single-quoted-string string">''</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token boolean constant">false</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$startPos</span> <span class="token operator">==</span> <span class="token single-quoted-string string">''</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token variable">$startPos</span> <span class="token operator">=</span> <span class="token variable">$fileSize</span> <span class="token operator">-</span> <span class="token variable">$endPos</span><span class="token punctuation">;</span>
            <span class="token variable">$endPos</span> <span class="token operator">=</span> <span class="token variable">$fileSize</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$endPos</span> <span class="token operator">==</span> <span class="token single-quoted-string string">''</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token variable">$endPos</span> <span class="token operator">=</span> <span class="token variable">$fileSize</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token variable">$startPos</span> <span class="token operator">=</span> <span class="token variable">$startPos</span> <span class="token operator">&lt;</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token variable">$startPos</span><span class="token punctuation">;</span><span class="token comment">//开始位置</span>
        <span class="token variable">$endPos</span> <span class="token operator">=</span> <span class="token variable">$endPos</span> <span class="token operator">&gt;</span> <span class="token variable">$fileSize</span> <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">?</span> <span class="token variable">$fileSize</span> <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token variable">$endPos</span><span class="token punctuation">;</span><span class="token comment">//结束位置</span>

        <span class="token variable">$length</span> <span class="token operator">=</span> <span class="token variable">$endPos</span> <span class="token operator">-</span> <span class="token variable">$startPos</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span><span class="token comment">//剩余大小</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$length</span> <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token boolean constant">false</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token variable">$contentLength</span> <span class="token operator">=</span> <span class="token variable">$length</span><span class="token punctuation">;</span>
        <span class="token variable">$isPartial</span> <span class="token operator">=</span> <span class="token boolean constant">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

//断点续传 记录下次下载的位置
if ($isPartial) {
header(‘HTTP/1.1 206 Partial Content’);
header(sprintf(‘Content-Range:bytes %s-%s/%s’, $startPos, $endPos, $fileSize));

<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    <span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"HTTP/1.1 200 OK"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token variable">$startPos</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token variable">$endPos</span> <span class="token operator">=</span> <span class="token variable">$contentLength</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//设置header头</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Pragma: cache'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Last-Modified: '</span> <span class="token punctuation">.</span> <span class="token function">gmdate</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"D, d M Y H:i:s"</span><span class="token punctuation">,</span> <span class="token variable">$lastModified</span><span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token single-quoted-string string">' GMT'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"ETag: <span class="token interpolation"><span class="token variable">$etag</span></span>"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Cache-Control: public, must-revalidate, max-age=0'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Accept-Ranges: bytes'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Content-Length: '</span> <span class="token punctuation">.</span> <span class="token variable">$contentLength</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"Content-Type: application/force-download"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"Content-Type: application/octet-stream"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"Content-Type: application/download"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">//对不同浏览器进行中文设置,避免下载导致文件名乱码</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$forceDownload</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">//处理中文文件名</span>
    <span class="token variable">$ua</span> <span class="token operator">=</span> <span class="token variable">$_SERVER</span><span class="token punctuation">[</span><span class="token double-quoted-string string">"HTTP_USER_AGENT"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">preg_match</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"/MSIE/"</span><span class="token punctuation">,</span> <span class="token variable">$ua</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">header</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Content-Disposition: attachment; filename="'</span> <span class="token punctuation">.</span> <span class="token function">rawurlencode</span><span class="token punctuation">(</span><span class="token variable">$fancyName</span><span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token single-quoted-string string">'"'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">preg_match</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"/Firefox/"</span><span class="token punctuation">,</span> <span class="token variable">$ua</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">header</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Content-Disposition: attachment; filename*="utf8\'\''</span> <span class="token punctuation">.</span> <span class="token function">rawurlencode</span><span class="token punctuation">(</span><span class="token variable">$fancyName</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token function">header</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Content-Disposition: attachment; filename="'</span> <span class="token punctuation">.</span> <span class="token variable">$fancyName</span> <span class="token punctuation">.</span> <span class="token single-quoted-string string">'"'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token keyword">else</span>
<span class="token punctuation">{</span>
    <span class="token function">header</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"Content-Disposition: attachment; filename="</span> <span class="token punctuation">.</span> <span class="token variable">$fancyName</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token variable">$bufferSize</span> <span class="token operator">=</span> <span class="token number">1024</span><span class="token punctuation">;</span><span class="token comment">//设置最小读取字节数 1kb</span>
<span class="token comment">//判断是否有设置下载速度</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token variable">$rate</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> 
<span class="token punctuation">{</span>
    <span class="token variable">$bufferSize</span> <span class="token operator">=</span> <span class="token variable">$rate</span> <span class="token operator">*</span> <span class="token variable">$bufferSize</span><span class="token punctuation">;</span> <span class="token comment">//100*1024 下载速度最大为100KB/s</span>
<span class="token punctuation">}</span>

<span class="token variable">$bytesSent</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token variable">$outputTimeStart</span> <span class="token operator">=</span> <span class="token number">0.00</span><span class="token punctuation">;</span>
<span class="token variable">$fp</span> <span class="token operator">=</span> <span class="token function">fopen</span><span class="token punctuation">(</span><span class="token variable">$file</span><span class="token punctuation">,</span> <span class="token double-quoted-string string">"rb"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">fseek</span><span class="token punctuation">(</span><span class="token variable">$fp</span><span class="token punctuation">,</span> <span class="token variable">$startPos</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token variable">$bytesSent</span> <span class="token operator">&lt;</span> <span class="token variable">$contentLength</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span><span class="token function">feof</span><span class="token punctuation">(</span><span class="token variable">$fp</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">connection_status</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token variable">$readBufferSize</span> <span class="token operator">=</span> <span class="token variable">$contentLength</span> <span class="token operator">-</span> <span class="token variable">$bytesSent</span> <span class="token operator">&lt;</span> <span class="token variable">$bufferSize</span> <span class="token operator">?</span> <span class="token variable">$contentLength</span> <span class="token operator">-</span> <span class="token variable">$bytesSent</span> <span class="token punctuation">:</span> <span class="token variable">$bufferSize</span><span class="token punctuation">;</span>
    <span class="token variable">$buffer</span> <span class="token operator">=</span> <span class="token function">fread</span><span class="token punctuation">(</span><span class="token variable">$fp</span><span class="token punctuation">,</span> <span class="token variable">$readBufferSize</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">echo</span> <span class="token variable">$buffer</span><span class="token punctuation">;</span>
    <span class="token comment">//输出缓冲</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token function">ob_get_level</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&gt;</span><span class="token number">0</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">ob_flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token variable">$bytesSent</span> <span class="token operator">+</span><span class="token operator">=</span> <span class="token variable">$readBufferSize</span><span class="token punctuation">;</span>
    <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//睡眠一秒 这里也就是限制下载速度的关键 一秒只读$readBufferSize字节</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token variable">$fp</span><span class="token punctuation">)</span> <span class="token function">fclose</span><span class="token punctuation">(</span><span class="token variable">$fp</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 

}
$file = ’./files/centos.zip’;
$rate = 1000; //下载速度 单位 kb/s
downFile($file,$rate,true);

评论 (0)

还没有评论,来做第一个吧。

发表评论

提交后需管理员审核通过后显示