已有轮子
http://fex.baidu.com/webuploader/
原理
前端通过file.slice
对文件做切割,后端拼接。
简单实现
用别人的代码做了下实验,https://www.cnblogs.com/fjzhang/p/7227401.html
分片上传,这样就不用担心服务器请求超时了。
前端页面
<div class="layui-container"> <input type="file" id="file" multiple required> <br> <div class="layui-progress layui-progress-big" lay-filter="demo"> <div class="layui-progress-bar layui-bg-green"></div> </div> <br> <button class="layui-btn btnFile">立即提交</button> <script type="text/javascript"> var element = layui.element; var time = new Date().getTime(); var upload = function (file, num) { var formData = new FormData(); var blockSize = 1024 * 1000; var blockNum = Math.ceil(file.size / blockSize); var nextSize = Math.min(num * blockSize, file.size); var fileData = file.slice((num - 1) * blockSize, nextSize); formData.append("file", fileData); formData.append("fileName", file.name + time); $.ajax({ url: "/admin/op/seoAsk?action=fileUpload", type: "POST", data: formData, processData: false, contentType: false, success: function (responseText) { element.progress('demo', ((num * 100) / blockNum) + '%'); if (file.size <= nextSize) { layer.msg("上传成功"); return; } upload(file, ++num);//递归调用 } }); }; $(".btnFile").click(function () { var file = $("#file")[0].files[0]; upload(file, 1); }); </script> </div>
后端实现
$file = isset($_FILES['file']) ? $_FILES['file']:null; //分段的文件 if (!isset($_POST['fileName'])) { echo 'failed'; } $filename = str_replace(["..","/"."\\"],"",$_POST['fileName']); $content = file_get_contents($file['tmp_name']); if (!file_put_contents($name, $content, FILE_APPEND)) { echo 'failed'; }
优化与改进
- 鉴权
- 断点续传
- 多线程上传
我设想的一个思路:
第一步,客户端发送身份
+文件 md5
,以及该文件的总分片数。身份可以是登录用户的 uid。
第二步,服务端返回该文件已经上传了的分片索引数组,这样就可以可以实现断点续传。我们设定分片大小是固定的,如果文件 md5 不变,那么它分片的结果也不会变。
第三步,前端根据后端返回的分片索引来并行的上传文件,而不需要像上面那样同步递归。
第四步,服务端收到分片根据客户端身份和文件 md5来进行文件合并。当分片到达首次传输过来的该文件对应的总分片数时才合并。