PHPファイルのダウンロード速度制限

ユーザーによるファイルのダウンロード速度を制限することが必要になる場合があります。 これには多くの理由(無料および有料モード、ユーザー登録など)がありますが、サーバーを購入したり、適切に構成したりできるとは限りません。 このトピックでは純粋なPHPの肩にタスクをシフトすることを提案します。



機能:



 function loadfile ($filename, $speed=false) { //    }
      
      



$ filenameは、提供するファイルのアドレスです。

$速度-ダウンロード速度。





制限と制限を削除し、出力バッファリングを開始します。



  //実行時間制限
 set_time_limit(0);

 //ユーザーが切断しても実行を継続します
 ignore_user_abort(true);

 //バッファリングを開始
 ob_start();




ファイルに関する必要なデータを収集します。



  //ファイルサイズ
 $ filesize = filesize($ filename);

 //ファイルが最後に変更された時刻
 $ filetime = gmdate( 'r'、filemtime($ filename));

 // Etagを生成します
 $ etag = md5($ filename。 "="。$ filesize。 "="。$ filetime);
 $ etag = substr($ etag、0、8).'- '。substr($ etag、8、7).'-'。substr($ etag、15、8);




ヘッダーを作成して提供します。



  //ファイル全体ではなく、ファイルの一部のみを提供する(再開する)ように「求められた」場合、「答える」 
 if(isset($ _ SERVER ['HTTP_RANGE'])){

	 //文字列$ _SERVER ['HTTP_RANGE']をサブストリングに分割して、
	 //ファイルのユーザー部分のアイデア
	 $ range = substr($ _ SERVER ['HTTP_RANGE']、strpos($ _ SERVER ['HTTP_RANGE']、 '=')+ 1);
	 $ from =(整数)(strtok($範囲、「-」));  //どのバイトの一部を開始するか
	 $ to =(整数)(strtok( "-"));  //終了するバイト

	 //ヘッダーを提供します
	 header( 'HTTP / 1.1 206 Partial Content');
	 header( 'Content-Range:bytes'。$ from .'- '。($ to-1)。' / '。$ filesize);
 } else {
	ヘッダー( 'HTTP / 1.1 200 Ok');
 }

 //クライアントが最初の最後のバイトに関する情報を送信しなかった場合、割り当てます
 //自分で。
 if($ to == 0)$ to = $ filesize;
 if(empty($ from))$ from = 0;




ユーザーごとのスレッド制限:



ユーザーが必要な速度でファイルをダウンロードし、複数のストリームでダウンロードを提供するプログラムの助けを借りて制限を回避できないようにするには、1人の訪問者に制限を設定する必要があります。 これを行うには、すでに確立された接続の存在を確認する追加機能を導入する必要があります。 MySQLをDBMSとして使用することをお勧めします。



したがって、テーブルを作成します。 それを「file_session」と呼びましょう。 この例では、ダウンローダーのIPアドレスを含む「session_ip」フィールドが1つだけ必要です。 データベースに必要なIPがある場合はtrueを指定し、そうでない場合はそれを書き込んでfalseを指定します。



 関数is_active_user($ clear = false){
	グローバル$ dbi;  //これはデータベース接続です
	 //ユーザー接続を確認します
	 $ result = mysql_query( "SELECT` session_ip` FROM` file_session` WHERE` session_ip` = '"。$ _ SERVER [' REMOTE_ADDR ']。"' LIMIT 1 "、$ dbi);
	 if(mysql_num_rows($ result)){
		 // $ clearが設定されている場合、ユーザー
		 //切断されました。 レコードを削除します。
		 if(!$ clear){
			 trueを返します。
		 } else {
			 mysql_query( "DELETE FROM` file_session` WHERE session_ip = '"。$ _ SERVER [' REMOTE_ADDR ']。 "' LIMIT 1"、$ dbi);
		 }
	 } else {
		 //エントリがない場合は追加します
		 mysql_query( "INSERT INTO` file_session` VALUES( '"。$ _ SERVER [' REMOTE_ADDR ']。 "')"、$ dbi);
		 falseを返します。
	 }
 }


その後、ログイン、支払い可能性などのチェックを追加することにより、機能をアップグレードできます。



ファイルを提供します:



  //ヘッダーを提供します
 header( 'ETag: "'。$ etag。 '"');
 header( 'Accept-Ranges:bytes');
 header( 'Content-Length:'。($ filesize- $ from));
 header( 'Content-Type:application / octet-stream');
 header( 'Last-Modified:'。gmdate( 'r'、filemtime($ filename)));
 header( 'Content-Disposition:attachment; filename = "'。$ filename。 '";');

 //ユーザーが持っているかどうかを確認します
 //アクティブなスレッドis_active_user()
 //およびconnection_status()を切断したかどうか。
 while(is_active_user()and!connection_status()){
	 //ユーザーがアクティブなスレッドを持っている間はスリープします
	睡眠(1);
 }

 //ファイルを開きます
 $ f = fopen($ filename、 'rb');

 //ポインタを目的の位置に設定します
 fseek($ f、$ from、SEEK_SET);

 //パーツの合計ボリュームを設定し、ダウンロードしたボリュームを格納する変数を宣言します
 $サイズ= $ to-$ from;
 $ isready = 0;

 //リターンを開始
 while(!feof($ f)and!connection_status()and($ isready <$ size)){
	 //制限がない場合は、0.5 Mbを読み取り、遅滞なく提供します。
	 //制限はありますか? 制限で設定されたとおりに正確に読み取り、1秒間スリープ状態にします。
	 echo fread($ f ,! $ speed?512000:$ speed);  //読んで与える
	フラッシュ();  ob_flush();  //バッファをクリアしてユーザーに出力します
	 if($ speed)sleep(1);  //眠りに落ちる
	 $ isready + =!$ speed?512000:$ speed;  //カウンターを更新します
 }

 //ファイルを閉じます
 fclose($ f);

 //データベースから接続情報を削除します
 is_active_user(true);




関数呼び出し:



 ロードファイル( "/files/moifilm.avi"、10240);  //速度はバイト単位で示されます




結果:



完全なコードと、 制限なしで、10 Kb / s-1 Mbファイルの制限付きでダウンロードする実際の例。



PS私の最初のhabrapost(:



All Articles