为了解决大文件上传 (PHP上传最大限制2GB)

同时为了解决文件上传是对服务器造成的压力

可以通过分段上传解决这个问题,这得益于HTML5开发的file API

前台代码:

引用了进度条插件myProgress.js

<link href="__PUBLIC__/admin/css/myProgress.css" rel="stylesheet">
<script src="__PUBLIC__/admin/js/jquery.myProgress.js"></script> <div>
<div>
<form id="myForm">
<div>
//上传文件时由用户指定文件名
<label for="FileName">File Name</label>
<input type="text" name="title" class="form-control" id="FileName">
</div>
<div>
<label for="myFile">Chose File</label>
<input type="file" id="myFile">
<div class="progress-out" id="progress">
<div class="percent-show"><span>0</span>%</div>
<div class="progress-in"></div>
</div>
</div>
</form>
<button type="button" class="btn btn-default" id="btn">Submit</button>
</div>
</div>
<script>
//初始化上传
function initUpload() {
var chunk = 1000*1024; //每片大小
var input = document.getElementById("myFile"); //input file
input.onchange = function (e) {
//获得上传的文件
var file = this.files[0];
//如果大于指定大小 提示错误
if(file.size > 1*1024*1024*1024){
$('#help_msg').removeClass('help-block').addClass('error-block');
return ;
}else{
$('#help_msg').css('display','none');
}
// 开启进度条
$("#progress").css('display','block');
$("#progress").myProgress({speed: 1000, percent: 0, width: "200px", height: "12px"}); var query = {};
var chunks = []; if (!!file) {
var start = 0;
//文件分片
for (var i = 0; i < Math.ceil(file.size / chunk); i++) {
//最后一段取文件的真实大小
var end = 0;
if(i == (Math.ceil(file.size / chunk)-1)){
end = file.size;
}else{
end = start + chunk;
}
chunks[i] = file.slice(start , end);
start = end;
} // 采用post方法上传文件
// url query上拼接以下参数,用于记录上传偏移
// post body中存放本次要上传的二进制数据
query = {
fileName : file.name,
fileSize: file.size,
dataSize: chunk,
nextOffset: 0
} upload(chunks, query, successPerUpload);
}
}
} // 执行上传
function upload(chunks, query, cb) {
//对象转字符串 用&连接
var queryStr = Object.getOwnPropertyNames(query).map(key => {
return key + "=" + query[key];
}).join("&"); var xhr = new XMLHttpRequest();
xhr.open("POST", "/Shop/index.php/Admin/File/upload_file?" + queryStr);
xhr.overrideMimeType("application/octet-stream"); //获取post body中二进制数据
var index = Math.floor(query.nextOffset / query.dataSize);
getFileBinary(chunks[index], function (binary) {
if (xhr.sendAsBinary) {
xhr.sendAsBinary(binary);
} else {
xhr.send(binary);
} }); xhr.onreadystatechange = function (e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var resp = JSON.parse(xhr.responseText);
//通过返回数据更新进度条
var precent = Math.ceil((resp.offset / query.fileSize) * 100);
$("#progress").myProgress({speed: 1000, percent: precent, width: "200px", height: "12px"});
// 接口返回nextoffset
// resp = {
// isFinish:false,
// offset:100*1024
// }
if (typeof cb === "function") {
cb.call(this, resp, chunks, query)
}
}
}
}
} // 每片上传成功后执行
function successPerUpload(resp, chunks, query) {
if (resp.isFinish === true) {
//上传完成给出提示
$('#help_msg').css('display','block').addClass('error-block').html('success!');
} else {
//未上传完毕
query.nextOffset = resp.offset;
upload(chunks, query, successPerUpload);
}
} // 获取文件二进制数据
function getFileBinary(file, cb) {
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (e) {
if (typeof cb === "function") {
cb.call(this, this.result);
}
}
}
//初始化上传
initUpload(); //ajax模拟提交表单
$(function(){
$('#btn').click(function(){
var fd = new FormData(document.querySelector('#myForm'));
var input = document.getElementById("myFile"); //input file
var file = input.files[0];
if(!file){
$('#help_msg').css('display','block').addClass('error-block').html('please chose the file !');
return ;
}
fd.append('FileName',file.name);
fd.append('size',file.size);
$.ajax({
url : "/Shop/index.php/Admin/File/add",
type: "POST",
async : true,
data: fd,
processData: false, // 不处理数据
contentType: false, // 不设置内容类型
success : function(result){
console.log(result);
if(result.res == 1){
window.location.href = "http://localhost:8080/Shop/index.php/Admin/File/index";
}else{
$("#help_msg_1").css('display','block').html('upload faild ' + $result.msg);
}
}
});
})
}) </script>

后台PHP代码

    public function add(){
if($_POST){
$Attach = D('Attachment');
$file_path = './Upload/File/'.$_POST['FileName'];
//如果是win系统将文件名改成GBK编码
if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'){
$file_path = iconv('UTF-8', 'GBK', $file_path);
}
if(file_exists($file_path)){
//获得拓展名
$ext = strtolower(trim(substr(strrchr($_POST['FileName'], '.'), 1)));
//生成新的文件名
$url = './Upload/File/'.date("Ymdhms").rand(1000,9999).'.'.$ext;
$_POST['url'] = $url ;
//将上传的文件改名,将新的路径存入数据库
if(rename($file_path, $url)){
$res = $Attach -> add_file($_POST);
if($res['res']){
$log['remark'] = session('userinfo')['name'].'在'.date("Y-m-d H:i:s").'上传了文件';
D('ActionLog') -> add_log($log);
$this -> ajaxReturn(array('res' => 1));
}else{
$this -> ajaxReturn(array('res' => 0 , 'msg' => $res['msg']));
}
}
}else{
$this -> ajaxReturn(array('res' => 0, 'msg' => '上传文件不存在'));
}
}else{
$this -> show();
}
}
//异步分段上传文件
public function upload_file(){ $path = './Upload/File/'.$_GET['fileName'];
if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'){
$path = iconv('UTF-8', 'GBK', $path);
}
if(!file_exists($path)){
$handle = fopen($path, "a+");
fclose($handle);
}
file_put_contents($path, file_get_contents('php://input'),FILE_APPEND|LOCK_EX);
$offset = filesize($path);
if( $offset >= $_GET['fileSize'] ){
$this -> ajaxReturn(array('isFinish' => true));
}else{
$this -> ajaxReturn(array('isFinish' => false , 'offset' => $offset));
}
}

JS 异步分段上传文件的更多相关文章

  1. js实现分段上传文件

    使用js实现分段上传文件,本文使用了FileReader对象,可参考:https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader 1)获取文 ...

  2. c#+js 使用formdata上传文件

    如果不是使用form表单submit的形式,我们可以手动通过formdata传值(针对文件上传等) 比如: <html> <head> <meta name=" ...

  3. Nodejs学习笔记(八)--- Node.js + Express 实现上传文件功能(felixge/node-formidable)

    目录 前言 formidable简介 创建项目并安装formidable 实现上传功能 运行结果 部分疑惑解析 写在之后 前言 前面讲了一个构建网站的示例,这次在此基础上再说说web的常规功能---- ...

  4. Nodejs学习笔记(八)—Node.js + Express 实现上传文件功能(felixge/node-formidable)

    前言 前面讲了一个构建网站的示例,这次在此基础上再说说web的常规功能----文件上传,示例以一个上传图片的功能为例子 上传功能命名用formidable实现,示例很简单! PS:最近比较忙,距上一次 ...

  5. js拖拽上传 文件上传之拖拽上传

    由于项目需要上传文件到服务器,于是便在文件上传的基础上增加了拖拽上传.拖拽上传当然属于文件上传的一部分,只不过在文件上传的基础上增加了拖拽的界面,主要在于前台的交互, 从拖拽的文件中获取文件列表然后调 ...

  6. 使用Python3.7+Tornado5.1配合七牛云存储api来异步切分上传文件

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_123 之前写了几篇关于FastDfs分布式存储的文章:python3.7.3操作FastDfs来进行文件操作,其实市面上关于云存储 ...

  7. js无刷新上传文件

    传统的文件上传方式 <form action="" method="POST" enctype="multipart/form-data&quo ...

  8. JS分段上传文件(File)并使用MD5.js加密文件段用来后台校验

    HTML <form method="POST" name="form1" action="/mupload/upload/" enc ...

  9. 传统表单提交文件上传,以及FormData异步ajax上传文件

    传统的文件上传: 只用将form表单的entype修改成multipart/form-data,然后就可以进行文件上传,这种方式常用并且简单. 以下是另一种方式FormData,有时候我们需要ajax ...

随机推荐

  1. ribbon的注解使用报错--No instances available for [IP]

    使用RestTemplate类调用其他系统的url的时候,加上ribbon的注解@LoadBalanced上这个注解之后访问,就报错了. 报错如下: 因为这里你不能直接访问地址,需要把地址改成你所调用 ...

  2. JSON Web Tokens测试工具

    JSON Web Tokens官方提供测试工具https://jwt.io某些静态资料需要链接google.twitter服务器,被墙无法访问.现在提供可以方法测试工具http://hingtai.c ...

  3. python 数组 变成 字典的方法

    1.现在有两个列表,list1 = ['key1','key2','key3']和list2 = ['1','2','3'],把他们转为这样的字典:{'key1':'1','key2':'2','ke ...

  4. 笔记函数 - Ring0 Sleep()

    #define DELAY_ONE_MICROSECOND (-10) #define DELAY_ONE_MILLISEND (DELAY_ONE_MICROSECOND*1000) void Sl ...

  5. UTC时间和普通时间的区别

            UTC时间 [root@openstack01 ~]# timedatectl Local time: Sat 2018-08-18 23:04:24 CST Universal ti ...

  6. win10以上系统设定PPTP自动拨号

    :bohaorasdial adsl 123 123if not %errorlevel% == 0 goto :bohaoexit rasdial adsl 123 123 rasdial是开始拨号 ...

  7. 市值3万亿的facebook再出丑闻,你的数据,到底应该归谁?

    最近一则<Facebook隐私泄露事件继续发酵,黑客明码标价出售聊天信息>的新闻被爆出,一个用户的信息被标价10美分.让人不禁感慨,3万亿市值的facebook,用户数据竟然如此便宜. 在 ...

  8. Zabbix故障总结(持续更新)

    Zabbix housekeeper processes more than 75% busy 问题原因 为了防止数据库持续增大,zabbix有个自动删除历史数据的机制,就是housekeeper,而 ...

  9. window.open打开新窗口报错ie 位指明错误,原因是window没有加引号!

    function JsMod(htmlurl,tmpWidth,tmpHeight){ htmlurl=getRandomUrl(htmlurl); var newwin = window.open( ...

  10. ZBrush常用3D术语

    转自:http://www.zbrushcn.com/jichu/zbrush-cy-3dsys.html Polygon(多边形) 多边形是一种形状,通过在3D空间连接几个点而创建,最简单的形式就是 ...