已有轮子
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来进行文件合并。当分片到达首次传输过来的该文件对应的总分片数时才合并。