JS 异步分段上传文件
为了解决大文件上传 (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 异步分段上传文件的更多相关文章
- js实现分段上传文件
使用js实现分段上传文件,本文使用了FileReader对象,可参考:https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader 1)获取文 ...
- c#+js 使用formdata上传文件
如果不是使用form表单submit的形式,我们可以手动通过formdata传值(针对文件上传等) 比如: <html> <head> <meta name=" ...
- Nodejs学习笔记(八)--- Node.js + Express 实现上传文件功能(felixge/node-formidable)
目录 前言 formidable简介 创建项目并安装formidable 实现上传功能 运行结果 部分疑惑解析 写在之后 前言 前面讲了一个构建网站的示例,这次在此基础上再说说web的常规功能---- ...
- Nodejs学习笔记(八)—Node.js + Express 实现上传文件功能(felixge/node-formidable)
前言 前面讲了一个构建网站的示例,这次在此基础上再说说web的常规功能----文件上传,示例以一个上传图片的功能为例子 上传功能命名用formidable实现,示例很简单! PS:最近比较忙,距上一次 ...
- js拖拽上传 文件上传之拖拽上传
由于项目需要上传文件到服务器,于是便在文件上传的基础上增加了拖拽上传.拖拽上传当然属于文件上传的一部分,只不过在文件上传的基础上增加了拖拽的界面,主要在于前台的交互, 从拖拽的文件中获取文件列表然后调 ...
- 使用Python3.7+Tornado5.1配合七牛云存储api来异步切分上传文件
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_123 之前写了几篇关于FastDfs分布式存储的文章:python3.7.3操作FastDfs来进行文件操作,其实市面上关于云存储 ...
- js无刷新上传文件
传统的文件上传方式 <form action="" method="POST" enctype="multipart/form-data&quo ...
- JS分段上传文件(File)并使用MD5.js加密文件段用来后台校验
HTML <form method="POST" name="form1" action="/mupload/upload/" enc ...
- 传统表单提交文件上传,以及FormData异步ajax上传文件
传统的文件上传: 只用将form表单的entype修改成multipart/form-data,然后就可以进行文件上传,这种方式常用并且简单. 以下是另一种方式FormData,有时候我们需要ajax ...
随机推荐
- 寻找数组中第K大的数
给定一个数组A,要求找到数组A中第K大的数字.对于这个问题,解决方案有不少,此处我只给出三种: 方法1: 对数组A进行排序,然后遍历一遍就可以找到第K大的数字.该方法的时间复杂度为O(N*logN) ...
- redis(redis概念,运用场景,如何操作基本数据类型)
什么是redis:Nosql一种缓存数据库 redis可以干什么:redis可以减轻对数据库的请求压力如果不使用缓存:客服端->控制层->业务层->dao层使用缓存:客服端-> ...
- Jmeter(十九)Logic Controllers 之 Module Controller and Include Controller
Module Controller ---模块控制器 测试计划设置“独立运行没每个线程组” 线程组2中使用Module Controller执行线程组1中的Sampler: 紧接着,将线程组1disa ...
- android Information:Gradle tasks [:dl_version:generateDebugSources, :dl_version:generateDebugAndroidTestSources导致无法实现Preview功能
Androidstudio 出现以下错误导致layout xml无法实现预览功能: Information:Gradle tasks [:dl_version:generateDebugSources ...
- typescript泛型类 泛型方法
/* 泛型:软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性. 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能. 在像C# ...
- 非mapreduce生成Hfile,然后导入hbase当中
转自:http://blog.csdn.net/stark_summer/article/details/44174381 未实验 最近一个群友的boss让研究hbase,让hbase的入库速度达到5 ...
- 第41课 kmp子串查找算法
1. 朴素算法的改进 (1)朴素算法的优化线索 ①因为 Pa != Pb 且Pb==Sb:所以Pa != Sb:因此在Sd处失配时,子串P右移1位比较没有意义,因为前面的比较己经知道了Pa != Sb ...
- python基础知识-(1)语法基础知识总结(转载)
1.Python标识符 在 Python 里,标识符有字母.数字.下划线组成. 在 Python 中,所有标识符可以包括英文.数字以及下划线(_),但不能以数字开头. Python 中的标识符是区分大 ...
- react 数据管理之state思想指南
react的数据管理库有不少,最常听到的可能是mobx redux altjs之类的,当然还有很多其他,可以自己搜索. 为什么需要数据管理库呢,因为react本身只是为了实现view的表现,而不是数据 ...
- Android CoordinatorLayout实现多列表切换并和头布局联动;
注意:不是双列表联动,是多列表和头布局联动: 大概就是和饿了么店铺首页类似的布局框架吧,头布局显示时,列表RecyclerView或ScrollView和头布局一起滚动,头布局完全隐藏后列表再去滚动, ...