前段时间做视频上传业务,通过网页上传视频到服务器。

视频大小 小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1,文件过大,超出服务端的请求大小限制;2,请求时间过长,请求超时;3,传输中断,必须重新上传导致前功尽弃;

解决方案:

1,修改服务端上传的限制配置;Nginx 以及 PHP 的上传文件限制 不宜过大,一般5M 左右为好;

2,大文件分片,一片一片的传到服务端,再由服务端合并。这么做的好处在于一旦上传失败只是损失一个分片而已,不用整个文件重传,而且每个分片的大小可以控制在4MB以内,服务端限制在4M即可。

前端

Web前端可使用HttpUploader6的大文件上传控件6;官网地址:http://t.cn/EyI6vHh

<div class="section section6 section5">

<div class="part1"><a href="javascript:;" target="_blank" class="part1__btn">批量删除</a><span class="part1__txt"><em class="part1__num" id="upload_num">0</em>个视频,共 <em class="part1__num"id="upload_size">0M</em></span></div>

<table class="section5__table">

<tbody id="thelist">

<tr class="thead">

<th class="col1 allCkeck"><input type="checkbox" name="" class="col1__checkBox"/>视频名称</th><th class="col2">视频大小</th><th class="col3">视频分类</th><th class="col4">状态</th><th class="col5">进度</th><th>操作</th>

</tr>

</tbody>

</table>

<div class="selFile" id="selFile">

<div id="drag_tips">

<div id="btns__add2"></div>

<h2 class="txt1">选择视频文件</h2>

<span class="txt2">或直接将文件拖拽至此窗口</span>

</div>

</div>

<div class="btns"><span class="btns__add" id="btns__add">+添加视频文件</span><span class="btns__upload btns__upload-start" id="uploadBtn"><i class="btns__upload_icon"></i>开始上传视频</span></div>

</div>

//引入插件

<script type="text/javascript" src="media/js/lib/webuploader/js/webuploader.min.js"></script>

upload.js

1// 文件上传

2 jQuery(function() {

3     var $ = jQuery,

4         $list = $('#thelist'),

5         $btn = $('#upload-start'),

6         $thead = $('.thead'),

7         $part_btn = $('.part1__btn'), //批量上传按钮

8         state = 'pending',

9         fileCount = 0, //上传文件总数

10         fileSize = 0,//上传文件的总大小

11     // 上传按钮

12         $upload = $('#uploadBtn'),

13     // 所有文件的进度信息,key为file id

14         percentages = {},

15     // 所有文件的md5,key为file id

16         md5Obj = {},

17     // 可能有pedding, ready, uploading, confirm, done.

18         state = 'pedding',

19         uploader;

20

21     //浏览器关闭提醒

22     window.is_confirm = false;

23     $(window).bind('beforeunload', function(){

24         // 只有在标识变量is_confirm不为false时,才弹出确认提示

25         if(window.is_confirm !== false)

26             return '正在上传视频,该操作将丢失视频,是否继续?';

27     })

28

29     if ( !WebUploader.Uploader.support() ) {

30         alert( 'Web Uploader 不支持您的浏览器!如果你使用的是IE浏览器,请尝试升级浏览器');

31         thrownew Error( 'WebUploader does not support the browser you are using.' );

32     }

33

34     $(".pop2 .btns__sure").click(function(){

35         $('.popup,.pop').hide();

36     });

37

38     uploader = WebUploader.create({

39         //拖拽容器

40         dnd:'#selFile',

41

42         // 不压缩image

43         resize: false,

44

45         // swf文件路径

46         swf: '/media/js/lib/webuploader/js/Uploader.swf',

47

48         // 文件接收服务端。

49         server: '/service/upload/upload_file',

50         //server:'http://vod.test.4399sy.com/service/upload/ssl_upload_file',

51         formData: {

52             file_id: 'file',

53             guid:new Date().getTime() + Math.ceil(Math.random()*100),

54             file_name:''

55         },

56

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

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

59         pick: {

60             id:'#btns__add',

61             innerHTML:"+添加视频文件"

62         },

63

64         // 开起分片上传。

65         chunked: true,

66

67         //如果要分片,分多大一片2M

68         chunkSize:2*1024*1024,

69

70         //上传文件的类型

71         accept:{

72             title: 'Videos',

73             extensions: 'mp4,avi,flv',

74             mimeTypes: 'video/*'

75         },

76         //验证文件总数量, 超出则不允许加入队列。

77         fileNumLimit: 10,

78         //单个文件上传的大小限制 2G

79         fileSingleSizeLimit:2*1024*1024*1024,

80

81     });

82

83     //添加文件具体函数

84     function addFile( file ){

85         var data = new Date(),

86             month = (data.getMonth()+1)<10 ? '0'+(data.getMonth()+1) : (data.getMonth()+1),

87             day = data.getDate()<10 ? '0'+ data.getDate(): data.getDate(),

88             time = data.getFullYear() + "-" + month + "-" + day,

89             $tr = $('<tr class="toBeUploaded" id="'+file.id+'"></tr>'),

90             $td = $('<td class="col1"><input type="checkbox" name="" class="col1__checkBox"/><input type="text" value="'+ file.name +'" name="" class="name"/></td><td class="col2">'+convert_size(file.size)+'</td><td class="col3"><select class="class_id">'+ class_options +'</select></td><td class="col4">读取视频中</td><td class="col5">0%</td><td class="col6"><ul><li class="view"><a target="_blank" href="javascript:;">查看</a></li><li class="delete">删除</li></ul></td>').appendTo($tr),

91             $state = $tr.find('td.col4'),

92             $prgress = $tr.find('td.col5'),

93             $delbtn = $tr.find('li.delete');

94

95         $("#selFile").hide();

96

97         if ( file.getStatus() === 'invalid' ) {

98             switch( file.statusText ) {

99                 case 'exceed_size':

100                     text = '文件大小超出';

101                     break;

102

103                 case 'interrupt':

104                    text = '上传暂停';

105                     break;

106

107                 default:

108                     text = '上传失败,请重试';

109                     break;

110             }

111             showError(text);

112         } else {

113             // @todo lazyload

114             percentages[ file.id ] = [ file.size, 0 ];

115             file.rotation = 0;

116         }

117

118         file.on('statuschange', function( cur, prev ) {

119             if ( prev === 'progress' ) {

120                 //上传成功

121             } elseif ( prev === 'queued' ) {

122                 // 开始上传

123             }

124

125             // 成功

126             if ( cur === 'error' || cur === 'invalid' ) {

127                 console.log( file.statusText );

128                 showError( file.statusText );

129                 percentages[ file.id ][ 1 ] = 1;

130             } elseif ( cur === 'interrupt' ) {

131                 showError( 'interrupt' );

132             } elseif ( cur === 'queued' ) {

133                 percentages[ file.id ][ 1 ] = 0;

134             } elseif ( cur === 'progress' ) {

135             //   正在上传

136

137             } elseif ( cur === 'complete' ) {

138             //   上传完成

139

140             }

141

142             $tr.removeClass( 'state-' + prev ).addClass( 'state-' + cur );

143         });

144         $delbtn.on('click',function(){

145             uploader.removeFile( file );

146         });

147         $tr.appendTo($list);

148         //$tr.insertAfter($thead);

149     }

150

151     // 负责view的销毁

152     function removeFile( file ) {

153         var $tr = $('#'+file.id);

154

155         delete percentages[ file.id ];

156         $tr.off().find('.col6').off().end().remove();

157     }

158

159     function setState( val ) {

160         var file, stats;

161

162         if ( val === state ) {

163             return;

164         }

165

166         $upload.removeClass( 'state-' + state );

167         $upload.addClass( 'state-' + val );

168         state = val;

169

170         switch ( state ) {

171             case 'pedding':

172                 uploader.refresh();

173                 break;

174

175             case 'ready':

176                 uploader.refresh();

177                 break;

178

179             case 'uploading':

180                 $upload.text( '暂停上传' );

181                 break;

182             case 'paused':

183                 $upload.text( '继续上传' );

184                 break;

185

186             case 'confirm':

187                 //$progress.hide();

188                $upload.text( '开始上传' ).addClass( 'disabled' );

189

190                 stats = uploader.getStats();

191                 if ( stats.successNum && !stats.uploadFailNum ) {

192                     setState( 'finish' );

193                     return;

194                 }

195                 break;

196             case 'finish':

197                 stats = uploader.getStats();

198                 if ( stats.successNum ) {

199                     alert( '上传成功' );

200                 } else {

201                     // 没有成功的图片,重设

202                     state = 'done';

203                     location.reload();

204                 }

205                 break;

206         }

207     }

208

209

210     // 当有文件添加进来的时候

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

212         fileCount++;

213         fileSize += file.size;

214         $("#upload_num").text(fileCount);

215         $("#upload_size").text(convert_size(fileSize));

216         md5Obj[ file.id ] = '';

217         //获取文件MD5 值

218         uploader.md5File( file )

219             // 及时显示进度

220             .progress(function(percentage) {

221                 $( '#'+file.id ).find('.col4').text('读取文件'+parseInt(percentage*100)+"%");

222             })

223             // 完成

224             .then(function(val) {

225             console.log('md5 result:', val);

226             md5Obj[ file.id ] = val;

227             $( '#'+file.id ).find('.col4').text('待上传');

228             setState( 'ready' );

229         });

230         addFile( file );

231     });

232

233     // 删除文件

234     uploader.onFileDequeued = function( file ) {

235         fileCount--;

236         fileSize -= file.size;

237         $("#upload_num").text(fileCount);

238         $("#upload_size").text(convert_size(fileSize));

239         if ( !fileCount ) {

240             setState( 'pedding' );

241         }

242         removeFile( file );

243

244     };

245

246     // 添加“添加文件”的按钮,

247     uploader.addButton({

248         id: '#btns__add2',

249         label: ''

250     });

251

252     // 文件上传过程中创建进度实时显示。

253     uploader.onUploadProgress = function( file, percentage ) {

254         var $tr = $('#'+file.id),

255             $percent = $tr.find('td.col5'),

256             $state = $tr.find('td.col4');

257         percentage = parseInt(percentage*100);

258         if(! (percentage == 0 && percentage == 100)){

259             $state.text("正在上传");

260         }

261         $percent.text( percentage + "%")

262         percentages[ file.id ][ 1 ] = percentage;

263     };

264

265     //上传前,请求服务端 判断文件是否已经上传过

266     uploader.on( 'uploadStart', function( file ) {

267         var type = 'POST';

268         var url = '/service/upload/determine_video_exist';

269         var request_data = {

270             'md5': md5Obj[ file.id ],

271             'type':1

272         };

273         var success = function(r) {

274             uploader.upload( file );

275             console.log(r);

276             if(r.code == 1) {

277                 uploader.skipFile( file );

278                 $( '#'+file.id ).find('.col4').text('视频已存在');

279                 $( '#'+file.id ).find('.col5').text('100%');

280                 $('#'+file.id).find('.view').find('a').attr('href',playmain +'/?video_id='+ r.data.video_id);

281                 $('.pop2 .video_game').text("所在游戏:"+r.data.game_name);

282                 $('.pop2 .create_time').text("上传时间:"+r.data.create_time);

283                 $('.pop').hide();

284                 $('.pop2').show();

285                 $('.popup').show();

286             }elseif(r.code <= 0) {

287                 showError(r.msg);

288             }else {

289

290             }

291         };

292         request(type, url, request_data, success);

293     });

294

295     //当某个文件的分块在发送前触发,主要用来询问是否要添加附带参数,大文件在开起分片上传的前提下此事件可能会触发多次。

296     uploader.on('uploadBeforeSend', function (obj, data, headers) {

297         $tr = $("#"+data.id);

298         var file_name = $tr.find(".name").val();

299         var class_id = $tr.find("select.class_id").val();

300         var reg = /[1-9][0-9]*/g;

301         data.md5 = md5Obj[ obj.file.id ];

302         data.file_name = file_name;

303         data.class_id = class_id;

304         data.guid = data.guid + data.id.replace(/[^0-9]+/g, '');

305     });

306

307     uploader.on( 'uploadSuccess', function( file ,res) {

308         if(res.code == 1){

309             $( '#'+file.id ).find('.col4').text('成功上传');

310             console.log(res);

311             $('#'+file.id).find('.view').find('a').attr('href',playmain +'/?video_id='+ res.data.video_id);

312         }elseif(res.code == 2) {

313             $( '#'+file.id ).find('.col4').text('视频已存在');

314             console.log(res);

315             $('#'+file.id).find('.view').find('a').attr('href',playmain +'/?video_id='+ res.data.video_id);

316         }else {

317             showError(res.msg);

318         }

319     });

320

321     uploader.on( 'uploadError', function( file,reason ) {

322         $( '#'+file.id ).find('.col4').text('上传失败');

323         console.log(reason);

324     });

325

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

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

328     });

329

330     uploader.on( 'all', function( type ) {

331         if ( type === 'startUpload' ) {

332             state = 'uploading';

333         } elseif ( type === 'stopUpload' ) {

334             state = 'paused';

335         } elseif ( type === 'uploadFinished' ) {

336             state = 'done';

337         }

338

339         if ( state === 'uploading' ) {

340             window.is_confirm = true;

341             $('.toBeUploaded').addClass("uploaded").removeClass("toBeUploaded");

342             $('input.name').attr("disabled","disabled");

343             $('input.col1__checkBox').hide();

344             $('input').attr("disabled","disabled");

345             $('select.class_id').attr("disabled","disabled");

346             $('.btns__add').remove();

347             $upload.addClass("btns__upload-ing").removeClass("btns__upload-start").html('<i class="btns__upload_icon"></i>正在上传视频');

348

349         } elseif(state === 'done') {

350             window.is_confirm = false;

351             console.log("上传完成");

352             $upload.addClass("btns__upload-start btns__upload-refresh").removeClass("btns__upload-ing").html('<i class="btns__upload_icon"></i>开始上传视频');

353         }

354     });

355

356     /**

357     * 验证文件格式以及文件大小

358      */

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

360         var msg = ''

361         switch (type){

362             case "Q_TYPE_DENIED": msg = "请上传mp4格式文件";break;

363             case "F_EXCEED_SIZE": msg = "文件大小不能超过1G";break;

364             case "Q_EXCEED_NUM_LIMIT" : msg = "一次最多能上传10个文件";break;

365             default: msg='';

366         }

367         if(msg != ''){

368             showError(msg);

369         }

370     });

371

372     $part_btn.on('click',function(){

373         $('td .col1__checkBox').each(function(){

374             if($(this).is(':checked')){

375                 var $tr = $(this).parents('tr');

376                 var id = $tr.attr('id');

377                 uploader.removeFile( id );

378             }

379         });

380     });

381     $upload.on('click', function() {

382         var isbreak = false;

383         $(".name").each(function(){

384             if(!$(this).val()|| $(this).val() == ''){

385                 isbreak = true;

386             }

387         })

388         if(isbreak){

389             showError("文件名不能存在为空");

390             return;

391         }

392         $("select.class_id").each(function(){

393             if(!$(this).val()|| $(this).val() == ''){

394                 isbreak = true;

395             }

396         })

397         if(isbreak){

398             showError("分类不能为空,请先添加分类");

399             return;

400         }

401         if ( $(this).hasClass( 'btns__upload-refresh' ) ) {

402             location.reload();

403         }

404         if ( $(this).hasClass( 'btns__upload-ing' ) ) {

405             returnfalse;

406         }

407         var md5Ready = true;

408         $.each(md5Obj,function(index,item){

409             if(!item || item==''){

410                 md5Ready = false;

411             }

412         });

413         if(!md5Ready){

414             showError('文件尚未读取完成,请耐心等待');

415             returnfalse;

416         }

417         if ( state === 'ready' && md5Ready ) {

418             uploader.upload();

419         } elseif ( state === 'paused' ) {

420             uploader.upload();

421         } elseif ( state === 'uploading' ) {

422             uploader.stop();

423         }

424     });

425     $upload.addClass( 'state-' + state );

426

427 });

后台(PHP)【仅分片上传相关代码】

1     publicfunction action_upload_file(){

2         $file_id = R::string('file_id', 'file');

3         $keepFileName = R::string('keepFileName', 0);

4         $unsize_change = R::numeric('unsize_change',0);

5         $id = R::string('id');   //插件每上传一个视频自带id

6         $guid = R::string('guid');  //标识视频

7         $chunks = R::numeric('chunks');  // 分片数

8         $chunk = R::numeric('chunk');  //分片号

9         $file_name = R::string('file_name');

10         $file = isset($_FILES[$file_id])?$_FILES[$file_id]:'';

11         $md5 = R::string('md5');

12         $this->upload = new Common_Upload();

13

14         if(empty($guid) || empty($file_name) || empty($md5)){

15             $this->response_msg(-1, 'guid 或 file_name 或 md5 不能为空');

16             return;

17         }

18

19         if(empty($file['name'])){

20             $this->response_msg(-1, '请上传一个文件');

21             return;

22         }else{

23             if($chunks){

24                 $res = $this->upload->saveFile_chunks($file,$chunks, $chunk, $guid);

25                 if(empty($res)){

26                     $this->response_msg(-2, '分片上传失败');

27                     return;

28                 }

29

30             }elseif($keepFileName){

31                 $res = $this->upload->saveFile_nochunks($file, '', '', $keepFileName);

32             }else{

33                 $res = $this->upload->saveFile_nochunks($file);

34             }

35             if(empty($res)){

36                 $err = $this->upload->getError();

37                 $this->response_msg(-3, '上传文件出错!msg:'.print_r($err, true));

38                 return;

39             }

40             if($unsize_change){

41                 $size = $res['size'];

42             }else{

43                 $size = $this->convert_size($res['size']);

44             }

45

46             //视频上传完成

47             if($chunks && $res['last_chunk']){

48                 $domain = Kohana::$config->load('domain');

49                 $video_domain = $domain[RUN_MOD]['VIDEO'];

50

51                 if(!empty($file_name)){

52                     $res['name'] = $file_name;

53                 }

54                 $video_data = array(

55                     'video_name'=> $file_name,

56                     'video_url'=> $video_domain."/".$res['path'],

57                     'size'=>$res['size'],

58                     'create_time'=> date('y-m-d H:i:s',time()),

59                     'update_time'=> date('y-m-d H:i:s',time()),

60                     'duration'=> $res['time'],

61                     'md5'=>$md5

62                 );

63                 $video_mod = new Model_Videoinfo();

64                 $video = $video_mod->save_video($video_data,$guid);

65                 $res = array(

66                     'path'=>$res['path'],

67                     'chunks'=>$chunks,

68                     'chunk'=>$chunk,

69                     'size'=>$size,

70                     'guid'=> $guid,

71                     'video_id'=>$video[0],

72                     'file'=>$file,

73                     'id'=>$id

74                 );

75                 $this->response_msg(1,'视频上传成功',$res);

76                 return;

77             }

78             //非分片上传

79             if(!$chunks){

80                 $domain = Kohana::$config->load('domain');

81                 $video_domain = $domain[RUN_MOD]['VIDEO'];

82                 if(!empty($file_name)){

83                     $res['name'] = $file_name;

84                 }

85                 $video_data = array(

86                     'video_name'=> $file_name,

87                     'video_url'=> $video_domain."/".$res['path'],

88                     'size'=>$res['size'],

89                     'create_time'=> date('y-m-d H:i:s',time()),

90                     'update_time'=> date('y-m-d H:i:s',time()),

91                     'duration'=> $res['time'],

92                     'md5'=>$md5

93                 );

94                 $video_mod = new Model_Videoinfo();

95                 $video = $video_mod->save_video($video_data,$guid);

96                 if(empty($video)){

97                     $this->response_msg(-6, '视频信息保存失败');

98                     return;

99                 }

100                 $res = array(

101                     'path'=>$res['path'],

102                     'video_data'=>$video_data,

103                     'size'=>$size,

104                     'guid'=> $guid,

105                     'video_id'=>$video[0],

106                     'file'=>$file,

107                     'id'=>$id

108                 );

109                 $this->response_msg(1,'视频上传成功',$res);

110                 return;

111             }

112             //分片上传成功(未全部分片上传完成)

113             $res = array(

114                 'chunks'=>$chunks,

115                 'chunk'=>$chunk,

116             );

117             $this->response_msg(2, '分片上传成功',$res);

118         }

119     }

1     /**

2     * 保存分片文件(注意先验证文件是否合法)

3     *

4     * @param array $file 单个文件

5     * @param string $attachdir 上传文件路径

6     * @param string $upload_type 上传文件类型

7     * @param bool $keepFileName 是否保持文件名,默认不不保持

8     * @return bool

9      */

10     publicfunction saveFile_chunks($file,$chunks, $chunk, $guid)

11     {

12         if(empty($guid) || empty($file) ){

13             returnfalse;

14         }

15         $file_name = (string)$guid . $chunk;

16         //保存分片文件

17         $file_info = $this->saveFile($file, '', '', false, $file_name,true);

18         if ($file_info) {

19             $cache = Cache::instance('memcache');

20             //记录已上传的分片编号,上传顺序并不是按编号顺序进行上传

21             $chunks_list_pre = $cache->get($guid);

22             if(empty($chunks_list_pre)){

23                 $strarr = array();

24                 for($i=0;$i<$chunks;$i++){

25                     $strarr[] = $guid.$i;

26                 }

27                 $cache->set($guid,$strarr,60 * 60 * 24);

28             }

29             $file_path = $cache->set($guid.$chunk,$file_info['path'],60 * 60 * 24);

30

31             $chunk_path_array= array();

32             for($i=0;$i<$chunks;$i++){

33                 if($cache->get($guid.$i)){

34                     $chunk_path_array[$i] = $cache->get($guid.$i);

35                 }

36             }

37             list($Y,$M,$D,$H,$I,$S) = explode('-',date("Y-m-d-H-i-s", time()));

38             $file_info['chunks_path_count'] = count($chunk_path_array);

39             $file_info['last_chunk'] = false;

40             if (count($chunk_path_array) == $chunks) {

41                 //按目录类型存储

42                 $dirType = substr($file_info['type'], 1, strlen($file_info['type']));;

43                 //目录类型前面加上前缀url

44                 $dirType = $this->pre_url.$dirType;

45                 //按年月二级存储

46                 $month_file_path = $Y.'/'.$M;

47                 $saveName ='upload/mp4/'.$month_file_path.'/original/'.$guid.$file_info['type'];

48                 $join_file_name =$this->attachDIR.$saveName;

49                 if(!is_dir($this->attachDIR.'upload/mp4/'.$month_file_path.'/original/')){

50                     mkdir($this->attachDIR.'upload/mp4/'.$month_file_path.'/original/',0755,true);

51                 }

52                 if(! file_exists($join_file_name)){

53                     $fp = fopen($join_file_name, "ab");

54                     //合并过程中对文件加锁,防止同时操作而出错

55                     if (flock($fp,LOCK_EX)){

56                         for ($i = 0; $i < $chunks; $i++) {

57                                 $tmp_file = $this->attachDIR . $chunk_path_array[$i];

58                                 $handle = fopen($tmp_file, "rb");

59                                 fwrite($fp, fread($handle, filesize($tmp_file)));

60                                 fclose($handle);

61                                 unset($handle);

62                                 unlink($tmp_file);//合并完毕的文件就删除

63                         }//组装分片

64                         $cache->delete($guid);

65                         for($i=0;$i<$chunks;$i++){

66                             $cache->delete($guid.$i);

67                         }

68                         $time = $this->getTime($join_file_name,$file_info['type']);

69                         $file_info['time'] = $time;

70                         $file_info['path'] = $saveName;

71                         $file_info['size'] = filesize($join_file_name);

72                         $file_info['last_chunk'] = true;

73

74                         $model_mod = new Model_Base();

75                        $model_mod->disconnect();

76                         $pid = pcntl_fork();

77                         //父进程和子进程都会执行下面代码

78                         if ($pid == -1) {

79                             //错误处理:创建子进程失败时返回-1.

80                             die('could not fork');

81                         } elseif ($pid) {

82                             $model_mod->connect();

83                             //对上传完成的视频进行排队转码

84                             $this->thread($join_file_name,$file_info['type'],$guid);

85                             //父进程会得到子进程号,所以这里是父进程执行的逻辑

86                             pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。

87                         } else {

88                             return$file_info;

89                             //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。

90                         }

91

92                     }

93                 }

94

95             }

96             return$file_info;

97         } else {

98                 $this->error[] = '分片上传失败';

99                 returnfalse;

100         }

101             /*}}}*/

102         }

1,实现了分片上传;

2,同时在上传前检查视频md5 是否在库,如已存在可实现“秒传” 功能,即直接复制数据信息,指向同一个文件,不必再上传;

3,可实现断点续传,上传过程中中断;之前上传的分片已保留在服务器,只需重新上传尚未上传的分片即可;

相关参考:

http://blog.ncmem.com/wordpress/2019/09/10/%e8%b6%85%e5%a4%a7%e6%96%87%e4%bb%b6%e4%b8%8a%e4%bc%a0%e6%96%b9%e6%a1%88%ef%bc%88php%ef%bc%89/

超大文件上传方案(PHP)的更多相关文章

  1. 求超大文件上传方案( Java )

    最近遇见一个需要上传百兆大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...

  2. 超大文件上传方案(B/S)

    javaweb上传文件 上传文件的jsp中的部分 上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求 1.通过form表单向后端发送请求 <form id=" ...

  3. 超大文件上传方案(ASP.NET)

    ASP.NET上传文件用FileUpLoad就可以,但是对文件夹的操作却不能用FileUpLoad来实现. 下面这个示例便是使用ASP.NET来实现上传文件夹并对文件夹进行压缩以及解压. ASP.NE ...

  4. 超大文件上传方案( Java )

    1.介绍enctype enctype 属性规定发送到服务器之前应该如何对表单数据进行编码. enctype作用是告知服务器请求正文的MIME类型(请求消息头content-type的作用一样) 1. ...

  5. 百万行mysql数据库优化和10G大文件上传方案

    百万行mysql数据库优化和10G大文件上传方案 最近这几天正在忙这个优化的方案,一直没时间耍,忙碌了一段时间终于还是拿下了这个项目?项目中不要每次都把程序上的问题,让mysql数据库来承担,它只是个 ...

  6. 4GB以上超大文件上传和断点续传服务器的实现

    随着视频网站和大数据应用的普及,特别是高清视频和4K视频应用的到来,超大文件上传已经成为了日常的基础应用需求. 但是在很多情况下,平台运营方并没有大文件上传和断点续传的开发经验,往往在网上找一些简单的 ...

  7. Java超大文件上传解决办法

    这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数 下面直接贴代码吧,一些难懂的我大部分都加上注释了: 上传文件实体类: 看得 ...

  8. web超大文件上传

    文件夹数据库处理逻辑 publicclass DbFolder { JSONObject root; public DbFolder() { this.root = new JSONObject(); ...

  9. 使用JS实现可断点续传的文件上传方案

    需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制. 第一步: 前端修改 由于项目使用的是 ...

随机推荐

  1. Matlab——图形绘制——三维立体图形 剔透玲珑球 动态图——彗星状轨迹图

    三维绘图函数 三维绘制工具 函数view 实例:三维螺旋线 >> t=:pi/:*pi; plot3(sin(t),cos(t),t) grid %添加网格  plot3可以画出空间中的曲 ...

  2. python学习中

    python中的单引号.双引号.三引号的用法 网上也查找了资料,理解的都有些费劲 就自己验证了一下(主要是目前掌握的python知识,不知道什么时候会同时用到这三种引号) 用python3验证的 单引 ...

  3. Neither abstinence nor excess ever renders man happy

    inch.n. 英寸 courageous.adj.勇敢的 porcelain.n.瓷器 adj.脆的 inventor. n. 发明者 trivial.adj. 不重要的 grove.n.小树林,果 ...

  4. k8s/01开启云原生之门(Mooc)

    一.kubernetes(k8s)基础知识 1.简介 在2017年Kubernetes战胜了两个强大的竞争对手Swarm和Mesos,成为容器管理与调度编排领域的首选平台和事实标准. 2014年k8s ...

  5. 深入理解java:2.3.2. 并发编程concurrent包 之重入锁/读写锁/条件锁

    重入锁 Java中的重入锁(即ReentrantLock)   与JVM内置锁(即synchronized)一样,是一种排它锁. ReentrantLock提供了多样化的同步,比如有时间限制的同步(定 ...

  6. Linux 系统多台主机之间做SSH免密码登陆

    SSH 免密登录 环境说明 CentOS 7.3 关键点 免密登录的关键点在于理解谁登录谁. A 生成的公钥给 B,也给 C.D,则 A 可以直接免密 SSH 登录 B.C.D A 生成密钥 在 A ...

  7. CentOS7 安装dotnet sdk 2.1.401 的简单办法

    1. 下载 linux版本的tar包 路径为: https://dotnet.microsoft.com/download/thank-you/dotnet-sdk-2.1.401-linux-x64 ...

  8. CentOS 7 下安装.NET Core SDK 2.1

    一.RPM包安装 1.导入rpm源 sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod ...

  9. vue中的provide和inject

    vue中的provide和inject:https://blog.csdn.net/viewyu12345/article/details/83011618

  10. osi七层模型??

    1.应用层:提供用户服务,例如处理应用程序,文件传输,数据管理      (HTTP.RTSP.FTP) 2.表示层:做数据的转换和压缩,加解密等 3.会话层:决定了进程间的连接建立,选择使用什么样的 ...