要实现的功能是前台用html5文件api读取要上传的文件,用ajax请求把读取的内容上传到php服务端处理,但是如果文件太大就会导致浏览器崩溃(用的是chrome最新版),所以在前端就用File.slice把文件分块,并在服务端用php合并为完整的文件。
前端javascript如下:
1 <style> 2 #container { 3 min-width:300px; 4 min-height:200px; 5 border:3px dashed #000; 6 } 7 </style> 8 <div id='container'> 9 10 </div> 11 <script> 12 function addDNDListener(obj){ 13 obj.addEventListener('dragover',function(e){ 14 e.preventDefault(); 15 e.stopPropagation(); 16 },false); 17 obj.addEventListener('dragenter',function(e){ 18 e.preventDefault(); 19 e.stopPropagation(); 20 },false); 21 obj.addEventListener('drop',function(e){ 22 e.preventDefault(); 23 e.stopPropagation(); 24 var ul = document.createElement("ul"); 25 var filelist = e.dataTransfer.files; 26 for(var i=0;i<filelist.length;i++){ 27 var file = filelist[i]; 28 var li = document.createElement('li'); 29 li.innerHTML = '<label id="'+file.name+'">'+file.name+':</label><progress value="0" max="100"></progress>'; 30 ul.appendChild(li); 31 } 32 document.getElementById('container').appendChild(ul); 33 for(var i=0;i<filelist.length;i++){ 34 var file = filelist[i]; 35 uploadFile(file); 36 } 37 },false); 38 } 39 40 function uploadFile(file){ 41 var loaded = 0; 42 var step = 1024*1024; 43 var total = file.size; 44 var start = 0; 45 var progress = document.getElementById(file.name).nextSibling; 46 47 var reader = new FileReader(); 48 49 reader.onprogress = function(e){ 50 loaded += e.loaded; 51 progress.value = (loaded/total) * 100; 52 }; 53 54 reader.onload = function(e){ 55 var xhr = new XMLHttpRequest(); 56 var upload = xhr.upload; 57 upload.addEventListener('load',function(){ 58 if(loaded <= total){ 59 blob = file.slice(loaded,loaded+step+1); 60 reader.readAsBinaryString(blob); 61 }else{ 62 loaded = total; 63 } 64 },false); 65 xhr.open("POST", "upload.php?fileName="+file.name+"&nocache="+new Date().getTime()); 66 xhr.overrideMimeType("application/octet-stream"); 67 xhr.sendAsBinary(e.target.result); 68 }; 69 var blob = file.slice(start,start+step+1); 70 reader.readAsBinaryString(blob); 71 } 72 73 window.onload = function(){ 74 75 addDNDListener(document.getElementById('container')); 76 if(!XMLHttpRequest.prototype.sendAsBinary){ 77 XMLHttpRequest.prototype.sendAsBinary = function(datastr) { 78 function byteValue(x) { 79 return x.charCodeAt(0) & 0xff; 80 } 81 var ords = Array.prototype.map.call(datastr, byteValue); 82 var ui8a = new Uint8Array(ords); 83 try{ 84 this.send(ui8a); 85 }catch(e){ 86 this.send(ui8a.buffer); 87 } 88 }; 89 } 90 }; 91 </script>
后台php代码如下:
1 <?php 2 $filename = "upload/".$_GET['fileName']; 3 //$filename = "upload/".$_GET['fileName']."_".$_GET['nocache']; 4 $xmlstr = $GLOBALS['HTTP_RAW_POST_DATA']; 5 if(empty($xmlstr)){ 6 $xmlstr = file_get_contents('php://input'); 7 } 8 $is_ok = false; 9 while(!$is_ok){ 10 $file = fopen($filename,"ab"); 11 12 if(flock($file,LOCK_EX)){ 13 fwrite($file,$xmlstr); 14 flock($file,LOCK_UN); 15 fclose($file); 16 $is_ok = true; 17 }else{ 18 fclose($file); 19 sleep(3); 20 } 21 }
问题就是每次上传完之后文件大小总是比原始大小小一点,可能是最后一段没有上传到服务器,导致文件不完整(现在每次分片的大小是1M,小于2M的文件没问题,超过就有问题),求教问题出在哪里?还有我觉得现在这些代码质量,代码风格也有点问题,哪些地方是可以改进的?3QVM~~
文件也可以用ajax传了?
恩,用html5的文件api
@sangelee: 请问如何解决的