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 ...
随机推荐
- jQuery 闪动的文字提示
原文地址:http://www.cnblogs.com/kiter/archive/2013/02/22/2922242.html 声明,本文转自网络. jQuery 闪动的文字提示,仿QQ头像闪烁闪 ...
- [UE4]行为树,组合节点:Selector和Sequence
行为树节点 一.Composite组合节点: 1.Selector 要求比较低:只要有一个子节点成功就可以了. 只要子节点有一个返回true,则停止执行其它子节点,并且Selector返回true.如 ...
- CVE-2017-8570漏洞利用
CVE-2017-8570漏洞是一个逻辑漏洞,利用方法简单,影响范围广.由于该漏洞和三年前的SandWorm(沙虫)漏洞非常类似,因此我们称之为“沙虫”二代漏洞. 编号 CVE-2017-8570 影 ...
- C#存储过程中return参数
//1 连接字符串 string connectionString = "server=127.0.0.1;integrated security=true;database=MSPetSh ...
- 有关Set集合的一个小问题
先看两段代码: Demo1: Set<Short>s=new HashSet<>(); for(Short i=0;i<100;i++){ s.add(i); s.rem ...
- 第8课 列表初始化(3)_防止类型收窄、explicit关键字
1. 防止类型收窄 (1)类型收窄:指的是导致数据内容发生变化或者精度丢失的隐式类型转换. (2)类型收窄的几种情况: ①从浮点数隐式转换为整型数,如int i=2.2; ②从高精度浮点数隐式转换为低 ...
- Synchronized常用用法
我们都知道 Synchronized 是线程安全同步用的,大部分程序可能只会用到同步方法上面.其实 Synchronized 可以用到更多的场合,栈长列举了以下几个用法. 1.同步普通方法 这个也是我 ...
- mapreduce深入剖析5大视频
参考代码 TVPlayCount.java package com.dajiangtai.hadoop.tvplay; import java.io.IOException; import org.a ...
- 用Python进行人脸识别
本文的模型使用了C++工具箱 dlib 基于深度学习的最新人脸识别方法,基于户外脸部数据测试库Labeled Faces in the Wild 的基准水平来说,达到了99.38%的准确率. dlib ...
- Android标题头滑动渐变,Titlebar滑动渐变,仿美团饿了么标题头渐变;
原理就是滑动中改变透明度: 核心代码: rv.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public vo ...