PHP实现断点下载

function onaction() {
		ob_start();	//Turn on output buffering
		/*
		 * 通过 ob_start()手动激活php output_buffering机制,使得即便输出超过了1kb数据,
		 * 也不真的把数据交给tcp传给浏览器,因为ob_start()将php buffer空间设置到了足够大 。
		 * 只有直到脚本结束,或者调用ob_end_flush函数,才会把数据发送给客户端浏览器。
		 */
		Header("Content-type: application/octet-stream");	//定义传送文件的格式
		Header("Cache-Control: must-revalidate, post-check=0, pre-check=0");	//不缓存
		$id = $_REQUEST['id'];
		$type = $_REQUEST['type'];
		if (!empty($id)) {
			
			$data = $this->model['down']->get_data($id);	//从数据库中知道id=$id的数据
			
			if ($data){
				
				$p_name = $data['p_name'];
				$img = $data['smallImg'];
				if ($type == 'app') {
					$fullpath = SOFTPATH . $p_name;
					$filename = $p_name;
				} elseif ($type == 'icon') {
					$fullpath = IMGPATH . $img;
					$filename = $img;
				}
				
				header("Cache-Control: public");	//指明响应可被任何缓存保存
				header("Accept-Ranges: bytes");		//产生字节范围请求
				
				$size = filesize($fullpath);
				
				$size1=$size-1;
				/*
				 * 实现断点传送功能,用$_SERVER['HTTP_RANGE']取得取得用户请求的文件的range,
				 * 然后程序去控制文件的输出。比如第一次请求一个文件的从0到999字节,第二次请求1000到1999
				 * 字节,以此类推,每次请求1000字节的内容,然后程序通过fseek函数去取得对应的文件位置,
				 * 然后输出。
				 */
				if(isset($_SERVER['HTTP_RANGE'])){
					list($name, $range) = explode("=",$_SERVER['HTTP_RANGE']);
					$length=$size1-$range;
					header("HTTP/1.1 206 Partial Content");	//部分内容,表示需要续传
					header("Content-Range: bytes ".$range."-".$size1."/".$size);
					/*
					 * $rang是可变的,如果是手机,在下载东西的时候,可能来了电话打断下载。那么在电话
					 * 结束之后,重新请求,$rang表示已经下载的大小,这样才是完成断点续传功能。
					 */
				}
				else{
					$length=$size;
				}
				header('Content-type: application/octet-stream;charset=gbk');
				header("Content-Length: " . $length);
				header("Content-Disposition: attachment; filename=".$filename);
			
				$fp=fopen($fullpath,'rb');
				/*
				 * 不同的操作系统家族具有不同的行结束习惯。当写入一个文本文件并想插入一个新行时,需要使
				 * 用符合操作系统的行结束符号。基于 Unix 的系统使用 \n作为行结束字符,基于 Windows 的系统
				 * 使用 \r\n作为行结束字符,基于 Macintosh 的系统使用 \r作为行结束字符。 
				 * 如果写入文件时使用了错误的行结束符号,则其它应用程序打开这些文件时可能会表现得很怪异。 
				 * Windows 下提供了一个文本转换标记('t')可以透明地将 \n 转换为 \r\n。与此对应还可以
				 * 使用 'b' 来强制使用二进制模式,这样就不会转换数据。要使用这些标记,要么用 'b' 或者用 't' 
				 * 作为 mode 参数的最后一个字符。
				 */
				fseek($fp,$range);	//在文件指针中定位
				while(!feof($fp)){	//测试文件指针是否到了文件结束的位置
					set_time_limit(0);	//设置脚本最大执行时间 0 表示没有限制
					echo fread($fp,1024); //读取文件(可安全用于二进制文件),从文件指针 handle 读取最多 length 个字节
					flush();//该函数将当前为止程序的所有输出发送到用户的浏览器。
					ob_flush();//flush() 函数不会对服务器或客户端浏览器的缓存模式产生影响。因此,必须同时使用 ob_flush()
								// 和flush() 函数来刷新输出缓冲。 
				}
				fclose($fp);
				
			}
		}
}


你可能感兴趣的:(PHP,浏览器,server,header,FP,output)