网上很多文件切片上传的文章, 看了很多, 最终自己总结了下, 主要思路如下:
1. 需要实现的功能
- 前端多文件上传
- 前端文件切片, 并命名uuid
- 文件同步上传, 切片同步上传
- 后端接受切片并根据文件名称保存至文件夹
- 后端判断是否是最后一个切片,合并切片
2.用到的技术
- h5文件切片
切片上传请求参数:
filename: file-5bad6aab-cf7d-bfdb-356a-36d7b4ab1e1e.jpgfragname: frag-1e0d1311-2369-317b-262e-04a9f427ea8cfile: (binary)fragindex: 0total: 2
- es6 async await
- php monolog composer包
3. 开始写代码
3.1 前端
html:
点击上传, 获取所有的文件,并处理文件
$("#upload").click(function () { var file = document.getElementById("file"); //获取所有文件 var fileList = file.files; //操作文件 handleFiles(fileList); return false; });
处理文件方法:
文件上传同步,上传文件async function handleFiles(fileList) { var i = 0; while (i
处理上传文件切片,并上传
//upload file async function uploadFile(targetFile,index) { //console.log(targetFile); var tmp = targetFile.name.split("."); var filename = "file-"+guid() + '.' + tmp[tmp.length-1] ; var fileSize = targetFile.size; var total = Math.ceil( fileSize / pieceSize ); await handle(); async function handle() { var i = 0; var start = end = 0; while(i < total){ end = start + pieceSize; if(end >= fileSize){ end = fileSize; } console.log( '文件的index:' + index+ '| 处理文件切片 i:'+i , 'start:' + start, 'end:' + end ); var frag = targetFile.slice(start, end); await send( filename,frag,i , total ,function () { console.log( '文件的index:' + index+ "| 切片上传完成 回调 res111",i) }); start = end; i++; } } } //send async function send(filename,frag,index,total,cb) { var formData = new FormData(); var fragname = "frag-" + guid(); formData.append("filename",filename); formData.append("fragname",fragname); formData.append("file",frag); formData.append("fragindex",index); formData.append("total",total); await $.ajax({ url: url, type: 'POST', cache: false, data: formData, processData: false, contentType: false }).done(function (res) { //console.log('res:' + index); cb && cb(); }).fail(function (res) { }); }
3.2 后台php
pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));$file = $_FILES['file'];//打印文件$log->info('切片',$file);$orgFileName = $_POST['filename'];$log->info("orgFileName:" . $orgFileName);//获取文件名称$filename = explode("." , $_POST['filename']);//获取文件后缀$ext = $filename[1];$filename = $filename[0];$log->info("ext:" . $ext);//新建frag 文件夹, 以filename为命名方式if(!file_exists(FRAGPATH.$filename)){ mkdir(FRAGPATH.$filename);}//将接收到的frag文件移入file文件夹中//$frag_path = SITE_ROOT.'/dir/'.$filename.'/'.iconv('UTF-8','gbk',basename($_FILES['file']['tmp_name']));$frag_path = FRAGPATH.$filename ."/". $_POST['fragname'];try{ if(move_uploaded_file($_FILES['file']['tmp_name'] , $frag_path)){ echo response(["status" => "上传成功"]); }}catch (Exception $e){ throw new Exception();}//合并file文件夹中的frag为最终文件if( $_POST['fragindex'] == $_POST["total"] -1 ){ $blob = ""; $fragDir = FRAGPATH.$filename; $handler = @opendir($fragDir); //获取filename while ( ( $fragFileName = readdir($handler) ) !== false ){ $fp = fopen( FILEPATH . '/' . $orgFileName,"ab" ); // 务必使用!==,防止目录下出现类似文件名“0”等情况 if ($fragFileName !== "." && $fragFileName !== "..") { //方式一: //$blob .= file_get_contents( $fragDir . "/" . $fragFileName ); //方式二: $value = $fragDir . "/" . $fragFileName; $handle = fopen($value,"rb"); fwrite($fp,fread($handle,filesize($value))); fclose($handle); //删除切片文件 @unlink($fragDir . "/" . $fragFileName); } } //合并切片到文件 //file_put_contents( FILEPATH. "/" . $filename . ".". $ext , $blob ); //删除切片文件夹 @rmdir($fragDir);}
最终文件上传成功删除切片文件夹下的切片
完整代码地址: