【问题标题】:How to upload multiple file under 1 http request如何在 1 个 http 请求下上传多个文件
【发布时间】:2012-05-31 09:45:12
【问题描述】:

使用 HTML5 分块,我可以上传更小的文件。但是当它开始使用多个 http POST 请求时问题就开始了,这将导致计算机速度变慢,或者可能崩溃。反正有没有在一个http请求下分割文件..所以如果我有5个文件即使我使用html5分割块也只有5个http请求

例如:如果我上传 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);
        }

接收的服务器部分是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);
}

【问题讨论】:

  • 如果您不想将文件拆分为多个部分,那么为什么要拆分它们?
  • 不,我需要他们分开。因为 1. PHP 有上传限制(我知道我可以更改该限制,但这并不是真正的解决方案) 2. 这样我可以一次上传多个文件,这样会更快。
  • 其实分割文件也能帮我实现恢复文件(万一突然断线),用户不必再从头开始

标签: php javascript html file-upload xmlhttprequest


【解决方案1】:

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

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

无论哪种方式,将文件分块到大约 5-25MB(取决于您期望连接有多好 :P)+ 顺序上传(如果 XMLHttpRequest2 可用,加上一个不错的进度条,否则每个块都有一个进度条)似乎是明智的在防止浏览器过载的同时要走的路。 (哦,如果您需要支持较旧的浏览器,我真的建议您查看 flash 上传器,因为尽管 Apple 宣传 flash 是邪恶的,但在大多数(过时的)计算机上,它会给迄今为止最好的体验)

【讨论】:

  • 其实分割文件也可以帮助我实现恢复文件(万一突然断线),用户不必从头开始。那么,根据您的解决方案,同时上传不是一个好主意吗?我应该坚持按顺序上传吗?顺便说一句,flash 和 java 不是一个选项,因为我试图摆脱这个,这就是我使用 HTML5 的原因。谢谢
  • 这不是一个选项“因为”你想摆脱它?这不是我希望的原因,因为您不应该仅仅为了移动自身而迁移到 HTML5(目前没有什么本质上更好的东西,因为它的支持比闪存可用性更差)。无论如何,就恢复文件上传而言,这就是为什么我说在我的结论中拆分文件是一个好主意,并且根据连接质量使块尽可能大,但是如果同时上传它们,你会丢失所有优点。 (因为恢复上传也不现实)
  • 不,我的意思是我已经用 Java 编写了这个项目(并且正在运行),现在我正在尝试用 HTML5 重写它以备将来使用。我知道目前 HTML5 还不如 java 或 flash
  • 啊,这解释了 :) 是的,在这种情况下这很有意义(尽管我过去开发过各种 html5 应用程序,但我也知道有些公司过于关注在 html5 上作为一个流行词)。不管怎样,在那种情况下,我相信我给你的结论是最合适的。顺便说一句,我想你一定已经找到了这个,但是有各种各样的库可以为你做这件事,比如github.com/23/resumable.js
【解决方案2】:

Java 上传器 [即 JumpLoader] - 我不是说“使用它们”,而是了解它们的工作原理。到目前为止,我见过的最佳上传实践是:1)将文件拆分为一定大小的块,2)按顺序上传块(另外通过提供块的哈希,如果数据是敏感的),3)在服务器端合并块(但通过哈希验证数据完整性,如果你正在使用它们)。

因此,您将绕过 PHP 的 max_upload_size 限制。否则,我个人认为为什么有人应该首先将数据拆分成块有什么好处。

【讨论】:

    【解决方案3】:

    试试这个:

    <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>
    

    【讨论】:

    • 我的代码有什么不同?我似乎找不到区别?
    猜你喜欢
    • 2018-01-24
    • 1970-01-01
    • 2010-11-05
    • 2016-05-16
    • 1970-01-01
    • 2012-06-12
    • 1970-01-01
    相关资源
    最近更新 更多