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 ...
随机推荐
- mysql 数据库排序规则
MySQL中的排序规则.在新建MySQL数据库或表的时候经常会选择字符集和排序规则.数据库用的字符集大家都知道是怎么回事,那排序规则是什么呢? 排序规则:是指对指定字符集下不同字符的比较规则.其特征有 ...
- 【springboot】之 解析@EnableWebMvc 、WebMvcConfigurationSupport和WebMvcConfigurationAdapter
springboot默认格式化日期只需要在application文件中配置 spring.jackson.date-format= yyyy-MM-dd HH:mm:ss spring.jackson ...
- 【java】之彻底明白进制转换
首先区分 2进制 只有0和1组成 如:0101018进制 以0开头,0~7组成 如:01234510进制 以1~9开头,0~9组成 如:10016进制 以0X开头,0~9或者a ...
- C/C++基础----动态内存
why 管理较难,忘记释放会内存泄漏,提早释放可能非法引用,重复释放. 为了更容易,更安全的使用动态内存,提供智能指针,其默认初始化保存一个空指针. what shared_ptr允许多个指针指向同一 ...
- C++进阶--解谜operator new/delete
//############################################################################ // 解谜operator new/del ...
- vagrant在windows下的安装和配置
记录一下安装和配置过程中的一些坑步骤一分别下载vagrant和VirtualBox,我这里下载的是vagrant_1.9.1.msi 和 VirtualBox-5.1.14-112924-Win.ex ...
- 基于Kafka消息驱动最终一致事务(二)
实现用例分析 上篇基于Kafka消息驱动最终一致事务(一)介绍BASE的理论,接着我们引入一个实例看如何实现BASE,我们会用图7显示的算法实现BASE.
- 网站钓鱼的方法 和 xss
获取cookie利用代码cookie.asp <html> <title>xx</title> <body> <%testfile = Serve ...
- 面向对象php 接口 抽象类
1.定义类和实例化对象: 使用关键字class定义类,使用new实例化对象: 2.类成员的添加和访问: 类成员:有属性,方法,常量(常量名不带$符): 访问属性的时候,变量名不带$符 添加属性需要使用 ...
- [UE4]裁剪 Clipping
Clipping裁剪,是每个UI都有的属性.一般是在容器UI上设置,对容器内的UI进行裁剪. 一.Clip to Bounds:裁剪到边界 二.Clip To Bounds - Without Int ...