<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://jackxiang.com/post//</link>
<title><![CDATA[ 断点续传的原理,PHP断点续传 HTTP学习笔记。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Php/Js/Shell/Go]]></category>
<pubDate>Thu, 11 Apr 2013 04:12:49 +0000</pubDate> 
<guid>http://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	打造nginx为高效的上传附件服务器:(对立面的逻辑做了修改，好像是不用PHP来处理了)<br/>http://hi.baidu.com/hackers365/item/ddaa0d2f91cc4886ae48f571<br/><br/>作者微博客：http://t.lava.cn/w/23651 下载地址也在立面。 2013-04-14 15:15：00<br/>hack掉nginx_http_upload模块，添加了一个新的变量upload_file_md5_last。此变量可以得到最后一个文件的md5值。。。在这个问题上绊了两三个星期。昨天搞到十一点多。还是无果。今天早上给老婆发誓。今天整不好。晚上不睡觉。。。终于在最后一刻搞定了。。。耶。可以睡觉了。。<br/><br/>详细：<br/>在ngx_http_upload的模块变量upload_file_md5的get_handler里。它是每次动态生成的。。只有第一次使用的时候是正确的值。以后每次使用。get_handler里都会改变。。得不到正确的值。。所以。我就给它添加了一个变量upload_file_md5_last可以得到最后一个文件md5值。。。好了。可以继续下面未完成的工作了。<br/>附件是修改之后的ngx_upload模块。<br/><br/><br/>断点续传的原理 ：http://blog.csdn.net/oathevil/article/details/7752799<br/>摘抄如下：其实断点续传的原理很简单 <br/>其实断点续传的原理很简单，就是在Http的请求上和一般的下载有所不同而已。 <br/>打个比方，浏览器请求服务器上的一个文时，所发出的请求如下： <br/>假设服务器域名为wwww.sjtu.edu.cn，文件名为down.zip。 <br/>GET /down.zip HTTP/1.1 <br/>Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms- <br/>excel, application/msword, application/vnd.ms-powerpoint, */* <br/>Accept-Language: zh-cn <br/>Accept-Encoding: gzip, deflate <br/>User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) <br/>Connection: Keep-Alive <br/>服务器收到请求后，按要求寻找请求的文件，提取文件的信息，然后返回给浏览器，返回信息如下： <br/>200 <br/>Content-Length=106786028 <br/>Accept-Ranges=bytes <br/>Date=Mon, 30 Apr 2001 12:56:11 GMT <br/>ETag=W/&quot;02ca57e173c11:95b&quot; <br/>Content-Type=application/octet-stream <br/>Server=Microsoft-IIS/5.0 <br/>Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT <br/>所谓断点续传，也就是要从文件已经下载的地方开始继续下载。所以在客户端浏览器传给 <br/>Web服务器的时候要多加一条信息--从哪里开始。 <br/>下面是用自己编的一个&quot;浏览器&quot;来传递请求信息给Web服务器，要求从2000070字节开始。 <br/>GET /down.zip HTTP/1.0 <br/>User-Agent: NetFox <br/>RANGE: bytes=2000070- <br/>Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 <br/>仔细看一下就会发现多了一行RANGE: bytes=2000070- <br/>这一行的意思就是告诉服务器down.zip这个文件从2000070字节开始传，前面的字节不用传了。 <br/>服务器收到这个请求以后，返回的信息如下： <br/>206 <br/>Content-Length=106786028 <br/>Content-Range=bytes 2000070-106786027/106786028 <br/>Date=Mon, 30 Apr 2001 12:55:20 GMT <br/>ETag=W/&quot;02ca57e173c11:95b&quot; <br/>Content-Type=application/octet-stream <br/>Server=Microsoft-IIS/5.0 <br/>Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT <br/>和前面服务器返回的信息比较一下，就会发现增加了一行： <br/>Content-Range=bytes 2000070-106786027/106786028 <br/>返回的代码也改为206了，而不再是200了。 <br/>知道了以上原理，就可以进行断点续传的编程了。<br/><br/><br/><br/>PHP断点续传 HTTP学习笔记：http://blog.hao909.com/php%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0-http%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/<br/><br/>HTTP断点续传原理是这样的：<br/><br/>1. 客户端需要告诉服务器端从哪里开始。<br/>2.服务端收到请求,返回206状态。并标识续传的起始点及结束点<br/><br/>如下实例<br/><br/>1. 客户端传递请求信息给web服务器，要求从200070字节开始。。<br/><br/>GET /down.zip HTTP/1.1<br/>User-Agent：NetFox<br/>RANGE: bytes = 200070-<br/>Accept：text/html，image/gif，image/jpeg，*；q=.2，*/*；q=.2<br/><br/>2.服务端收到这个请求以后，返回信息<br/><br/>206<br/>Content-Length = 100222222<br/>Content-Range = bytes 200070 – 100222221/100222222<br/>Content-Type=application/octet-stream<br/><br/>注意：服务端状态 206； Content-Range = bytes （客户端请求续传起始点） – （下载文件大小-1）/（下载文件大小）<br/><br/>在PHP中，是利用$_SERVER[&#039;HTTP-RANGE&#039;]来取得客户端请求的续传起始点。所以其实现代码如下:<br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php
/**
 *&nbsp;&nbsp;PHP-HTTP断点续传实现
 *&nbsp;&nbsp;@param string $path: 文件所在路径
 *&nbsp;&nbsp;@param string $file: 文件名
 *&nbsp;&nbsp;@return void
 */

function download($path,$file) &#123;

&nbsp;&nbsp;&nbsp;&nbsp;$real = $path.&#039;/&#039;.$file;

&nbsp;&nbsp;&nbsp;&nbsp;if(!file_exists($real)) &#123;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;

&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;$size = filesize($real);
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;$size2 = $size-1;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;$range = 0;

&nbsp;&nbsp;&nbsp;&nbsp;if(isset($_SERVER[&#039;HTTP_RANGE&#039;])) &#123;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&#039;HTTP /1.1 206 Partial Content&#039;);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$range = str_replace(&#039;=&#039;,&#039;-&#039;,$_SERVER[&#039;HTTP_RANGE&#039;]);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$range = explode(&#039;-&#039;,$range);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$range = trim($range[1]);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&#039;Content-Length:&#039;.$size);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&#039;Content-Range: bytes &#039;.$range.&#039;-&#039;.$size2.&#039;/&#039;.$size);

&nbsp;&nbsp;&nbsp;&nbsp;&#125; else &#123;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&#039;Content-Length:&#039;.$size);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&#039;Content-Range: bytes 0-&#039;.$size2.&#039;/&#039;.$size);

&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;header(&#039;Accenpt-Ranges: bytes&#039;);

&nbsp;&nbsp;&nbsp;&nbsp;header(&#039;application/octet-stream&#039;);

&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Cache-control: public&quot;);

&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Pragma: public&quot;);

&nbsp;&nbsp;&nbsp;&nbsp;$ua = $_SERVER[&#039;HTTP_USER_AGENT&#039;];

&nbsp;&nbsp;&nbsp;&nbsp;if(preg_match(&#039;/MISE/&#039;,$ua)) &#123;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$ie_filename = str_replace(&#039;+&#039;,&#039;%20&#039;,urlencode($file));

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&#039;Content-Dispositon:attachment; filename=&#039;.$ie_filename);

&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;else &#123;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&#039;Content-Dispositon:attachment; filename=&#039;.$file);

&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;$fp = fopen($real,&#039;rb+&#039;);

&nbsp;&nbsp;&nbsp;&nbsp;fseek($fp,$range);

&nbsp;&nbsp;&nbsp;&nbsp;while(!feof($fp)) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_time_limit(0);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(fread($fp,1024));

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flush();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ob_flush();

&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;fclose($fp);

&#125;
?&gt;

</textarea><br/><br/>以下是另外一段代码样例 ：<br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php 
/*
 * PHP下载断点续传
 */
function dl_file_resume($file)&#123; 

&nbsp;&nbsp;&nbsp;&nbsp;//检测文件是否存在 
&nbsp;&nbsp;&nbsp;&nbsp;if (!is_file($file)) &#123; die(&quot;&lt;b&gt;404 File not found!&lt;/b&gt;&quot;); &#125; 
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;$len = filesize($file);//获取文件大小 
&nbsp;&nbsp;&nbsp;&nbsp;$filename = basename($file);//获取文件名字 
&nbsp;&nbsp;&nbsp;&nbsp;$file_extension = strtolower(substr(strrchr($filename,&quot;.&quot;),1));//获取文件扩展名 
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;//根据扩展名 指出输出浏览器格式 
&nbsp;&nbsp;&nbsp;&nbsp;switch( $file_extension ) &#123; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case &quot;exe&quot;: $ctype=&quot;application/octet-stream&quot;; break; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case &quot;zip&quot;: $ctype=&quot;application/zip&quot;; break; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case &quot;mp3&quot;: $ctype=&quot;audio/mpeg&quot;; break; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case &quot;mpg&quot;:$ctype=&quot;video/mpeg&quot;; break; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case &quot;avi&quot;: $ctype=&quot;video/x-msvideo&quot;; break; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default: $ctype=&quot;application/force-download&quot;; 
&nbsp;&nbsp;&nbsp;&nbsp;&#125; 
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;//Begin writing headers 
&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Cache-Control:&quot;); 
&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Cache-Control: public&quot;); 
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;//设置输出浏览器格式 
&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Content-Type: $ctype&quot;); 
&nbsp;&nbsp;&nbsp;&nbsp;if (strstr($_SERVER[&#039;HTTP_USER_AGENT&#039;], &quot;MSIE&quot;)) &#123;//如果是IE浏览器 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# workaround for IE filename bug with multiple periods / multiple dots in filename 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# that adds square brackets to filename - eg. setup.abc.exe becomes setup[1].abc.exe 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$iefilename = preg_replace(&#039;/&#92;./&#039;, &#039;%2e&#039;, $filename, substr_count($filename, &#039;.&#039;) - 1); 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Content-Disposition: attachment; filename=&#92;&quot;$iefilename&#92;&quot;&quot;); 
&nbsp;&nbsp;&nbsp;&nbsp;&#125; else &#123; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Content-Disposition: attachment; filename=&#92;&quot;$filename&#92;&quot;&quot;); 
&nbsp;&nbsp;&nbsp;&nbsp;&#125; 
&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Accept-Ranges: bytes&quot;); 
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;$size=filesize($file); 
&nbsp;&nbsp;&nbsp;&nbsp;//如果有$_SERVER[&#039;HTTP_RANGE&#039;]参数 
&nbsp;&nbsp;&nbsp;&nbsp;if(isset($_SERVER[&#039;HTTP_RANGE&#039;])) &#123; 
/*&nbsp;&nbsp; --------------------------- 
&nbsp;&nbsp; Range头域 　　Range头域可以请求实体的一个或者多个子范围。例如， 　　表示头500个字节：bytes=0-499 　　表示第二个500字节：bytes=500-999 　　表示最后500个字节：bytes=-500 　　表示500字节以后的范围：bytes=500- 　　第一个和最后一个字节：bytes=0-0,-1 　　同时指定几个范围：bytes=500-600,601-999 　　但是服务器可以忽略此请求头，如果无条件GET包含Range请求头，响应会以状态码206（PartialContent）返回而不是以200 （OK）。 
&nbsp;&nbsp; ---------------------------*/ 

// 断点后再次连接 $_SERVER[&#039;HTTP_RANGE&#039;] 的值 bytes=4390912- 
&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list($a, $range)=explode(&quot;=&quot;,$_SERVER[&#039;HTTP_RANGE&#039;]); 
&nbsp;&nbsp; //if yes, download missing part 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;str_replace($range, &quot;-&quot;, $range);//这句干什么的呢。。。。 
&nbsp;&nbsp; $size2=$size-1;//文件总字节数 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$new_length=$size2-$range;//获取下次下载的长度 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;HTTP/1.1 206 Partial Content&quot;); 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Content-Length: $new_length&quot;);//输入总长 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Content-Range: bytes $range$size2/$size&quot;);//Content-Range: bytes 4908618-4988927/4988928&nbsp;&nbsp; 95%的时候 
&nbsp;&nbsp;&nbsp;&nbsp;&#125; else &#123;//第一次连接 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$size2=$size-1; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Content-Range: bytes 0-$size2/$size&quot;); //Content-Range: bytes 0-4988927/4988928 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&quot;Content-Length: &quot;.$size);//输出总长 
&nbsp;&nbsp;&nbsp;&nbsp;&#125; 
&nbsp;&nbsp;&nbsp;&nbsp;//打开文件 
&nbsp;&nbsp;&nbsp;&nbsp;$fp=fopen(&quot;$file&quot;,&quot;rb&quot;); 
&nbsp;&nbsp;&nbsp;&nbsp;//设置指针位置 
&nbsp;&nbsp;&nbsp;&nbsp;fseek($fp,$range); 
&nbsp;&nbsp;&nbsp;&nbsp;//虚幻输出 
&nbsp;&nbsp;&nbsp;&nbsp;while(!feof($fp))&#123; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//设置文件最长执行时间 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_time_limit(0); 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(fread($fp,1024*8));//输出文件 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flush();//输出缓冲 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ob_flush(); 
&nbsp;&nbsp;&nbsp;&nbsp;&#125; 
&nbsp;&nbsp;&nbsp;&nbsp;fclose($fp); 
&nbsp;&nbsp;&nbsp;&nbsp;exit; 
&#125; 

dl_file_resume(&quot;1.zip&quot;);//同级目录的1.zip 文件 


//---------------------------------------
//不支持断点续传的文件下载。 
//---------------------------------------
 
downFile(&quot;1.zip&quot;); 

function downFile($sFilePath) 
&#123; 
&nbsp;&nbsp; if(file_exists($sFilePath))&#123; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $aFilePath=explode(&quot;/&quot;,str_replace(&quot;&#92;&#92;&quot;,&quot;/&quot;,$sFilePath),$sFilePath); 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $sFileName=$aFilePath[count($aFilePath)-1]; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $nFileSize=filesize ($sFilePath); 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; header (&quot;Content-Disposition: attachment; filename=&quot; . $sFileName); 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; header (&quot;Content-Length: &quot; . $nFileSize); 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; header (&quot;Content-type: application/octet-stream&quot;); 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; readfile($sFilePath); 
&nbsp;&nbsp; &#125; 
&nbsp;&nbsp; else 
&nbsp;&nbsp; &#123; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo(&quot;文件不存在!&quot;); 
&nbsp;&nbsp; &#125; 
&#125; 
?&gt;

</textarea><br/><br/>更多参考：http://hi.baidu.com/zdfgng/item/e220da1403077a781009b55e
]]>
</description>
</item><item>
<link>http://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论]  断点续传的原理,PHP断点续传 HTTP学习笔记。]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>