您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息
免费发信息

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

2024/4/17 17:13:16发布6次查看
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($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();
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录