Я хочу реализовать следующее:
В интерфейсе я использую apt html5 api для чтения файла, а затем загружаю содержимое файла в бэкэнд php с помощью ajax, и это нормально, если размер файла невелик. Однако, если файл достаточно большой, это приводит к сбою хрома. Поэтому я разбил большой файл на куски, используя file.slice, когда все куски загружаются на php, объединить куски в один полный.
код выглядит следующим образом:
передний конец:
<style> #container { min-width:300px; min-height:200px; border:3px dashed #000; } </style> <div id='container'> </div> <script> function addDNDListener(obj){ obj.addEventListener('dragover',function(e){ e.preventDefault(); e.stopPropagation(); },false); obj.addEventListener('dragenter',function(e){ e.preventDefault(); e.stopPropagation(); },false); obj.addEventListener('drop',function(e){ e.preventDefault(); e.stopPropagation(); var ul = document.createElement("ul"); var filelist = e.dataTransfer.files; for(var i=0;i<filelist.length;i++){ var file = filelist[i]; var li = document.createElement('li'); li.innerHTML = '<label id="'+file.name+'">'+file.name+':</label> <progress value="0" max="100"></progress>'; ul.appendChild(li); } document.getElementById('container').appendChild(ul); for(var i=0;i<filelist.length;i++){ var file = filelist[i]; uploadFile(file); } },false); } function uploadFile(file){ var loaded = 0; var step = 1024*1024; var total = file.size; var start = 0; var progress = document.getElementById(file.name).nextSibling; var reader = new FileReader(); reader.onprogress = function(e){ loaded += e.loaded; progress.value = (loaded/total) * 100; }; reader.onload = function(e){ var xhr = new XMLHttpRequest(); var upload = xhr.upload; upload.addEventListener('load',function(){ if(loaded <= total){ blob = file.slice(loaded,loaded+step+1); reader.readAsBinaryString(blob); }else{ loaded = total; } },false); xhr.open("POST", "upload.php?fileName="+file.name+"&nocache="+new Date().getTime()); xhr.overrideMimeType("application/octet-stream"); xhr.sendAsBinary(e.target.result); }; var blob = file.slice(start,start+step+1); reader.readAsBinaryString(blob); } window.onload = function(){ addDNDListener(document.getElementById('container')); if(!XMLHttpRequest.prototype.sendAsBinary){ XMLHttpRequest.prototype.sendAsBinary = function(datastr) { function byteValue(x) { return x.charCodeAt(0) & 0xff; } var ords = Array.prototype.map.call(datastr, byteValue); var ui8a = new Uint8Array(ords); try{ this.send(ui8a); }catch(e){ this.send(ui8a.buffer); } }; } }; </script>
код php:
<?php $filename = "upload/".$_GET['fileName']; //$filename = "upload/".$_GET['fileName']."_".$_GET['nocache']; $xmlstr = $GLOBALS['HTTP_RAW_POST_DATA']; if(empty($xmlstr)){ $xmlstr = file_get_contents('php://input'); } $is_ok = false; while(!$is_ok){ $file = fopen($filename,"ab"); if(flock($file,LOCK_EX)){ fwrite($file,$xmlstr); flock($file,LOCK_UN); fclose($file); $is_ok = true; }else{ fclose($file); sleep(3); } }
в<?php $filename = "upload/".$_GET['fileName']; //$filename = "upload/".$_GET['fileName']."_".$_GET['nocache']; $xmlstr = $GLOBALS['HTTP_RAW_POST_DATA']; if(empty($xmlstr)){ $xmlstr = file_get_contents('php://input'); } $is_ok = false; while(!$is_ok){ $file = fopen($filename,"ab"); if(flock($file,LOCK_EX)){ fwrite($file,$xmlstr); flock($file,LOCK_UN); fclose($file); $is_ok = true; }else{ fclose($file); sleep(3); } }
Проблема в том, что после того, как куски файла будут загружены на сервер и объединены в новый, общий размер файла меньше оригинала, а объединенный – сломан. Где проблема и как ее исправить?
В вашем js-скрипте есть небольшая ошибка. Я заметил, что событие reader.onprogress запускается больше раз, чем событие загрузки xhr. В этом случае некоторые куски пропускаются. Попробуйте увеличить загруженную переменную внутри функции загрузки .
function uploadFile(file){ var loaded = 0; var step = 1024*1024; var total = file.size; var start = 0; var progress = document.getElementById(file.name).nextSibling.nextSibling; var reader = new FileReader(); reader.onload = function(e){ var xhr = new XMLHttpRequest(); var upload = xhr.upload; upload.addEventListener('load',function(){ loaded += step; progress.value = (loaded/total) * 100; if(loaded <= total){ blob = file.slice(loaded,loaded+step); reader.readAsBinaryString(blob); }else{ loaded = total; } },false); xhr.open("POST", "upload.php?fileName="+file.name+"&nocache="+new Date().getTime()); xhr.overrideMimeType("application/octet-stream"); xhr.sendAsBinary(e.target.result); }; var blob = file.slice(start,step); reader.readAsBinaryString(blob); }
Только время, когда okey должен читать / разрезать файл, если вы решаете зашифровать / дешифровать / заархивировать файлы перед отправкой на сервер.
Но только в течение ограниченного времени, пока все браузеры не начнут поддерживать потоки.
Затем вы должны взглянуть на выборку и ReadableStream
fetch(url, {method: 'post', body: new ReadableStream({...})})
если вам просто нужно xhr.send(blob_or_file)
blob на сервер, просто выполните: xhr.send(blob_or_file)
и браузер позаботится о его чтении (правильно) и не будет потреблять какую-либо память. И файл может быть большим, файл / blob
Эта проблема вызвана главным образом глобальными ограничениями общих хостов. Они часто контролируют количество данных и отбрасывают соединение, если ограничение отменено. Я пробовал это несколько раз и несколько способов. Всегда придерживайтесь одной позиции. целевой файл был меньше и искажен. Даже принимая меньший файл для загрузки, чем этот размер, чтобы объединенные данные были в пределе, результат был в порядке. У вас есть только один шанс: увеличьте максимальный размер, чтобы файлы были открыты. Каждый раз, когда вы открываете целевой файл и записываете в него содержимое Chunk, а размер переопределяет Limit, хостер прерывает соединение. Пример hoster: Strato. Здесь Limit установлен по всему миру на 16 МБ. Я получаю максимальный размер слияния, размер которого равен удвоенному размеру. Нет шансов переопределить его.
Вы должны использовать этот рабочий Javascript. Подробнее см. Здесь
https://mytechbites.blogspot.in/2016/07/uploading-large-files-in-js.html