这是一个功能齐全的 PHP 下载类,基本原理是将文件切片处理,这里贴上代码附调用方法,可以研究和使用。

<?php
class httpdownload {
	var $data = null;
	var $data_len = 0;
	var $data_mod = 0;
	var $data_type = 0;
	var $data_section = 0; //section download
	var $sentSize=0;
	var $handler = array('auth' => null);
	var $use_resume = true;
	var $use_autoexit = false;
	var $use_auth = false;
	var $filename = null;
	var $mime = null;
	var $bufsize = 2048;
	var $seek_start = 0;
	var $seek_end = -1;
	var $totalsizeref = 0;
	var $bandwidth = 0;
	var $speed = 0;

	function initialize(){
		global $HTTP_SERVER_VARS;

		if($this->use_auth){// use authentication
			if(!$this->_auth()){// no authentication
				header('WWW-Authenticate: Basic realm="Please enter your username and password"');
				header('HTTP/1.0 401 Unauthorized');
				header('status: 401 Unauthorized');

				if($this->use_autoexit) exit();

				return false;
			}
		}

		if($this->mime == null){
			$this->mime = "application/octet-stream"; //default mime
		}

		if(isset($_SERVER['HTTP_RANGE']) || isset($HTTP_SERVER_VARS['HTTP_RANGE'])){
			if(isset($HTTP_SERVER_VARS['HTTP_RANGE'])){
				$seek_range = substr($HTTP_SERVER_VARS['HTTP_RANGE'] , strlen('bytes='));
			}else{
				$seek_range = substr($_SERVER['HTTP_RANGE'] , strlen('bytes='));
			}

			$range = explode('-',$seek_range);

			if($range[0] > 0){
				$this->seek_start = intval($range[0]);
			}

			if($range[1] > 0){
				$this->seek_end = intval($range[1]);
			}else{
				$this->seek_end = -1;
			}

			if(!$this->use_resume){
				$this->seek_start = 0;
				//header("HTTP/1.0 404 Bad Request");
				//header("Status: 400 Bad Request");
				//exit;
				//return false;
			}else{
				$this->data_section = 1;
			}
		}else{
			$this->seek_start = 0;
			$this->seek_end = -1;
		}

		$this->sentSize=0;

		return true;
	}

	function header($size, $seek_start=null, $seek_end=null){
		header('Content-type: ' . $this->mime);
		header('Content-Disposition: attachment; filename="' . $this->filename . '"');
		header('Last-Modified: ' . date('D, d M Y H:i:s \G\M\T' , $this->data_mod));

		if($this->data_section && $this->use_resume){
			header("HTTP/1.0 206 Partial Content");
			header("Status: 206 Partial Content");
			header('Accept-Ranges: bytes');
			header("Content-Range: bytes $seek_start-$seek_end/$size");
			header("Content-Length: " . ($seek_end - $seek_start + 1));
		}else{
			header("Content-Length: $size");
		}
	}

	function download_ex($size){
		if(!$this->initialize()){
			return false;
		}

		ignore_user_abort(true);

		//Use seek end here
		if($this->seek_start > ($size - 1)){
			$this->seek_start = 0;
		}

		if($this->seek_end <= 0){
			$this->seek_end = $size - 1;
		}

		$this->header($size, $seek, $this->seek_end);
		$this->data_mod = time();

		return true;
	}

	function download(){
		if(!$this->initialize()){
			return false;
		}

		try{
			error_log("begin download\n", 3, LOG_PATH.'download.error');

			$seek = $this->seek_start;
			$speed = $this->speed;
			$bufsize = $this->bufsize;
			$packet = 1;

			//do some clean up
			@ob_end_clean();
			$old_status = ignore_user_abort(true);
			@set_time_limit(0);
			$this->bandwidth = 0;
			$size = $this->data_len;

			if($this->data_type == 0){//download from a file
				$size = filesize($this->data);

				if($seek > ($size - 1)){
					$seek = 0;
				}

				if($this->filename == null){
					$this->filename = basename($this->data);
				}

				$res = fopen($this->data,'rb');

				if($seek){
					fseek($res , $seek);
				}

				if($this->seek_end < $seek){
					$this->seek_end = $size - 1;
				}

				$this->header($size,$seek,$this->seek_end); //always use the last seek
				$size = $this->seek_end - $seek + 1;

				while(!(connection_aborted() || connection_status() == 1) && $size > 0){
					if($size < $bufsize){
						echo fread($res, $size);
						$this->bandwidth += $size;
						$this->sentSize += $size;
					}else{
						echo fread($res, $bufsize);
						$this->bandwidth += $bufsize;
						$this->sentSize += $bufsize;
					}

					$size -= $bufsize;

					@ob_flush();
					@flush();

					if($speed > 0 && ($this->bandwidth > $speed*$packet*1024)){
						sleep(1);
						$packet++;
					}
				}
				fclose($res);
			}else if($this->data_type == 1){//download from a string
				if($seek > ($size - 1)){
					$seek = 0;
				}

				if($this->seek_end < $seek){
					$this->seek_end = $this->data_len - 1;
				}

				$this->data = substr($this->data, $seek, $this->seek_end - $seek + 1);

				if($this->filename == null){
					$this->filename = time();
				}

				$size = strlen($this->data);
				$this->header($this->data_len, $seek, $this->seek_end);

				while(!connection_aborted() && $size > 0){
					if($size < $bufsize){
						$this->bandwidth += $size;
						$this->sentSize += $size;
					}else{
						$this->bandwidth += $bufsize;
						$this->sentSize += $bufsize;
					}

					echo substr($this->data, 0, $bufsize);
					$this->data = substr($this->data, $bufsize);
					$size -= $bufsize;

					@ob_flush();
					@flush();

					if($speed > 0 && ($this->bandwidth > $speed*$packet*1024)){
						sleep(1);
						$packet++;
					}
				}
			}else if($this->data_type == 2){
				//just send a redirect header
				header('location: ' . $this->data);
			}

			if($this->totalsizeref==$this->sentSize ){
				error_log("end download\n", 3, LOG_PATH.'download.error');
			}else{
				error_log("download is canceled\n", 3, LOG_PATH.'download.error');
			}

			if($this->use_autoexit){
				exit();
			}

			//restore old status
			ignore_user_abort($old_status);
			set_time_limit(ini_get("max_execution_time"));
		}catch(Exception $e){
			error_log("cancel download\n".$e, 3, LOG_PATH.'download.error');
		}

		return true;
	}

	function set_byfile($dir){
		if(is_readable($dir) && is_file($dir)){
			$this->data_len = 0;
			$this->data = $dir;
			$this->data_type = 0;
			$this->data_mod = filemtime($dir);
			$this->totalsizeref = filesize($dir);

			return true;
		}else{
			return false;
		}
	}

	function set_bydata($data){
		if($data == ''){
			return false;
		}

		$this->data = $data;
		$this->data_len = strlen($data);
		$this->data_type = 1;
		$this->data_mod = time();

		return true;
	}

	function set_byurl($data){
		$this->data = $data;
		$this->data_len = 0;
		$this->data_type = 2;

		return true;
	}

	function set_lastmodtime($time){
		$time = intval($time);

		if($time <= 0){
			$time = time();
		}

		$this->data_mod = $time;
	}

	function _auth(){
		if(!isset($_SERVER['PHP_AUTH_USER'])){
			return false;
		}

		if(isset($this->handler['auth']) && function_exists($this->handler['auth'])){
			return $this->handler['auth']('auth' , $_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']);
		}else{
			return true; //you must use a handler
		}
	}
}

调用方法如下:

$object = new httpdownload();
$object->set_byfile($file);//服务器文件名,包括路径
$object->filename = $downName;//下载另存为的文件名
$object->download();

转载请注明: 转载自Ryan 是菜鸟 | LNMP 技术栈笔记

如果觉得本篇文章对您十分有益,何不 打赏一下

谢谢打赏

本文链接地址: 非常好用的 PHP 下载类

知识共享许可协议 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可