webuploader 获取文件md5_webuploader 大文件分片,断点续传,以及秒传功能

本文详细介绍了使用WebUploader库进行大文件上传时,如何实现分片、断点续传和秒传功能。通过JavaScript代码展示了上传前的MD5校验,断点续传时的分块验证,以及合并上传后的处理。同时,还提供了PHP后台处理分片上传的代码示例,包括文件校验、分块检查和合并操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

js代码

/**

* Created by 西瓜哥 on 2017/8/18.

* 分片,急速秒传和断点续传

*/

$(function () {

var obj = $('#uploader-video');

var attr = utils.toJson(obj.attr('data-options'));

var $list = $("#videoList");

var video_container = $(".video-container");

var GUID = WebUploader.Base.guid();

var chunkSize = 10 * 1024 * 1024;

//注册功能一定要写在前头,否则不会生效

WebUploader.Uploader.register({

'before-send-file': 'beforeSendFile'

, "before-send": "beforeSend"

, "after-send-file": "afterSendFile"

}, {

beforeSendFile: function (file) {

var owner = this.owner,

server = this.options.server,

deferred = WebUploader.Deferred(),

obj = $list.find(' #' + file.id);

owner.md5File(file.source).fail(function () {

deferred.reject();

}).progress(function (percentage) {

obj.find('.note').text('读取文件进度' + parseInt(percentage * 100) + "%");

}).then(function (md5Value) {

obj.find('.note').text('文件验证完毕...');

file.wholeMd5 = md5Value;

$.ajax(server, {

dataType: 'json',

type: 'post',

data: {

status: "md5Check",

unique: md5Value

},

cache: false,

timeout: 1000

}).then(function (response, textStatus, jqXHR) {

if (response.exist) {

deferred.reject();

owner.skipFile(file);

obj.find('.note').remove();

obj.find('p.state').attr('title', '正在上传').html('100%');

UploadComlate(file, response);

file.uniqueFileName = md5Value;

} else {

deferred.resolve();

file.uniqueFileName = md5Value;

}

}, function (jqXHR, textStatus, errorThrown) {

deferred.resolve();

});

});

return deferred.promise();

}, beforeSend: function (block) {

//分片验证是否已传过,用于断点续传

var deferred = WebUploader.Deferred();

var server = this.options.server;

$.ajax({

type: "POST"

, url: server

, data: {

status: "chunkCheck"

, name: block.file.uniqueFileName

, chunkIndex: block.chunk

, ext: block.file.ext

, size: block.end - block.start

}

, cache: false

, timeout: 1000

, dataType: "json"

}).then(function (response, textStatus, jqXHR) {

if (response.exist) {

deferred.reject();

} else {

deferred.resolve();

}

}, function (jqXHR, textStatus, errorThrown) { //任何形式的验证失败,都触发重新上传

deferred.resolve();

});

return deferred.promise();

}, afterSendFile: function (file) {

//合并文件

var chunksTotal = 0;

if ((chunksTotal = Math.ceil(file.size / chunkSize)) >= 1) {

//合并请求

var deferred = WebUploader.Deferred();

var server = this.options.server;

$.ajax({

type: "POST"

, url: server

, data: {

status: "chunksMerge"

, name: file.uniqueFileName

, chunks: chunksTotal

, original_name: file.source.name

, ext: file.ext

, md5: file.md5value

}

, cache: false

, dataType: "json"

}).then(function (response, textStatus, jqXHR) {

deferred.resolve();

UploadComlate(file, response);

}, function (jqXHR, textStatus, errorThrown) {

deferred.reject();

});

return deferred.promise();

} else {

UploadComlate(file);

}

}

});

var uploader = WebUploader.create({

// 选完文件后,是否自动上传。

auto: true,

// swf文件路径

swf: '/static/js/plugins/webuploader/Uploader.swf',

runtimeOrder: 'html5,flash',

// 文件接收服务端。

server: attr.url,

// 选择文件的按钮。可选。

// 内部根据当前运行是创建,可能是input元素,也可能是flash.

pick: {

id: '#videoPicker',

multiple: false,

},

threads: 1,

resize: false,

compress: false,

duplicate: true,

chunked: true,

chunkSize: chunkSize,

formData: {guid: GUID},

fileNumLimit: 10,

// fileSingleSizeLimit:2*1024*1024*1024,

accept: {

title: 'Videos',

extensions: 'mp4,mkv,flv,avi,vob,mov,mpg',

mimeTypes: 'video/*'

}

});

uploader.on('fileQueued', function (file) {

video_container.hide();

var $li = $(

'

' +

'

正在计算文件特征...
' +

'

' +

'

'

'

);

$list.append($li);

});

//发送前填充数据

uploader.on('uploadBeforeSend', function (block, data) {

// block为分块数据。

// file为分块对应的file对象。

// var file = block.file;

// var fileMd5 = file.wholeMd5;

// 修改data可以控制发送哪些携带数据。

// console.info("fileName= " + file.name + " fileMd5= " + fileMd5 + " fileId= " + file.id);

// 将存在file对象中的md5数据携带发送过去。

data.md5value = block.file.wholeMd5;//md5

//唯一标识符,用作断点续传

data.uniqueFileName = block.file.uniqueFileName;

if (block.chunks > 1) {

data.isChunked = true;

} else {

data.isChunked = false;

}

});

//前一个文件未传完,不能再添加文件

uploader.on('beforeFileQueued', function () {

if (obj.hasClass('disabled')) {

utils.fail('请等待上一个文件传完!');

return false;

}

});

//开始上传做一个标记

uploader.on('startUpload', function () {

obj.addClass('disabled');

});

uploader.on('uploadProgress', function (file, percentage) {

var $li = $list.find(' #' + file.id),

$percent = $li.find('.progress .progress-bar');

// 避免重复创建

if (!$percent.length) {

$percent = $('

' +

'

' +

'

' +

'

').appendTo($li).find('.progress-bar');

}

$li.find(".note").remove();

$li.find('p.state').attr('title', '正在上传').html(parseInt(percentage * 100) + '%');

$percent.css('width', percentage * 100 + '%');

});

uploader.on('uploadError', function () {

utils.fail('文件上传失败');

});

//删除标记和进度条

uploader.on('uploadComplete', function (file) {

$('#' + file.id).find('.progress').fadeOut();

obj.removeClass('disabled');

$list.html('');

});

uploader.on("error", function (type, handler) {

if (type === "Q_TYPE_DENIED") {

utils.fail('上传文件格式不符合要求');

} else if (type === "F_EXCEED_SIZE") {

utils.fail('上传文件超过限制');

}

});

function UploadComlate(file, response) {

utils.success('上传成功');

uploader.reset();

$list.find('.item').remove();

video_container.show();

if (response.state) {

video_container.find('span').html(file.source.name);

video_container.find('input').val(response.url);

} else {

video_container.find('span').html(file.source.name);

video_container.find('input').val( response.data.file_path);

}

}

});

php部分代码:

public function batch(Request $request)

{

if ($request->isMethod('post')) {

$action = request()->get('status');

switch ($action) {

case "md5Check":

$file = $this->checkFile();

if ($file) {

return ["exist" => 1, "data" => $file];

} else {

return ["exist" => 0];

}

break;

case "chunkCheck":

$this->upload = new Upload();

$this->upload->chunkCheck();

return $this->upload->info();

break;

case "chunksMerge":

$this->upload = new Upload();

$this->upload->type = 'batch';

$this->upload->public = false;

$this->upload->user = $this->service->setUser();

$this->upload->chunksMerge();

return $this->upload->info();

break;

default:

$this->upload = new Upload();

$this->upload->chunkUpload();

return $this->upload->info();

}

}

}

public function checkFile()

{

if (request()->isMethod('post')) {

$md5 = request()->get('unique');

return $this->service->checkFile($md5);

}

}

uploader 类

namespace App\Tools\Upload;useIlluminate\Support\Facades\Event;useIntervention\Image\Facades\Image;useStorage;useApp\Events\UserUploadImage;useApp\Events\UserUploadAttach;useApp\Events\Logger;use\App\Jobs\OSSQueue;classUpload

{private $public = true;private $type;private $water;private $info;private $img;private $original_name;private $original_path;private $thumb_image;private $ext;private $attachType = 'thumb';private $mimetype;private $user;private $size;private $image_exts = ["png", "jpg", "jpeg", "gif", "bmp"];private $video_exts = ["flv", "swf", "mkv", "avi", "rm", "rmvb", "mpeg", "mpg", "ogg", "ogv", "mov", "wmv", "mp4", "webm", "mp3", "wav", "mid"];private $fileField = 'file';public function __construct($type = 'images', $water = false)

{$this->type = $type;$this->water = $water;

}public function __set($name, $value)

{$this->$name = $value;

}public function __get($name)

{return $this->$name;

}public functioninfo()

{return $this->info;

}public functionupload()

{$file = request()->file($this->fileField);if ($file->isValid()) {if ($this->type == 'images') {$allow_exts = explode(',', config('system.images_extensions'));$max_size = config('system.max_images_size') * 1024;

}elseif ($this->type == 'video') {$allow_exts = explode(',', config('system.video_extensions'));$max_size = config('system.max_video_size') * 1024;

}else{$allow_exts = explode(',', config('system.attach_extensions'));$max_size = config('system.max_attach_size') * 1024;

}$this->ext = $file->getClientOriginalExtension();$this->size = $file->getClientSize();//批量上传

if ($this->type == 'batch') {$flag = false;if (in_array(strtolower($this->ext), $this->image_exts)) {$this->type = 'images';$this->attachType = 'depot';$flag = true;

}if (in_array(strtolower($this->ext), $this->video_exts)) {$this->type = 'video';$this->attachType = 'video';$flag = true;

}if ($flag == false) {$this->info = ['state' => '未知的上传类型'];return;

}

}else{if (!in_array(strtolower($this->ext), $allow_exts)) {$this->info = ['state' => '不允许上传的类型'];return;

}if ($this->size > $max_size) {$this->info = ['state' => '上传文件大小超过限制'];return;

}

}$this->original_name = $file->getClientOriginalName();$realPath = $file->getRealPath();$this->mimetype = $file->getClientMimeType();if ($this->attachType == 'agreement') {$path = upload_path() . '/agreements/' . date('Y-m-d');

}else{$path = upload_path() . '/' . $this->type . '/' . date('Y-m-d');

}if (!is_dir(public_path($path))) {

@mkdir(public_path($path), 0777, true);

}$small_thumb = '';$oss_file = '';if ($this->type == 'images') {if ($this->public == false) {$filename = $file->store($path);if (!is_file(storage_path('app/' . $filename))) {$this->info = ['state' => '文件上传失败,请确保storage目录可写'];return;

}

}else{$filename = $path . '/' . md5(uniqid()) . '.' . $this->ext;

Storage::disk('uploads')->put($filename, file_get_contents($realPath));if (!is_file(public_path($filename))) {$this->info = ['state' => '文件上传失败,请确保uploads目录可写'];return;

}

}$this->thumb_image = $this->thumb($filename);$small_thumb = '/' . setSmallImg($filename);$oss_file = '/' . setOSSImg($filename);$this->original_path = $filename;$this->setImagesInfo();$images = Event::fire(new UserUploadImage($this->user))[0];$link = '/images/' . $images->name;$newName = $images->name;$this->user->message = '上传了图片:' . $filename;

}else if ($this->type == 'video') {if ($this->public == false) {$filename = $file->store($path);if (!is_file(storage_path('app/' . $filename))) {$this->info = ['state' => '文件上传失败,请确保storage目录可写'];return;

}

}else{$filename = $path . '/' . md5(uniqid()) . '.' . $this->ext;

Storage::disk('uploads')->put($filename, file_get_contents($realPath));if (!is_file(public_path($filename))) {$this->info = ['state' => '文件上传失败,请确保uploads目录可写'];return;

}

}$this->original_path = $filename;$this->setAttachInfo();$video = Event::fire(new UserUploadAttach($this->user))[0];$link = '/video/' . $video->name;$newName = $filename;$this->user->message = '上传了视频:' . $filename;

}else if ($this->type == 'attach') {if ($this->public == false) {$filename = $file->store($path);if (!is_file(storage_path('app/' . $filename))) {$this->info = ['state' => '文件上传失败,请确保storage目录可写'];return;

}

}else{$filename = $path . '/' . md5(uniqid()) . '.' . $this->ext;

Storage::disk('uploads')->put($filename, file_get_contents($realPath));if (!is_file(public_path($filename))) {$this->info = ['state' => '文件上传失败,请确保uploads目录可写'];return;

}

}$this->original_path = $filename;$this->setAttachInfo();$video = Event::fire(new UserUploadAttach($this->user))[0];$link = '/video/' . $video->name;$newName = $filename;$this->user->message = '上传了附件:' . $filename;

}else{$filename = $path . '/' . md5(uniqid()) . '.' . $this->ext;

Storage::disk('uploads')->put($filename, file_get_contents($realPath));if (!is_file(public_path($filename))) {$this->info = ['state' => '文件上传失败,请确保uploads目录可写'];return;

}$this->original_path = $filename;$link = '/' . $filename;$newName = '';$this->user->message = '上传了附件:' . $filename;

}

Event::fire(new Logger($this->user));//上传原图原附件到阿里云OSS

if ($this->public == false) {

dispatch((new OSSQueue($filename, false, $oss_file))->onQueue('high'));

}$this->info =['state' => 'SUCCESS',

'originalName' => $this->original_name,

'ext' => $this->ext,

'small' => $small_thumb,

'oss_file' => $oss_file,

'type' => $this->type,

'mime' => $this->mimetype,

'size' => $this->size,

'newName' => $newName, //链接形式访问 文件名称

'link' => $link, //链接形式访问地址

'url' => '/' . $filename, //文件存放路径

];return;

}else{$this->info = ['state' => '文件上传失败'];return;

}

}public functionchunkCheck()

{$dir_name = request()->get('name');$chunkIndex = request()->get('chunkIndex');$size = request()->get('size');if (!is_dir(storage_path('chunk_temp_files/' . $dir_name))) {

Storage::disk('storage')->makeDirectory('chunk_temp_files/' . $dir_name);

}$chunk_file = storage_path('chunk_temp_files/' . $dir_name . '/' . $chunkIndex . '.tmp');if (file_exists($chunk_file)) {if (filesize($chunk_file) == $size) {$this->info = ['exist' => 1];return;

}

}$this->info = ['exist' => 0];return;

}public functionchunkUpload()

{$file = request()->file('file');$isChunked = request()->get('isChunked');$chunk = request()->get('chunk');$chunks = request()->get('chunks');$uniqueFileName = request()->get('uniqueFileName');if ($file->isValid()) {$this->ext = $file->getClientOriginalExtension();$this->original_name = $file->getClientOriginalName();$this->mimetype = $file->getClientMimeType();$this->size = $file->getClientSize();$flag = false;$this->image_exts = explode(',', config('system.images_extensions'));$this->video_exts = explode(',', config('system.video_extensions'));if (in_array(strtolower($this->ext), $this->image_exts)) {$flag = true;

}if (in_array(strtolower($this->ext), $this->video_exts)) {$flag = true;

}if ($flag == false) {$this->info = ['chunked' => false, 'state' => '不允许的上传类型'];return;

}$realPath = $file->getRealPath();if ($isChunked=='true') {

Storage::disk('storage')->put('chunk_temp_files/' . $uniqueFileName . '/' . $chunk . '.tmp', file_get_contents($realPath));if ($chunks == ($chunk + 1)) {$this->info = ['chunked' => true, 'state' => 'SUCCESS', 'ext' => $this->ext, 'original' => $this->original_name];

}else{$this->info = ['chunked' => true, 'state' => 'chunked'];

}

}else{

Storage::disk('storage')->put('chunk_temp_files/' . $uniqueFileName . '/tmp.tmp', file_get_contents($realPath));$this->info = ['chunked' => true, 'state' => 'SUCCESS', 'ext' => $this->ext, 'original' => $this->original_name];

}return;

}else{$this->info = ['chunked' => false, 'state' => '文件上传失败'];return;

}

}public functionchunksMerge()

{$store = request()->all();$this->ext = $store['ext'];$dir_name = $store['name'];$chunks = $store['chunks'];$this->original_name = $store['original_name'];if (in_array(strtolower($this->ext), $this->image_exts)) {$this->type = 'images';$this->attachType = 'depot';

}elseif (in_array(strtolower($this->ext), $this->video_exts)) {$this->type = 'video';$this->attachType = 'video';

}else{$this->type = 'attach';$this->attachType = 'attach';

}$path = upload_path() . '/' . $this->type . '/' . date('Y-m-d');if (!is_dir(storage_path('app/' . $path))) {

Storage::makeDirectory($path);

}$filename = $path . '/' .$dir_name. '.' . $this->ext;$files = Storage::disk('storage')->files('chunk_temp_files/' . $dir_name);if (count($files) == $chunks) {$arr=array();foreach ($files as $value)

{$arr[filemtime(storage_path($value))]=$value;

}//根据修改时间对文件排序

ksort($arr);$fp = fopen(storage_path('app/') . $filename, "ab");foreach ($arr as $file) {$tempFile = storage_path($file);$handle = fopen($tempFile, "rb");fwrite($fp, fread($handle, filesize($tempFile)));fclose($handle);unset($handle);

}fclose($fp);

Storage::disk('storage')->deleteDirectory('chunk_temp_files/' . $dir_name);$this->mimetype = Storage::disk('local')->mimeType($filename);$this->size = Storage::disk('local')->size($filename);$small_thumb = '';$oss_file = '';if ($this->type == 'images') {if (!is_dir(public_path($path))) {

Storage::disk('uploads')->makeDirectory($path);

}$this->thumb_image = $this->thumb($filename);$small_thumb = '/' . setSmallImg($filename);$oss_file = '/' . setOSSImg($filename);$this->original_path = $filename;$this->setImagesInfo();$images = Event::fire(new UserUploadImage($this->user))[0];$link = '/images/' . $images->name;$newName = $images->name;$this->user->message = '上传了图片:' . $filename;

dispatch((new OSSQueue($filename, false, $oss_file))->onQueue('high'));

}if ($this->type == 'video') {$this->original_path = $filename;$this->setAttachInfo();$video = Event::fire(new UserUploadAttach($this->user))[0];$link = '/videos/' . $video->name;$newName = $filename;$this->user->message = '上传了视频:' . $filename;

dispatch((new OSSQueue($filename))->onQueue('low'));

}//上传加入队列 控制台需要运行队列进程 php artisan queue:work

// dispatch(new OSSQueue($filename));

Event::fire(new Logger($this->user));$this->info =['state' => 'SUCCESS',

'originalName' => $this->original_name,

'ext' => $this->ext,

'small' => $small_thumb,

'oss_file' => $oss_file,

'type' => $this->type,

'mime' => $this->mimetype,

'size' => $this->size,

'newName' => $newName, //链接形式访问 文件名称

'link' => $link, //链接形式访问地址

'url' => '/' . $filename, //文件存放路径

];return;

}

}private functionsetImagesInfo()

{$this->user->public = $this->public;$this->user->image_type = $this->attachType;$this->user->mime = $this->mimetype;$this->user->original_name = $this->original_name;$this->user->ext = $this->ext;$this->user->thumb_image = $this->thumb_image;$this->user->original_image = $this->original_path;

}private functionsetAttachInfo()

{$this->user->public = $this->public;$this->user->attach_type = $this->attachType;$this->user->mime = $this->mimetype;$this->user->original_name = $this->original_name;$this->user->ext = $this->ext;//$this->user->thumb_image = $this->thumb_image;

$this->user->original_path = $this->original_path;

}private function thumb($filename)

{if ($this->type == 'images') {$temp = explode('.', $filename);$ext = $temp[count($temp) - 1] ?: 'jpg';$width = config('system.images_max_width') ?: 500;$height = config('system.images_max_height') ?: 500;$file = $this->public ? public_path($filename) : storage_path('app/' . $filename);$this->img = Image::make($file);$this->resizeByWidth(360);if (!is_dir(public_path(dirname(setSmallImg($filename))))) {

@mkdir(public_path(dirname(setSmallImg($filename))), 0777, true);

}$this->img->save(public_path(setSmallImg($filename)));$this->img = Image::make($file);if ($this->img->width() > $this->img->height()) {if ($this->img->width() > $width) {$this->resizeByWidth($width);

}

}else{if ($this->img->height() > $height) {$this->resizeByHeight($height);

}

}if ($this->water) {$this->water();$this->img->save(public_path($filename), 60);

}else{$this->img->save(public_path($filename), 90);

}return $filename;

}else{return '';

}

}private function resizeByWidth($width)

{$this->img = $this->img->resize($width, null, function ($constraint) {$constraint->aspectRatio();

});

}private function resizeByHeight($height)

{$this->img = $this->img->resize(null, $height, function ($constraint) {$constraint->aspectRatio();

});

}private functionwater()

{if ($this->water) {if (file_exists(public_path(config('system.images_water')))) {$this->img->insert(public_path(config('system.images_water')), 'center');

}else{$this->img->insert(resource_path('logo.png'), 'center');

}

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值