ホームページ > バックエンド開発 > PHPチュートリアル > PHP で大きなファイルをアップロードおよびダウンロードするための技術ガイド

PHP で大きなファイルをアップロードおよびダウンロードするための技術ガイド

王林
リリース: 2023-05-21 10:00:02
オリジナル
2126 人が閲覧しました

モバイル インターネット時代の到来により、大きなファイルを転送する必要性がますます一般的になってきています。中でも PHP は人気のあるプログラミング言語であり、大きなファイルのアップロードやダウンロードに優れたパフォーマンスを発揮します。この記事では、大きなファイルの処理方法、チャンクアップロード、再開されたアップロード、非同期ダウンロードなどの重要なテクノロジーを含む、PHP での大規模ファイルのアップロードおよびダウンロードテクノロジーについて学習します。

1. PHP で大きなファイルを処理する方法

PHP で大きなファイルを処理する際の最も重要なステップは、適切なメモリ使用計画を計画することです。メモリ オーバーフローが発生し、プログラム全体がクラッシュする可能性があるため、大きなファイル全体をメモリに直接読み取ることはできません。では、PHP で大きなファイルを処理するにはどのような方法があるのでしょうか?

まず、「ファイル ポインタ」の概念を使用して、この問題を解決できます。 「ファイル ポインタ」は、ファイル全体を一度に読み取るのではなく、ファイルの特定の部分を読み取ることができるファイル内にあるポインタです。 PHP では、fopen() 関数と fread() 関数を使用してファイルを開いて読み取ることができます。

2 番目に、「ストリーミング」方法を使用できます。まず大きなファイルを複数の部分に分割し、次にそれらを部分的にアップロードまたはダウンロードします。これにより、大きなファイル全体を一度に読み取ることがなくなり、データの整合性が確保されます。

2. 大きなファイルのアップロード

HTTP 通信の場合、PHP のデフォルトのアップロード ファイル サイズは 2MB であるため、より大きなファイルをアップロードできるように php.ini 設定ファイルの Upload_max_filesize オプションを変更する必要があります。アップロードされました。

しかし、php.ini ファイルを変更した後でも、大きなファイルのアップロード中に依然として問題が発生します。アップロード中のメモリ リークやプログラムのクラッシュを回避するにはどうすればよいでしょうか?答えは、チャンク アップロード テクノロジを使用することです。

  1. チャンク アップロード

いわゆるチャンク アップロードは、大きなファイルを固定サイズのチャンクに分割し、アップロードが完了するまでそれらを少しずつアップロードすることです。 。この方法では、ファイル全体を一度に読み取ることがなくなり、サーバーのメモリ負荷が軽減されます。

具体的な実装は次のとおりです。

フロントエンド コード:

<input type="file" name="file" id="file">
ログイン後にコピー
var chunkSize = 1 * 1024 * 1024; //每一块的大小为1MB

var file = document.getElementById('file').files[0];
var name = file.name;
var size = file.size;

var chunkNum = Math.ceil(size / chunkSize); //总块数

for(var i=0;i<chunkNum;i++){

    var start = i*chunkSize;
    var end = Math.min(size,start+chunkSize);

    var chunk = file.slice(start,end); //将文件切成每个chunkSize大小的块

    //使用FormData上传
    var formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('filename', i+'_'+name); //在文件名前加上块的编号

    //发起已经分割好的块的上传请求
    send(chunkUrl,formData);

}
ログイン後にコピー

バックエンド コード:

$chunk = $_FILES['chunk']; //获取文件块
$filename = $_POST['filename']; //获取文件名

//上传文件块
move_uploaded_file( $chunk['tmp_name'] , $upload.$filename);

echo "success";
ログイン後にコピー

上記のコードは、大きな分割を実装します。ファイルを複数の 1MB サイズのファイルに分割し、分割してアップロードして圧力を分散します。

  1. ブレークポイント再開

注目に値するもう 1 つの問題は、大きなファイルのアップロードが誤ってキャンセルされた場合、中断された場所からアップロードを続行するにはどうすればよいかということです。

その答えは、ブレークポイント再開テクノロジーを使用することです。ファイルのアップロード中にファイルのアップロードの進行状況を記録し、ユーザーが再度アップロードするときに、最後のアップロードの未完了のファイル ブロックをキャッシュして、後で再度アップロードできるようにします。

具体的な実装は次のとおりです。

フロントエンド コード:

var chunkSize = 1 * 1024 * 1024; //每一块的大小为1MB

var file = document.getElementById('file').files[0];
var name = file.name;
var size = file.size;

var chunkNum = Math.ceil(size / chunkSize); //总块数

for(var i=0;i<chunkNum;i++){

    var start = i*chunkSize;
    var end = Math.min(size,start+chunkSize);

    var chunk = file.slice(start,end); //将文件切成每个chunkSize大小的块

    //使用FormData上传
    var formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('filename', i+'_'+name); //在文件名前加上块的编号
    formData.append('chunkNum',chunkNum); //总块数
    formData.append('index',i); //当前块的编号

    //将文件分块上传
    send(chunkUrl,formData,function(){ 

        uploaded[i] = 1; //标记该块已上传
        var uploadedAll = uploaded.every(v => v == 1); //检查是否所有块都已上传

        //如果所有块都已上传,则在服务端组装文件
        if(uploadedAll){

            var formData = new FormData();
            formData.append('name', name);
            formData.append('chunkNum',chunkNum); //总块数

            //发起文件组装请求
            send(mergeUrl,formData,function(response){

                console.log(response);

            });

        }

    });

}
ログイン後にコピー

バックエンド コード:

$chunk = $_FILES['chunk']; //获取文件块
$filename = $_POST['filename']; //获取文件名
$chunkNum = $_POST['chunkNum']; //获取文件总块数
$index = $_POST['index']; //获取当前块的编号

//上传文件块
move_uploaded_file( $chunk['tmp_name'] , $upload.$filename);

//上传完成后检查所有块是否已上传
$uploaded = $this->isUploaded($upload,$chunkNum);
if($uploaded){
    $this->mergeFile($upload,$chunkNum,$name); //组装文件
}

echo "success";
ログイン後にコピー

上記のコードは、ファイルを分割してクライアントにアップロードします。 サーバー側でアップロードの進行状況をマークし、サーバー側でアップロードが完了したかどうかを確認します。アップロードが完了すると、アップロードされたすべてのファイル チャンクが結合されます。

3. 大きなファイルのダウンロード

PHP で大きなファイルをダウンロードする場合、メモリ リークやプログラムのクラッシュの問題も解決する必要があります。このために、非同期ダウンロード技術を使用できます。

非同期ダウンロードとは、サーバーのメイン スレッドのブロックを避けるために、ダウンロード リクエストを別のスレッドに配置することを意味します。 PHP では、exec() 関数を使用して別のスレッドを開始できます。

具体的な実装は次のとおりです。

フロントエンド コード:

<a href="#" onclick="download()">下载</a>
ログイン後にコピー
function download(){

    var filename = 'test.zip'; //准备下载文件名

    //发起异步下载请求
    var ajax = new XMLHttpRequest();
    ajax.open('GET', '/download.php?filename='+filename, true);
    ajax.send();

}
ログイン後にコピー

バックエンド コード:

$action = isset($_GET['action']) ? $_GET['action'] : 'download'; //获取下载动作
$filename = $_GET['filename']; //获取文件名

if($action == 'download'){

    //启动异步下载
    exec('php download.php '.$filename.' > /dev/null &'); 

}else{

    //文件下载
    header("Content-type: application/octet-stream");
    header("Content-Disposition: attachment; filename=".$filename);
    header("Accept-Ranges: bytes");

    $file = fopen($download.$filename,"r");
    if($file){

        while(!feof($file)){
            print(fread($file, 1024*8 ));
            flush();
            ob_flush();
        }

    }
    fclose($file);

}
ログイン後にコピー

上記のコードは、非同期ダウンロードを実装します。リクエストはクライアント上で開始され、最後は exec() 関数を使用してダウンロード用の別のスレッドを開始し、メイン スレッドがブロックされる問題を回避します。同時に、チャンクダウンロードとバッファへの出力を使用して、ファイルをダウンロードする際のメモリの問題も解決されます。

4. まとめ

この記事では、主に大きなファイルの処理方法、チャンクアップロード、ブレークポイント再開、非同期ダウンロードなどのテクノロジーを含む、PHP での大規模ファイルのアップロードおよびダウンロードテクノロジーについて学習しました。 。この記事のガイダンスを通じて、PHP で大きなファイルを処理するテクニックをよりよく習得し、これらのテクニックを実際のプロジェクトに適用して、大きなファイルの効率的な送信を実現することができます。

以上がPHP で大きなファイルをアップロードおよびダウンロードするための技術ガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート