如何在1个http请求下上传多个文件

Har*_*rts 5 javascript php html5 file-upload xmlhttprequest

使用HTML5分块,我可以用较小的片段进行文件上传.但问题开始时,它开始使用多个http POST请求,这将导致计算机减速,或可能崩溃.反正有没有在一个http请求下分割文件..所以,如果我有5个文件,它将只有5个http请求,尽管我使用html5拆分块

例如:如果我上传5个文件,每个文件将被拆分为1mb块,所以如果第一个文件是10mb,那么它将变成10个1mb块.问题是,每个块将在1个http请求下,所以只有第一个文件它将是10个HTTP请求.想象一下,如果我有1GB文件,它将成为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);
        }
Run Code Online (Sandbox Code Playgroud)

并且用于接收的服务器部分将是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);
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*der 6

在你的评论中阅读你的动机之后,我想指出一些"误解".首先,建议将文件拆分,然后立即上传所有拆分的部分.拆分文件的全部意义不是绕过PHP上传限制(如果适用,应该更改,这可能是一个真正的解决方案*),而是通过顺序执行不同的部分,这允许客户端上的负载计算机是最小的,特别是如果您正在考虑上传1GB的内容.无论哪种方式,都没有理由将文件拆分,然后将其合并到一个请求中(尽管理论上这可能与XMLHttpRequest2一起使用,但如果您可以使用XMLHttpRequest2那么您不应该担心以任何方式拆分文件,因为它提供了干净地上传多个文件的必要控制.

*请注意,如果你这样做,你将必须确保你的PHP内存设置正确设置(以防止PHP尝试将其完全加载到内存中,然后将其写入临时文件,但这不应该发生在最近PHP的版本,我相信默认设置).(我觉得有必要补充一点,我几年没有使用PHP和PHP上传,所以我可能会错误地对这最后的评论)

无论哪种方式,将文件分块大约5-25MB(取决于你期望连接有多好:P)+顺序上传(加上一个很好的进度条,如果XMLHttpRequest2可用,否则每个块的进度条)似乎是一个明智的方法去同时防止浏览器过载.(哦,如果你需要支持旧的浏览器,我真的建议你研究一下flash上​​传器,因为尽管苹果宣传闪存是邪恶的,但在大多数(过时的)计算机上,它将提供最好的体验)