前言:

之前所写的文件上传类通常进行考虑的是文件的类型、大小是否符合要求条件。当上传大文件时就要考虑到php的配置和服务器的配置问题。之前简单的觉得只要将php.ini中的表单上传的 大小,单脚本执行的最大时间都配 大就行了。显然这是很小白吃的做法。这样改完之后页面及服务器还是会崩溃。差不多几百兆这样吧。所以查阅资料,采用将大文件分割上传的方式来解决。这里进行记录下。

内容:

  • 首先记录下更改文件上传大小的一些配置信息
  1. 打开php.ini
  2. file_uploads = on       //是否允许通过HTTP上传文件的开关,默认开启
  3. upload_tmp_dir              //临时文件储存的路径
  4. upload_max_filesize   20M         //允许上传的文件最大值
  5. post_max_size          22M         //通过表单POST所能上传的大小
  6. max_execution_time 600    //单个PHP页面允许运行的最大时间
  7. max_input_time         600        //单个PHP页面接收数据所需的最大时间,默认60秒
  8. memory_limit              256M       //单个PHP页面执行过程中可占用的最大内存,默认8M

通过更改上述的配置就可以调整允许文件上传的大小。(有的还需要调整服务器的一些配置)

补充:413错误  如果服务器是nginx的话,需要更改配置nginx_conf 中的client_max_body_size 24M,设置接收客户端发送过来包的最大值。记得放在http里,重启服务器,用restart,不要用reload。

贴下具体修改nginx配置的博文:http://blog.51cto.com/13673885/2299771。

  • 接着开始实现文件的分割上传。

文件通过HTML的input标签的file来选择文件上传。通过H5新对象FileReader。就像字面上的意思一样FileRaeder对象就是一个读取本地文件的对象。FileReader对象可以将本地文件读取后以base64位的编码返回。(具体有关FileReader对象的使用,请自行百度,或者阅读以下博文,写的很具体。博文连接:https://www.cnblogs.com/hhhyaaon/p/5929492.html

实际开发经历:

  1. 第一次尝试

    • 通过input file标签来选择文件
    • 采用FileReader对象对文件进行读取
    • 通过ajax异步将文件的base64编码发送给服务端
    • 服务端接收后对编码进行解码并保存到文件中。
    • 测试结果失败,当文件过大时所编码的长度也越长,通过ajax异步提交参数的最大上线为8000个字节。
  2. 第二次尝试
    • 在第一次的基础上对所获取到的base64编码进行分割上传
    • 将所获取的base64编码字符串分成几份并进行编号,在循环调用ajax进行发送
    • 服务端接收到后对数据进行解码,以编号进行命名
    • 接收完所有小文件后,调用后台方法将小文件进行合并
    • 测试结果失败,当上传文件超过1G时,浏览器就崩溃了。应该是在读取文件时,文件过大,一次性读出返回base64编码过大,导致页面崩溃。
    • (这边实现上要注意一点,在对base64编码分割的时候,每一段数据长度要是4的倍数才行。不然会导致文件在服务端解码合并后出错。可以去理解下base64的编码原理就懂了。当然也可以在服务器代码上避免,就是将所接收到的所有base64的字符串先拼接起来再进行解码,就不会造成错误。不过建议不要这样子,以为当上传的文件太大,假设1G的文件,编码后产生1.3G编码在代码中去执行操作,会造成内存溢出!!!!)
  3. 第三次尝试
    • 在第二次的基础上想着在读取文件获取编码的过程也进行分批读取来避免一次性读取过大的文件导致页面崩溃。
    • 这边就要使用到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;
});

php的代码太多了不贴了,后面把代码整出来,放仓库里再来把地址贴出来。

结语:快过年了,总算迎来了好消息,算个新年礼物吧!

   越努力!越幸运!

      

tp5+layui 实现上传大文件的更多相关文章

  1. [Asp.net]Uploadify上传大文件,Http error 404 解决方案

    引言 之前使用Uploadify做了一个上传图片并预览的功能,今天在项目中,要使用该插件上传大文件.之前弄过上传图片的demo,就使用该demo进行测试.可以查看我的这篇文章:[Asp.net]Upl ...

  2. php 上传大文件配置upload_max_filesize和post_max_size选项

    php 上传大文件配置upload_max_filesize和post_max_size选项 (2014-04-29 14:42:11) 转载▼ 标签: php.ini upload _files[f ...

  3. PHP上传大文件 分割文件上传

    最近遇到这么个情况,需要将一些大的文件上传到服务器,我现在拥有的权限是只能在一个网页版的文件管理系统来进行操作,可以解压,可以压缩,当然也可以用它来在线编辑.php文件. 文件有40M左右,但是服务器 ...

  4. ASP.NET上传大文件的问题

    原文:http://www.cnblogs.com/wolf-sun/p/3657241.html?utm_source=tuicool&utm_medium=referral 引言 之前使用 ...

  5. php 上传大文件主要涉及配置upload_max_filesize和post_max_size两个选项

    php 上传大文件主要涉及配置 upload_max_filesize 和post_max_size两个选项   今天在做上传的时候出现一个非常怪的问题,有时候表单提交可以获取到值,有时候就获取不到了 ...

  6. SWFUpload上传大文件(暂时用用,真正用的时候还是要改的)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. PHP上传大文件和处理大数据

    1. 上传大文件 /* 以1.5M/秒的速度写入文件,防止一次过写入文件过大导致服务器出错(chy/20150327) */ $is_large_file = false; if( strlen($x ...

  8. QQ上传大文件为什么这么快

    今天和同事在群里讨论“QQ上传大文件/QQ群发送大文件时,可以在极短的时间内完成”是如何做到的. 有时候我们通过QQ上传一个几百M的文件,竟然只用了几秒钟,从带宽上限制可以得出,实际上传文件是不可能的 ...

  9. IIS7下swfupload上传大文件出现404错误

    要求上传附件大小限制在2G,原本以为可以轻松搞定.在编译模式下可以上传大文件,可是在IIS7下(自己架的服务器),一上传大的文件就会出现 Http 404错误,偶尔有的文件还有IO. error错误. ...

随机推荐

  1. 常用lua代码块

    1.读取请求体中参数 local request_method = ngx.var.request_method local args --获取参数的值 if "GET" == r ...

  2. Python2.7-filecmp

    filecmp 模块,定义了比较文件或目录的函数,比较文件只会有 True 和 False 两种结果,比较目录会返回目录下相同的文件,不同的文件,出错的文件.比较文件也可以用 difflib 模块,d ...

  3. ubuntu系统中Qt creator 编辑和应用使用中文输入法

    在ubuntu系统的GUI开发过程中遇到在编辑器里面不能使用中文输入法,前提我已经安装了搜狗输入法,但是还是不能使用,原因是QT的库里没有最新fcix的库,. 没有安装搜狗的输入法的 https:// ...

  4. HDU 1203 I NEED A OFFER!(01背包+简单概率知识)

    I NEED A OFFER! Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Sub ...

  5. day69

    昨日回顾: 1 路由层:  1简单配置  2无名分组  3有名分组  4反向解析--模板层,视图层  5路由分发  include  6名称空间   7伪静态 2 作业:  urlpatterns = ...

  6. VBA删除 语法

    Option Explicit '清空数据  Private Sub CommandButton1_Click() Dim qknum As Integer  '选择是或者否 来确认删除数据 '中对话 ...

  7. Multi account chang login with multi -thread

    void worker_DoWork(object sender, DoWorkEventArgs e) { isBussy = true; if (Common.isChangingAccount) ...

  8. Nuget包CommonServiceLocator从1.0.3升级到2.0.4时MvvmLight的ViewModelLocator初始化SimpleIoc.Default格式不匹配问题

    原文:Nuget包CommonServiceLocator从1.0.3升级到2.0.4时MvvmLight的ViewModelLocator初始化SimpleIoc.Default格式不匹配问题 把旧 ...

  9. 使用 vi/vim 时,粘贴进新创建文件或空文件的首行内容丢失的解决方法

    只需要进入插入模式后,回车空一行或几行,再粘贴,再把上面的几个空行back回去,就不会丢失首行的内容了.

  10. [CF1063F]String Journey[后缀数组+线段树]

    题意 在 \(S\) 中找出 \(t\) 个子串满足 \(t_{i+1}\) 是 \(t_{i}\) 的子串,要让 \(t\) 最大. \(|S| \leq 5\times 10^5\). 分析 定义 ...