首先记录下更改文件上传大小的一些配置信息.
打开php.ini
file_uploads = on //是否允许通过HTTP上传文件的开关,默认开启
upload_tmp_dir //临时文件储存的路径
upload_max_filesize 20M //允许上传的文件最大值
post_max_size 22M //通过表单POST所能上传的大小
max_execution_time 600 //单个PHP页面允许运行的最大时间
max_input_time 600 //单个PHP页面接收数据所需的最大时间,默认60秒
memory_limit 256M //单个PHP页面执行过程中可占用的最大内存,默认8M
通过更改上述的配置就可以调整允许文件上传的大小。(有的还需要调整服务器的一些配置)
补充:413错误 如果服务器是nginx的话,需要更改配置nginx_conf 中的client_max_body_size 24M,设置接收客户端发送过来包的最大值。记得放在http里,重启服务器,用restart,不要用reload。
接着开始实现文件的分割上传。
文件通过HTML的input标签的file来选择文件上传。通过H5新对象FileReader。就像字面上的意思一样FileRaeder对象就是一个读取本地文件的对象。FileReader对象可以将本地文件读取后以base64位的编码返回。(具体有关FileReader对象的使用,请自行百度,或者阅读以下博文,写的很具体。
实际开发
第一次尝试
通过input file标签来选择文件
采用FileReader对象对文件进行读取
通过ajax异步将文件的base64编码发送给服务端
服务端接收后对编码进行解码并保存到文件中。
测试结果失败,当文件过大时所编码的长度也越长,通过ajax异步提交参数的最大上线为8000个字节。
第二次尝试
在第一次的基础上对所获取到的base64编码进行分割上传
将所获取的base64编码字符串分成几份并进行编号,在循环调用ajax进行发送
服务端接收到后对数据进行解码,以编号进行命名
接收完所有小文件后,调用后台方法将小文件进行合并
测试结果失败,当上传文件超过1G时,浏览器就崩溃了。应该是在读取文件时,文件过大,一次性读出返回base64编码过大,导致页面崩溃。
第三次尝试
在第二次的基础上想着在读取文件获取编码的过程也进行分批读取来避免一次性读取过大的文件导致页面崩溃。
这边就要使用到H5的file.slice()来对文件进行分块,从而实现分批读取分批上传。
通过FlieReader对象来读取文件快
通过ajax将base64编码异步发送到服务端
服务端接收数据进行解码和文件保存
测试成功,测试上传了快4G的文件。
(由于将文件进行了分段,所以在上传大文件时会发起大量的ajax请求,产生大量的并发,可能会导致页面再次崩溃。所以我才用错开请求的方式。减慢产生ajax请求的速度。)
具体实现代码
接下来贴点代码
前端框架:layui
后端框架:tp5
页面代码:
<div class="layui-form-item"> <label class="layui-form-label">视频上传</label> <div class="layui-input-block layui-upload-video-btn"> <ul> <li class="img-upload"> <label></label> <input type="file" class="video-upload-file layui-upload-video-file-btn" name="file"/> <video width="320" height="240" controls style="display: none"> <source src="" type="video/mp4"> <source src="" type="video/ogg"> 您的浏览器不支持Video标签。 </video> <span style="display: none">X</span> <input type="hidden" class="video-link-id" name="video_link_id" value=""> </li> <li>//视频上传会比较久(上传完会有提示)</li> </ul> </div> </div>
js代码:
$('.video-upload-file').on('change',function(){ layer.msg('正在提交视频......'); //隐藏按钮,显示进度条 $('.layui-upload-video').hide(); $('.layui-progress-ads').show(); var loads_video = layer.load(2,{shade: [0.2, '#3a3535']}); //产生加载圈,禁止用户其他操作 var thisFile = $(this); var reader=new FileReader(); var file_size = this.files[0].size; //文件大小 var limit = 8388608; //每次读取文件的大小 // var limit = 1048000; //每次读取文件的大小 var up_count = Math.ceil(file_size/limit); //总上传次数 var type = this.files[0].type.substr(this.files[0].type.indexOf('/')+1); //文件类型 var success_num = 0; //用于存放上传成功的数据的id var check = 1; //防止多次合并 console.log('文件大小:'+this.files[0].size); console.log('文件类型:'+type); console.log('分割上传次数:'+up_count); //分段读取文件 readFile(this.files[0], 0, limit); function readFile(file, num, limit){ // console.log('第'+num+'次:'+num*limit); reader.readAsDataURL(file.slice(num*limit, (num+1)*limit)); reader.onload = function(e){ console.log(reader.result.length); console.log(reader.result); //异步base64的数据传输到服务器 ajax_way(reader.result, name, num+1, thisFile); if((num+1)*limit <= file_size){ readFile(file, num+1, limit); } } } function ajax_way(data,name,num, thisFile){ //避免一次性生成太多的请求 if(num+1 > 60){ // console.log('等待两秒'); sleep(6000); // console.log('等待结束'); } $.ajax({ url: "<?= url('admin/video/up_mfile');?>", type: "POST", data: {video:data,name:name,num:num}, // async:false, //是否采用同步,串行发送请求 success: function (data) { if(data.code == 1){ //上传成功,成功次数加一 success_num++; console.log(num+'完成'); console.log('已完成:'+success_num+'/'+up_count); //计算完成的百分比 var precentage = Math.ceil((success_num/up_count)*100); //更改进度条显示 $('.layui-progress-ads-btn').attr('lay-percent', precentage+'%'); $('.layui-progress-ads-btn').css('width', precentage+'%'); $('.layui-progress-text').html(precentage+'%'); //如果分割文件都上传了则调用接口合并文件 if(success_num == up_count && check == 1){ check = 0; success_num = 0; merge_mfile(name, up_count, thisFile, type); } } }, error:function(e){ console.log('出错了:'+num); //传输出错则重新上传 ajax_way(data, name, num, thisFile); } }); } //合并文件 function merge_mfile(name, count, thisFile, type){ $.ajax({ url:"<?= url('admin/video/merge_mfile');?>", data:{name:name, count:count, type:type}, type:"POST", success:function(data){ if (data.code==1){ layer.close(loads_video); layer.msg('视频提交成功'); thisFile.siblings('.video-link-id').val(data.data); }else{ layer.msg('视频提交异常请重新提交'); //显示按钮,隐藏进度条 $('.layui-upload-video').show(); $('.layui-progress-ads').hide(); //将进度条置零 $('.layui-progress-ads-btn').attr('lay-percent', '0%'); $('.layui-progress-ads-btn').css('width', '0%'); $('.layui-progress-text').html('0%'); //清空已选中的文件 var file = $(".layui-upload-video-file-btn"); file.after(file.clone().val("")); file.remove(); } } }) } function sleep(n) { //n表示的毫秒数 var start = new Date().getTime(); while (true) if (new Date().getTime() - start > n) break; } return false; });
更多layui知识请关注layui使用教程栏目。
以上是tp5+layui实现上传大文件介绍的详细内容。更多信息请关注PHP中文网其他相关文章!