首页 > 编程语言 >基于php+webuploader的大文件分片上传,支持断点续传,带进度条

基于php+webuploader的大文件分片上传,支持断点续传,带进度条

时间:2023-09-19 11:44:41浏览次数:42  
标签:function 断点续传 postData 进度条 webuploader 文件 file msg 上传

基于php+webuploader的大文件分片上传,带进度条,支持断点续传(刷新、关闭页面、重新上传、网络中断等情况)。文件上传前先检测该文件是否已上传,如果已上传提示“文件已存在”,如果未上传则直接上传。视频上传时会根据设定的参数(分片大小、分片数量)进行上传,上传过程中会在目标文件夹中生成一个临时文件夹,用于存储临时分片,等所有分片上传完毕后,会根据序号重新组合成一个完整的视频,临时文件被删除。

如果文件上传至七牛云,可参看基于php大文件分片上传至七牛云,带进度条

首先下载webuploader

效果图:

 

临时文件,用于存储分片

 html代码

<title>webuploader分片上传</title>
<meta charset="utf8">
<!--引入CSS-->
<link rel="stylesheet" type="text/css" href="/static/webupload/webuploader.css">
<script type="text/javascript" src="/static/index/js/jquery.js"></script>
<script type="text/javascript" src="/static/index/js/jquery.md5.js"></script>

<!--引入JS-->
<script type="text/javascript" src="/static/webupload/webuploader.js"></script>
<div id="uploader" class="wu-example">
<!--用来存放文件信息-->
<div id="thelist" class="uploader-list"></div>
<div class="btns">
<div id="picker">选择文件</div>
<button id="ctlBtn" class="btn btn-default">开始上传</button>
</div>
</div>
<style>
.progress{
height: 20px; width: 300px; background: #ccc; }
.progress-bar{
height: 20px; background: #0a3536;}
</style>
<script>

var uploadswf = '/static/webupload/Uploader.swf';
var chunkSize = 2*1024*1024;
var server_url='uploadVedio';
var GUID = WebUploader.Base.guid();//一个GUID
var chunkObj = {}; //用来记录文件的状态、上传中断的位置
var seq=1;
var msg='';
$(function () {
var $ = jQuery;
var $list = $('#thelist');
WebUploader.Uploader.register({
"before-send-file":"beforeSendFile",
"before-send": "beforeSend"
}, {
"beforeSendFile": function (file) {
//上传前校验文件是否已经上传过
var deferred = WebUploader.Deferred();
$.ajax({
type:"POST",
//上传前校验文件上传到第几片
url: "checkFile",
data: {
seq: seq,
fileMd5: $.md5(file.name + file.size + file.ext),
fileName:file.name
},
dataType: "json",
success: function (data) {
console.log(data);
chunkObj = data;
chunkObj.type = data.type;
chunkObj.chunk == data.chunk;
msg = data.msg;
if(data.type==404){
deferred.reject();
$("#" + file.id).find(".state").text(data.msg);
}else if (data.type == 0) {
deferred.reject();
$("#" + file.id).find(".state").text("文件已上传");
} else if (data.type == 1) {
if (data.chunk) {
deferred.resolve();
}
} else {
deferred.resolve();
}

},
error: function () {
deferred.resolve();
}
})
//deferred.resolve();
return deferred.promise();
},
"beforeSend": function (block) {
var deferred = WebUploader.Deferred();
var curChunk = block.chunk;
var totalChunk = block.chunks;
console.log(chunkObj)
if (chunkObj.type == "1") {
if (curChunk < chunkObj.chunk) {
deferred.reject();
} else {
deferred.resolve();
}
} else {
deferred.resolve();
}
return deferred.promise();
}
});
var uploader = WebUploader.create({
// 选完文件后,是否自动上传。
auto: false,
// swf文件路径
swf: uploadswf,
// 文件接收服务端。
server: server_url,
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: '#picker',
chunked: true,//开始分片上传
chunkSize:1 * 1024 * 1024,//每一片的大小
threads: 1,
formData: {
},

// 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
resize: false
});

// 当有文件被添加进队列的时候
uploader.on('fileQueued', function (file) {

$list.append('<div id="' + file.id + '" class="item">' +
'<div class="item-file"><div class="fileType-logo"></div>' +
'<div class="fileMes"><h4 class="info">' + file.name + '</h4>' +
'<p class="state">等待上传...</p>' +
'</div></div></div>');

});
// 文件上传过程中创建进度条实时显示。
uploader.on('uploadProgress', function (file, percentage) {
var $li = $('#' + file.id),
$percent = $li.find('.progress .progress-bar');
// 避免重复创建
if (!$percent.length) {
$percent = $('<div class="progress progress-striped active">' +
'<div class="progress-bar" role="progressbar" style="width: 0%">' +
'</div>' +
'</div>').appendTo($li).find('.progress-bar');
}
$li.find('p.state').text('上传中');
$percent.css('width', percentage * 100 + '%');
});
uploader.on("uploadBeforeSend", function (obj, data, headers) {
var file = obj.cuted.file;


data.test = 1;
data.fileMd5 = $.md5(file.name + file.size + file.ext);


})
// 文件上传成功,给item添加成功class, 用样式标记上传成功。
uploader.on('uploadSuccess', function (file, response) {
if(response.status==299){
$('#' + file.id).find('p.state').text('文件已存在');
}else{
$('#' + file.id).find('p.state').text('已上传');
}

});
// 文件上传失败,显示上传出错。
uploader.on('uploadError', function (file) {
$('#' + file.id).find('p.state').text(msg);
});
// 完成上传完了,成功或者失败,先删除进度条。
uploader.on('uploadComplete', function (file) {
$('#' + file.id).find('.progress').fadeOut();
});
//所有文件上传完毕
uploader.on("uploadFinished", function () {
//提交表单
});
//开始上传
$("#ctlBtn").click(function () {
uploader.upload();

});
});

</script>

php请求后端

// 引用封装好的Upload类
use app\index\controller\Upload;
public function uploadVedio()
{
$model =new Upload();
$res = $model->doUpload();
$model->ajaxReturn($res);

}

封装上传类

<?php
namespace app\index\controller;
use think\Controller;

/**
* 大文件分片上传
*/
class Upload extends Controller
{


private $filepath = 'uploads/'; //上传目录
private $blobNum; //第几个文件块
private $totalBlobNum; //文件块总数
private $fileName; //文件名
#允许上传的文件
private $allowExtension = ['mp4','avi','wmv'];
#文件后缀
private $fileExtension ='';
#当前块内容
private $nowFile = '';
#文件大小
private $totalSize = 0;
#文件总大小只允许1G
private $allowFileSize = 0;
#文件md5 前端传过来的 用于创建临时文件夹 上传完后删除
private $fileMd5='';

public function __construct($savePath =''){
$postData = $_POST;
#测试断点上传
if(isset($postData['test'])){
sleep(1);
}
if($savePath){
$this->filepath = $this->filepath.$savePath;
}
# #文件名称
# var_dump($postData);
$postData['name'] =isset($postData['name'])?$postData['name']:'';
$this->fileName =$postData['name'];
if($this->isHaveFile()){
$this->ajaxReturn(['status'=>299,'msg'=>'文件已存在!']);
}

$this->fileMd5 =$postData['fileMd5'];

#允许文件的大小 1G
$this->allowFileSize =(1*1024*1024*1024);

if((int)$postData['size']>$this->allowFileSize){
$this->ajaxReturn(['status'=>204,'msg'=>"文件大小超1G限制!"]);
}
#文件大小
$this->totalSize=$postData['size'];
$postData['chunks']=isset($postData['chunks'])?(int)$postData['chunks']:1;
$postData['chunk']=isset($postData['chunk'])?(int)$postData['chunk']:0;
if(!(int)$postData['chunks']){
$this->ajaxReturn(['status'=>208,'msg'=>'chunks参数错误']);
}

#当前块
$this->blobNum =$postData['chunk']+1;
#总共块
$this->totalBlobNum =$postData['chunks'];

#获取后缀
$fileExtension =explode(".",basename( $this->fileName));
$this->fileExtension=array_pop($fileExtension);
#检测后缀是否在允许范围
$this->checkFileExtension();
$this->nowFile = $_FILES['file'];
if( $this->nowFile['error'] > 0) {
$msg['status'] = 502;
$msg['msg'] = "文件错误!";
$this->ajaxReturn($msg);
}

}
public function doUpload(){
#临时文件移动到指定目录下
$res = $this->moveFile();
if($res['status']==999){
return $this->fileMerge();
}else{
return $res;
}
}

#创建md5 文件名
public function createFileName(){
return $this->filepath.$this->fileName;
}

#检测文件是否重复
public function isHaveFile(){
if(file_exists($this->filepath.$this->fileName)){
return true;
}
return false;
}
#文件合并
public function fileMerge(){
if ($this->blobNum == $this->totalBlobNum) {
$fileName = $this->createFileName();
@unlink($fileName);
#删除旧文件
#文件合并 文件名以
$handle=fopen($fileName,"a+");
for($i=1; $i<= $this->totalBlobNum; $i++){
#当前分片数
$this->blobNum = $i;
#吧每个块的文件追加到 上传的文件中
fwrite($handle,file_get_contents($this->createBlockFileName()));
}
fclose($handle);
#删除分片
for($i=1; $i<= $this->totalBlobNum; $i++){
$this->blobNum = $i;
@unlink($this->createBlockFileName());
}
#删除临时目录
@rmdir($this->filepath.$this->fileMd5);
if(filesize($fileName) == $this->totalSize){
$msg['status'] = 200;
$msg['msg'] = '上传成功!';
$msg['size'] = $this->totalSize;
$msg['filename'] = "http://".$_SERVER['HTTP_HOST']."/".$this->createFileName();
$msg['name'] = $this->fileName;
}else{
$msg['status'] = 501;
$msg['msg'] = '上传文件大小和总大小有误!';
@unlink($this->createFileName());
}
return $msg;
# $this->ajaxReturn($msg);
}
}
#检测上传类型
public function checkFileExtension(){
if(!in_array(strtolower($this->fileExtension),$this->allowExtension)){
$this->ajaxReturn(['status'=>203,'msg'=>"文件类型不允许"]);
}
}
#将临时文件移动到指定目录
public function moveFile(){
try{
#每个块的文件名 以文件名的MD5作为命名
$filename=$this->createBlockFileName();
#分片文件写入
$handle=fopen($filename,"w+");
fwrite($handle,file_get_contents($this->nowFile ['tmp_name']));
fclose($handle);
#不是最后一块就返回当前信息 是最后一块往下执行合并操作
if($this->blobNum != $this->totalBlobNum) {
$msg['status'] = 201;
$msg['msg'] = "上传成功!";
$msg['blobNum'] = $this->blobNum;
return $msg;
#$this->ajaxReturn($msg);
}else{
$msg['status'] = 999;
$msg['msg'] = "上传成功!";
$msg['blobNum'] = $this->blobNum;
return $msg;
}
}catch (Exception $e){
$msg['status'] = 501;
$msg['error'] = $e->getMessage();
return $msg;
#$this->ajaxReturn($msg);
}
}
#创建分片文件名
public function createBlockFileName(){
$dirName = $this->filepath.$this->fileMd5."/";
if (!is_dir($dirName) ) {
@mkdir($dirName, 0700);
};
return $dirName.$this->blobNum.".part";
}

#json格式放回处理
public function ajaxReturn($msg){
exit(json_encode($msg));
}
}

参考文章:http://blog.ncmem.com/wordpress/2023/09/19/%e5%9f%ba%e4%ba%8ephpwebuploader%e7%9a%84%e5%a4%a7%e6%96%87%e4%bb%b6%e5%88%86%e7%89%87%e4%b8%8a%e4%bc%a0%ef%bc%8c%e6%94%af%e6%8c%81%e6%96%ad%e7%82%b9%e7%bb%ad%e4%bc%a0%ef%bc%8c%e5%b8%a6%e8%bf%9b/

欢迎入群一起讨论

 

 

标签:function,断点续传,postData,进度条,webuploader,文件,file,msg,上传
From: https://www.cnblogs.com/songsu/p/17714222.html

相关文章

  • php上传断点续传
    Ⅰ求php上传大文件的三种解决方案第一种是使用第三方的存储空间,这种比较方便,也不需要你做什么,直接请求接口就好啦。第二种可以使用ftp方式进行大文件上传,支持断点续传。第三种是用php调用服务端程序来上传,比如调用python等等开发的上传功能ⅡPHP大文件上传,支持断点续传,求具体......
  • ABAP进度条
    *进度条例子1:DATA:perctypei,cntTYPEi.DATA:stxtTYPEstring.DATA:sperc(3)TYPEc.perc=0.cnt=1000.DOcntTIMES.stxt=''.perc=sy-index*100/cnt.sperc=perc.CONCATENATE'已经完成:'sperc'%......
  • 如何在gradio使用多进程,并且使用进度条显示多进程
    直接上代码:defmethod_a(progress=gr.Progress(track_tqdm=True)):pool=multiprocessing.Pool(multiprocessing.cpu_count())param_v=range(10)pbar=tqdm(total=len(param_v))resy=[]forpinparam_v:pool.apply_async(task_deal......
  • python分片和断点续传oss
    分片上传和断点续传是常见于文件上传至云存储服务的操作,其中OSS(ObjectStorageService)是阿里云提供的云存储服务。Python可以用来实现分片上传和断点续传到阿里云OSS。下面是一个简单的示例,演示了如何使用Python和阿里云OSSSDK进行分片上传和断点续传。首先,确保你已......
  • 百度开源上传组件webuploader
    //上传多文件   functionUploadMultiFile(){       varuploader=WebUploader.create({           //选完文件后,是否自动上传。           auto:true,           //swf文件路径           swf:'~/Cont......
  • 百度WebUploader开源上传控件
    前言首先声明一下,我这个是对WebUploader开源上传控件的二次封装,底层还是WebUploader实现的,只是为了更简洁的使用他而已.下面先介绍一下WebUploader简介:WebUploader是由BaiduWebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能......
  • Progress 圆形进度条 实现
    效果图实现过程分析简要说明本文主要以TypeScript+React为例进行讲解,demo中使用到了sass,但用法相对简单,不影响理解HTMLDOM元素说明<divclassName="g-progress-wrap"><divclassName="g-progress"></div><divclassName="g-circle">......
  • WebUploader 支持 超大上G,多附件上传
    ​ 以ASP.NETCoreWebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API,包括文件的上传和下载。 准备文件上传的API #region 文件上传  可以带参数        [HttpPost("upload")]        publicJsonResultuploadProject(I......
  • Python之断点续传下载及进度显示
    Python之断点续传下载及进度显示某日,因工作需要下载大量OSGB数据,下载链接来源于一个csv文件,于是解析了csv文件然后下载。为了提高下载效率及进度显示,写了一份脚本。环境python3.7requestscsv过程解析csv废话不多说,先上代码:deffetch_download_url(source):res......
  • 文件复制(断点续传)
    rsync的目的是实现本地主机和远程主机上的文件同步(包括本地推到远程,远程拉到本地两种同步方式),也可以实现本地不同路径下文件的同步,但不能实现远程路径1到远程路径2之间的同步(scp可以实现)。注意事项:目录名后有或没有/是很不同的,非常复杂。具体参考:cp拷贝文件夹时/的用法不是所有......