5

HTML5 のチャンクを使用すると、より小さな断片でファイルのアップロードを行うことができました。しかし、複数の http POST リクエストを使用し始めたときに問題が発生し、コンピューターの速度が低下したり、おそらくクラッシュしたりします。とにかく、分割されたファイルを1つのhttpリクエストの下に置くことはありますか?

例: 5 つのファイルをアップロードすると、各ファイルは 1 MB のチャンクに分割されるため、最初のファイルが 10 MB の場合、1 MB のチャンクが 10 個になります。そして問題は、各チャンクが 1 つの HTTP リクエストの下にあるため、最初のファイルだけで 10 の HTTP リクエストになることです。1 GB のファイルがある場合、1000 の HTTP リクエストになり、コンピューターの速度が低下すると想像してください。

これはコード例です:

        //Prepare element progress after the page load completely
        var uploaders = [];
        var totalChunks = 0;
        var progress;
        var bars;
        $(document).ready(function() {
            //progress = document.querySelector('progress');
            //bars = document.querySelector('#bars'); 
        });        

        //function for after the button is clicked, slice the file 
        //and call upload function
        function sendRequest() {       
            //clean the screen
            //bars.innerHTML = '';


            var file = document.getElementById('fileToUpload');   

            for(var i = 0; i < file.files.length; i++) {      
                var blob = file.files[i];         
                var originalFileName = blob.name;
                var filePart = 0

                const BYTES_PER_CHUNK = 10 * 1024 * 1024; // 10MB chunk sizes.
                const SIZE = blob.size;

                var start = 0;
                var end = BYTES_PER_CHUNK;

                totalChunks = Math.ceil(SIZE / BYTES_PER_CHUNK);

                while( start < SIZE ) {                    
                    if (blob.webkitSlice) {
                        //for Google Chrome
                        var chunk = blob.webkitSlice(start, end); 
                    } else if (blob.mozSlice) {
                        //for Mozilla Firefox
                        var chunk = blob.mozSlice(start, end);
                    }       

                    uploadFile(chunk, originalFileName, filePart, totalChunks, i);
                    filePart++;
                    start = end;
                    end = start + BYTES_PER_CHUNK;
                }
            }                
        }

        function uploadFile(blobFile, fileName) {
            var fd = new FormData();
            fd.append("fileToUpload", blobFile);

            var xm = $.ajax({
                url: "upload.php"+"?"+"file1="+fileName,
                type: "POST",
                data: fd,
                processData: false,
                contentType: false,
            });               
        }

        function uploadFile(blobFile, fileName, filePart, totalChunks, divBarsSelector) {
            if(filePart == 0) {
                bars = document.querySelector('#bars' + divBarsSelector);  
            }

            var progress = document.createElement('progress');
            progress.min = 0;
            progress.max = 100;
            progress.value = 0;
            bars.appendChild(progress);   

            var fd = new FormData();
            fd.append("fileToUpload", blobFile);

            var xhr = new XMLHttpRequest();                
            xhr.open("POST", "upload.php"+"?"+"file="+fileName + filePart, true);

            xhr.onload = function(e) {
                //make sure if finish progress bar at 100%
                progress.value = 100;

                //counter if everything is done using stack
                uploaders.pop();

                if (!uploaders.length) {
                    bars.appendChild(document.createElement('br'));
                    bars.appendChild(document.createTextNode('DONE :)'));
                    //mergeFile(fileName, totalChunks);
                }                  
            };

            // Listen to the upload progress for each upload.   
            xhr.upload.onprogress = function(e) {;
                if (e.lengthComputable) {
                    progress.value = (e.loaded / e.total) * 100;
                }
            };                 

            uploaders.push(xhr);
            xhr.send(fd);
        }

受信用のサーバー部分はupload.phpになります

$target_path = "uploads/";
$tmp_name = $_FILES['fileToUpload']['tmp_name'];
$size = $_FILES['fileToUpload']['size'];
$name = $_FILES['fileToUpload']['name'];

$originalName = $_GET['file'];

print_r("*******************************************\n");
print_r($originalName);
print_r("\n");
print_r($_FILES);
print_r("\n");
print_r("*******************************************\n");
$target_file = $target_path . basename($name);

//Result File
$complete = $originalName;
$com = fopen("uploads/".$complete, "ab");
error_log($target_path);

if ( $com ) {
    // Read binary input stream and append it to temp file
    $in = fopen($tmp_name, "rb");
    if ( $in ) {
        while ( $buff = fread( $in, 1048576 ) ) {
            fwrite($com, $buff);
        }   
    }
    fclose($in);
    fclose($com);
}
4

3 に答える 3

6

コメントであなたの動機を読んだ後、いくつかの「誤解」を指摘したいと思います。まず第一に、ファイルを分割して、次に分割されたすべての部分を一度にアップロードすることはお勧めできません。ファイルを分割することの全体的なポイントは、PHP アップロード制限をバイパスしないことです (該当する場合は変更する必要があり、本当の解決策*) ですが、別の部分を順番に実行することで、特に 1 GB のコンテンツをアップロードすることを検討している場合に、クライアント コンピューターの負荷を最小限に抑えることができます。いずれにせよ、ファイルを分割して 1 つのリクエストに結合する理由はまったくありません (これは XMLHttpRequest2 で理論的には可能ですが、XMLHttpRequest2 を使用できる場合は、どちらの方法でもファイルを分割することを心配する必要はありません)。 、複数のファイルをきれいにアップロードするために必要な制御を提供するため)。

*そうする場合は、phpメモリ設定が正しく設定されていることを確認する必要があることに注意してください(phpが一時ファイルに書き込む前に完全にメモリにロードしようとするのを防ぐためですが、最近の私が信じているデフォルト設定のPHPのバージョン)。(私は PHP と PHP のアップロードを数年間行っていないことを付け加えなければならないので、この最後のコメントは非常によく誤解されている可能性があります)

いずれにせよ、ファイルを約 5 ~ 25MB にチャンクする (接続がどれだけ良好であると予想されるかによる :P ) + 順次アップロード (さらに、XMLHttpRequest2 が利用可能な場合は素敵なプログレスバー、そうでない場合はチャンクごとのプログレスバー) が賢明な方法のようです。ブラウザが過負荷になるのを防ぎながら。(古いブラウザをサポートする必要がある場合は、Flash アップローダを調べることを強くお勧めします。なぜなら、Apple は Flash を悪と説いていますが、ほとんどの (時代遅れの) コンピュータでは、はるかに最高の体験が得られるからです)

于 2012-05-29T13:54:22.853 に答える
1

Java アップローダー [つまり、JumpLoader] - 「使用する」とは言いませんが、それらがどのように機能するかを学びます。これまでのところ、私が見たアップロードのベスト プラクティスは次のとおりです。1) ファイルを特定のサイズのチャンクに分割する、2) チャンクを順次アップロードする (さらに、データが機密である場合は、チャンクのハッシュを提供することによって)、3) サーバー側でチャンクを結合する (ただし、ハッシュを使用している場合は、ハッシュを通じてデータの整合性を確認してください)。

max_upload_sizeしたがって、PHP の制限をバイパスします。そうでなければ、そもそも誰かがデータをチャンクに分割しなければならない理由が、個人的には何のメリットもありません。

于 2012-05-31T13:18:17.960 に答える
0

これを試して:

<script type="text/javascript">
    //Prepare element progress after the page load completely
    var uploaders = [];
    var totalChunks = 0;
    var progress;
    var bars;
    $  (document).ready(function() {
        //progress = document.querySelector('progress');
        //bars = document.querySelector('#bars');
    });        

    //function for after the button is clicked, slice the file
    //and call upload function
    function sendRequest() {
        //clean the screen
        //bars.innerHTML = '';

        var file = document.getElementById('fileToUpload');   

        for(var i = 0; i < file.files.length; i++) {
            var blob = file.files[i];
            var originalFileName = blob.name;
            var filePart = 0

            const BYTES_PER_CHUNK = 10 * 1024 * 1024; // 10MB chunk sizes.
            const SIZE = blob.size;

            var start = 0;
            var end = BYTES_PER_CHUNK;

            totalChunks = Math.ceil(SIZE / BYTES_PER_CHUNK);

            while( start < SIZE ) {
                if (blob.webkitSlice) {
                    //for Google Chrome
                    var chunk = blob.webkitSlice(start, end);
                } else if (blob.mozSlice) {
                    //for Mozilla Firefox
                    var chunk = blob.mozSlice(start, end);
                }       

                uploadFile(chunk, originalFileName, filePart, totalChunks, i);
                filePart++;
                start = end;
                end = start + BYTES_PER_CHUNK;
            }
        }
    }

    function uploadFile(blobFile, fileName) {
        var fd = new FormData();
        fd.append("fileToUpload", blobFile);

        var xm = $  .ajax({
            url: "upload.php"+"?"+"file1="+fileName,
            type: "POST",
            data: fd,
            processData: false,
            contentType: false,
        });
    }

    function uploadFile(blobFile, fileName, filePart, totalChunks, divBarsSelector) {
        if(filePart == 0) {
            bars = document.querySelector('#bars' + divBarsSelector);
        }

        var progress = document.createElement('progress');
        progress.min = 0;
        progress.max = 100;
        progress.value = 0;
        bars.appendChild(progress);   

        var fd = new FormData();
        fd.append("fileToUpload", blobFile);

        var xhr = new XMLHttpRequest();
        xhr.open("POST", "upload.php"+"?"+"file="+fileName + filePart, true);

        xhr.onload = function(e) {
            //make sure if finish progress bar at 100%
            progress.value = 100;

            //counter if everything is done using stack
            uploaders.pop();

            if (!uploaders.length) {
                bars.appendChild(document.createElement('br'));
                bars.appendChild(document.createTextNode('DONE :) '));
                //mergeFile(fileName, totalChunks);
            }
        };

        // Listen to the upload progress for each upload.
        xhr.upload.onprogress = function(e) {;
            if (e.lengthComputable) {
                progress.value = (e.loaded / e.total) * 100;
            }
        };                 

        uploaders.push(xhr);
        xhr.send(fd);
    }
</script>
于 2012-06-04T05:30:32.183 に答える