ホームページ  >  記事  >  バックエンド開発  >  PHP はファイルのダウンロードを実装し、ダウンロードの原則を再開します

PHP はファイルのダウンロードを実装し、ダウンロードの原則を再開します

WBOY
WBOYオリジナル
2016-06-20 13:05:201159ブラウズ

PHP はファイルのダウンロードを実装し、ブレークポイントでダウンロードを再開します

php ファイルのダウンロード

ファイルのダウンロードとは、サーバーからファイルをダウンロードすることを意味します。たとえば、ファイルが http://www.xxx.com/1.rar (このファイルは実際に存在します) の場合、ブラウザに直接入力してダウンロードします。ダイアログが表示されますが、画像アドレスの場合は、ダウンロードされずにブラウザで直接開かれる可能性があります。また、クライアントにダウンロード アドレスが表示されないようにするには、直接指定しないことをお勧めします。ダウンロード ファイルのアドレス。たとえば、ログインしたユーザーのみがダウンロードできます。 。 待ってください。まだ別のダウンロード プログラムを作成する必要があります

より重要な応答ヘッダーがいくつかあります。それらを記録してください

コンテンツタイプ

コンテンツの配置

コンテンツの長さ

プラグマ

キャッシュ制御

コンテンツタイプ

Content-type はブラウザにファイルの MIME タイプを伝えます。これは非常に重要な応答ヘッダーです。MIME には多数のタイプがあります。

コンテンツの配置

Content-Disposition は MIME プロトコルの拡張機能であり、MIME ユーザー エージェントに添付ファイルの表示方法を指示します。 Internet Explorer がヘッダー

を受信すると、ファイル ダウンロード ダイアログ がアクティブになり、そのファイル名ボックスにはヘッダーで指定されたファイル名が自動的に入力されます。 以上です、アクティベーションプロンプトのダウンロードボックス

非常に多くの MIME タイプがあるため、プログラム内で一部の MIME タイプが欠落する可能性が非常に高くなります。タイプが欠落している場合は、すべてのタイプが

"Content-type:" になります。 application/octet-stream" "Content-Disposition" :attachment; filename=xxx.xx"(xx.xx はファイル名です) いくつかのブラウザーテストの結果、ダウンロードされたファイルが正しいことが判明しました

コンテンツの長さ

「Content-Length: 123」は、ファイルのサイズが 123 バイトであることをブラウザーに伝えます。実際、このヘッダーを設定しなくてもブラウザーはそれを認識できることがわかりました。

プラグマ キャッシュ制御

これら 2 つのヘッダーを public に設定して、ブラウザーにキャッシュするように指示します (実際、多くのキャッシュ ヘッダーは public 以外は明確に理解できません。つまり、すべてがキャッシュされることを意味しますが、ブラウザーのキャッシュがキャッシュされるかどうかについては、確かではないかもしれませんが、私は多くのブラウザを使用してみましたが、どのブラウザもブラウザのキャッシュからファイルを読み取らず、サーバーからファイルを読み取りました)

ファイルを出力する場合、1回限りの出力と、分割出力(一度に一部ずつ出力する)の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

リクエストのヘッダーには、コンテンツがリクエストされるバイトからバイトまでを示す Range フィールドが含まれている必要があります。サーバーがサポートしている場合は、206 Partial Content を返し、ヘッダーの Content-Range を使用して範囲を指定し、本文でこの範囲内のデータを指定します。

受け入れ範囲: バイト

このフィールドは、Web サーバーが Range をサポートしているかどうか (ブレークポイント再開機能をサポートしているかどうか) を示します。サポートされていない場合は、Accept-Ranges: none が返されます。 🎜>

コンテンツ範囲:

は応答ヘッダーに使用され、返される Web リソースのバイト範囲を指定します。このフィールド値の形式は次のとおりです: 開始バイト位置 - 終了バイト位置/Web リソースの総バイト数、例: Content-Range: 1000-3000/5000

fseek: この関数は、ファイル ポインターを現在の位置から新しい位置に前後に移動します。新しい位置は、ファイルの先頭からのバイト単位で測定されます。

ob_flush: この関数は、ファイル ポインターを現在の位置から新しい位置に前後に移動します。新しい位置はファイル ヘッダーから始まるバイト単位で測定されます。

IE7 と 8 はブレークポイント再開をサポートしていないことをテストしてみました (可能かもしれませんが、方法はわかりません)。残念なことに、Apple ブラウザもサポートしていません (幸いなことに、Firefox Chrome Opera はサポートしています)

履歴書のアップロード手順は次のとおりです

まず、クライアントはファイルをダウンロードするリクエストを php に送信します

これは最初のリクエストであるため、リクエストヘッダーに Range ヘッダーはありません

Fiddler

を使用したパケット キャプチャのスクリーンショット リクエストヘッダー

PHP 側では、$_SERVER['HTTP_RANGE'] はリクエスト ヘッダーの Rang を取得できます。これは最初は存在しないため、ファイルのコンテンツを取得するときにファイルのコンテンツ全体を取得し、次に返されるステータス コードも 200

レスポンスヘッダー

コンテンツの一部が送信された後、クリックして一時停止し、クリックがほぼ継続されると、キャプチャされたパケットの応答ヘッダーの範囲は

になります。

    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();

 


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。