利用php实现一个简单类,支持文件断点续传。 只是个demo, http range实现并不完整,但是对于普通的浏览器的下载没有问题。
<?php
//PHPXFileDownload v1.0
class File{
private $fp;
private $file;
private $name;
private $path;
private $mime;
private $size;
public function __construct($filename,$filepath){
ob_start();
$this->name = $filename;
$this->path = $filepath;
$this->file = "$filepath/$filename";
if (!$this->initFile()){
throw new Exception("File Error!");
}
}
public function __destruct(){
if ($this->fp){
flock($this->fp, LOCK_UN);
fclose($this->fp);
}
}
private function initFile(){
if (!file_exists($this->file))
return false;
$f = new finfo(FILEINFO_MIME_TYPE);
$this->mime = $f->file($this->file);
if ($this->mime === FALSE)
return false;
$this->size = filesize($this->file);
if ($this->size === FALSE)
return false;
$this->fp = fopen($this->file,"rb");
if ($this->fp === FALSE)
return false;
$ret = flock($this->fp, LOCK_SH | LOCK_NB);
if ($ret === FALSE){
fclose($this->fp);
$this->fp = FALSE;
return false;
}
return true;
}
public function getSize(){
return $this->size;
}
public function getMime(){
return $this->mime;
}
public function download(){
if (ob_get_contents() != ""){
throw new Exception("Have output before the file transfer");
}
ob_end_clean();
$start = 0;
$end = $this->size - 1;
if(isset($_SERVER['HTTP_RANGE'])) { //客户端要求断点续传
$range = $this->getRange($_SERVER['HTTP_RANGE']);
if ($range === false || $this->checkRange($range[0],$range[1])){
header('HTTP/1.1 416 Requested Range Not Satisfiable');
return false;
}
$start = (int)($range[0]);
$end = (int)($range[1]);
header('HTTP/1.1 206 Partial Content');
header('Content-Length:'.($end - $start + 1));
header('Content-Range: bytes '.$start.'-'.$end.'/'.$this->size);
$this->sendCommonHead();
}else{ //普通传输
header('Content-Length:'.$this->size);
$this->sendCommonHead();
}
fseek($this->fp,$start);
echo fread($this->fp,$end - $start + 1);
}
private function checkRange($start,$end){
if ($start < $end)
return false;
if ($end>=$this->size)
return false;
return true;
}
private function getRange($http_range){
$range = [];
$http_range = substr($http_range,strpos($http_range,"=")+1);
$http_range = explode('-',$http_range);
if (count($http_range)!=2)
return false;
if ($http_range[0] == "")
$range[0] = 0;
else
$range[0] = (int)($http_range[0]);
if ($http_range[1] == "")
$range[1] = $this->size - 1;
else
$range[1] = (int)($http_range[1]);
if ($range[0] > $range[1])
return false;
return $range;
}
private function sendCommonHead(){
header('Content-Disposition: attachment; filename="' . $this->name .'"' );
header("Content-Type: application/octet-stream");
header('Accept-Ranges: bytes');
}
}
##测试代码
$file = new File("test.mp3","./");
$file->download();