• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

php 实现文件下载 断点续传 原理

php 搞代码 4年前 (2022-01-23) 28次浏览 已收录 0个评论

php 实现文件下载 断点续传 原理

php文件下载

文件下载就是把文件从服务器上面下下来,比如一个文件是http://www.xxx.com/1.rar(真实存在这个文件),直接在浏览器上面输入,是可以弹出下载对话框的,但是如果是一个图片地址,很可能就是不是下载了,而是用浏览器直接打开.还有就是为了不让客户端看到下载地址,最好也是不直接提供下载文件地址的.还有就是比如只有登录用户才能下载。。 等等 .所以还是要单独写个下载程序

有几个响应头比较重要,记录下

Content-type

Content-Disposition

Content-Length

Pragma

Cache-control

Content-type

Content-type 告诉浏览器文件的MIME 类型,这是非常重要的一个响应头了,MIME种类繁多,真是太多了

Content-Disposition

Content-Disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。当 Internet Explorer 接收到头时,它会激活文件下载对话框,它的文件名框自动填充了头中指定的文件名。 嗯,就是这个头哟,激活弹出提示下载框

因为MIME的类型非常多,很可能会在程序中漏掉一些MIME类型.可以这样,漏掉了类型,全部以“Content-type: application/octet-stream” “Content-Disposition: attachment; filename=xxx.xx”(xx.xx为文件名) 经过一些浏览器的测试发现下载下来的文件都是正确的

Content-Length

“Content-Length: 123” 就是告诉浏览器这个文件的大小是123字节,其实我发现好像不设置这个头,浏览器也能自己识别

Pragma Cache-control

把这2个头都设置成public 告诉浏览器缓存(其实对于缓存头 我有很多都没理解清楚 除了public 它表示全部都缓存,但是至于浏览器缓存不缓存,可能还不一定,我试了很多浏览器,没有一个是从浏览器缓存读文件的,但是从服务器上下的)

在输出文件的时候,我看网上大概有2中方式:一种是一次性输出,一中是分段输出(每次输出一部分),我去csdn问了下,别人说分段输出好,减轻服务器压力,因为每次读文件的时候占的内存都少

一个例子(里面的MIME很少,更多的MIME最好去网上找)

class downLoad{	var $file_name;	var $file_dir;	var $buffer_size = 1024;	var $err = "";	public static $MIME_type = array(								"pdf"  =>"application/pdf",								"exe"  =>"application/octet-stream",								"zip"  =>"application/zip",								"doc"  =>"application/msword",								"xls"  =>"application/vnd.ms-excel",								"ppt"  =>"application/vnd.ms-powerpoint",								"gif"  =>"image/gif",								"png"  =>"image/png",								"jpeg" =>"jpg",								"mp3"  =>"audio/mpeg",								"wav"  =>"audio/x-wav",								"mpeg" =>"mpg",								"mpe"  =>"video/mpeg",								"mov"  =>"video/quicktime",								"avi"  =>"video/x-msvideo",											);	public function __construct($file_dir="",$file_name=""){		$this->file_dir  = $file_dir;		$this->file_name = $file_name;		$this->path = $file_dir."/".$file_name;		$this->suffix = pathinfo($file_name,PATHINFO_EXTENSION);	}		public function down(){		if(!file_exists($this->path)){			$this->err = "该文件被移除了";			return false;		}		$content_type = $this->getMIME($this->suffix);		$file_size = filesize($this->path);				header("Content-type: ".$content_type);		header('Content-Disposition: attachment; filename="'.$this->file_name.'"');				@header("Cache-control: public");		@header("Pragma: public"); 		header("Content-Length: ".$file_size);		ob_end_clean(); 		//readfile($this->path); 一次性读出来		$fp= fopen($this->path,"r");		$buffer_size = $this->buffer_size;		$cur_pos = 0; //记录读了多少了				while(!feof($fp) && $file_size>$buffer_size+$cur_pos){			$buffer = fread($<span>!本文来源gaodai#ma#com搞*!代#%^码网5</span><pre>搞gaodaima代码

fp,$buffer_size); //每次读1024字节 echo $buffer; $cur_pos += $buffer_size; } //把剩下的读出来 因为文件的带下很有很能不是1024 的整数倍 $buffer = fread($fp,$file_size-$cur_pos); echo $buffer; fclose($fp); return true; } public function getMIME($key=””){ if($key == “” || !isset(self::$MIME_type[$key])){ return “application/octet-stream”; } return self::$MIME_type[$key]; }}// $x = new downLoad($file_dir,$file_name); $file_dir路径 比如 all $file_name文件名 比如 a.exe 合起来就是全部的路径了all/a.exe// $x->down();

php 断点续传

这里面的断点续传指的是下载时候的断点续传的断点续传,上传的断点续传完全不明白原理

一些预备的东西

http 状态码206的意思

响应头 “Accept-Ranges: bytes”

响应头 “Content-Range:bytes start-end/all”

fseek

ob_flush

http 状态码 206

请求的 header 必须包含一个 Range 字段,表明自己请求第几个字节到第几个字节的内容。如果服务器支持的话,就返回 206 Partial Content,然后使用 header 的 Content-Range 指明范围,并在 body 内提供这个范围内的数据。

Accept-Ranges: bytes

这个字段说明Web服务器是否支持Range(是否支持断点续传功能),如果支持,则返回Accept-Ranges: bytes,如果不支持,则返回Accept-Ranges: none.

Content-Range:

用于响应头,指定了返回的Web资源的字节范围。这个字段值的格式是: 开始字节位置—结束字节位置/Web资源的总字节数,一个例子:Content-Range:1000-3000/5000

fseek : 该函数把文件指针从当前位置向前或向后移动到新的位置,新位置从文件头开始以字节数度量

ob_flush : 该函数把文件指针从当前位置向前或向后移动到新的位置,新位置从文件头开始以字节数度量

我测试了一下 ie7,8是不支持断点续传的(也许可以 但是我不会),苹果浏览器也不行.哎………. (还好 firefox chrome Opera支持)

断点续传的过程是这样的

首先客户端发一次请求给php请求下载文件
这时因为是第一次请求 所以请求头里面是没有 Range头的
我用Fiddler抓包的截图
请求头

在php端 $_SERVER[‘HTTP_RANGE’]可以取请求头里面的Rang, 因为第一次不存在这个,所以我们取文件内容就取全部,然后返回的状态码也是200

响应头

当传了一部分内容后,点击暂停,在点击几乎继续,抓包的响应头就有Range了

php端返回的时候也把返回内容的范围返回了 Content-Range: bytes 4194304-37939151/37939152 是返回数据的范围
Accept-Ranges: bytes表示支持断点续传
Content-Length: 33744847 里面的值是根据请求的Range, 也就是 $_SERVER[‘HTTP_RANGE’], 和文件的总大小,相减得出来的
另外http状态码是206

例子

	class downLoad	{		var $file_path;		var $file_name;		var $file_suffix;		var $speed = 1024; //表示下载速度1m		var $err = "";		var $range_start=0;		var $range_end;		var $http_range;		var $file_size;		public static $MIME_type = array(									"pdf"  =>"application/pdf",									"exe"  =>"application/octet-stream",									"zip"  =>"application/zip",									"doc"  =>"application/msword",									"xls"  =>"application/vnd.ms-excel",									"ppt"  =>"application/vnd.ms-powerpoint",									"gif"  =>"image/gif",									"png"  =>"image/png",									"jpeg" =>"jpg",									"mp3"  =>"audio/mpeg",									"wav"  =>"audio/x-wav",									"mpeg" =>"mpg",									"mpe"  =>"video/mpeg",									"mov"  =>"video/quicktime",									"avi"  =>"video/x-msvideo",												);		public function __construct($file_path="",$http_ranges="",$speed=""){			$this->file_path = $file_path;			$this->file_name = basename($file_path);			$this->file_suffix = substr(strrchr($this->file_name, '.'),1);			$this->file_size= filesize($file_path);			$this->http_range = (isset($http_ranges) && !empty($http_ranges)!="")?$http_ranges:false;			!empty($speed)&&($this->speed = $speed);  		}		public function down(){			if(!file_exists($this->file_path)){				$this->err = "该文件被移除";				return false;			}			$file_path = $this->file_path;			$content_type = $this->getMIME($this->file_suffix);			$http_range = $this->http_range;			if($http_range){				//$http_range 的形式为 bytes=3145728-  差不多就是这个样子的				$http_range = preg_replace('/[\s|,]*/', '', $http_range);				$arr = explode('-',substr($http_range,6));				$this->range_start = ( isset($arr[0]) && !empty($arr[0]) ) ? $arr[0] : 0;				$this->range_end   = ( isset($arr[1]) && !empty($arr[1]) && $arr[1]!=0 ) ? $arr[1] : $this->file_size-1;			}			$this->setHeader();						$fh =  fopen($file_path, "rb");						fseek($fh, $this->range_start);						$speed = $this->speed;			while(!feof($fh))			{				echo fread($fh, 1024*$speed);				ob_flush();				sleep(1);			}			fclose($fh);		}		public function getMIME($key=""){			if($key=="" || !isset(self::$MIME_type[$key])){				return "application/octet-stream";			}			return self::$MIME_type[$key];		}		public function setHeader(){			header('Cache-control: public');			header('Content-Type: application/octet-stream');			header('Content-Disposition: attachment; filename='.$this->file_name);									if($this->http_range){				$range_start = $this->range_start;				$range_end = $this->range_end;				header('HTTP/1.1 206 Partial Content');				header('Accept-Ranges: bytes');				header( sprintf('Content-Length: %u',$range_end - $range_start) );				header( sprintf('Content-Range: bytes %s-%s/%s', $range_start, $range_end, $this->file_size) );			}else{				header("HTTP/1.1 200 OK");				header(sprintf('Content-Length: %s',$this->file_size));			}		}	}	//$http_range = isset($_SERVER['HTTP_RANGE'])?$_SERVER['HTTP_RANGE']:false;	//$x = new downLoad("all/1.exe",$http_range);	//$x->down();

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:php 实现文件下载 断点续传 原理

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址