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

视频大小 小则几十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/08/09/php%E6%96%87%E4%BB%B6%E6%96%AD%E7%82%B9%E4%B8%8A%E4%BC%A0/

php文件断点上传的更多相关文章

  1. 后端springmvc,前端html5的FormData实现文件断点上传

    前言 最近项目中有使用到文件断点上传,得空便总结总结,顺便记录一下,毕竟“好记性不如烂笔头”. 后端代码: package com.test.controller; import java.io.Bu ...

  2. Android中Socket大文件断点上传

    原文:http://blog.csdn.net/shimiso/article/details/8529633 什么是Socket? 所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一 ...

  3. 文件断点上传,html5实现前端,java实现服务器

    断点上传能够防止意外情况导致上传一半的文件下次上传时还要从头下载,网上有很多关于断点的实现,这篇文章只是从前到后完整的记录下一个可用的实例,由于生产环境要求不高,而且就是提供给一两个人用,所以我简化了 ...

  4. Android应用开发之使用Socket进行大文件断点上传续传

    http://www.linuxidc.com/Linux/2012-03/55567.htm http://blog.csdn.net/shimiso/article/details/8529633 ...

  5. java HTTP文件断点上传

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

  6. asp.net 如何实现大文件断点上传功能?

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

  7. B/S文件断点上传

    一.概述 所谓断点续传,其实只是指下载,也就是要从文件已经下载的地方开始继续下载.在以前版本的HTTP协议是不支持断点的,HTTP/1.1开始就支持了.一般断点下载时才用到Range和Content- ...

  8. java文件断点上传

    1,项目调研 因为需要研究下断点上传的问题.找了很久终于找到一个比较好的项目. 在GoogleCode上面,代码弄下来超级不方便,还是配置hosts才好,把代码重新上传到了github上面. http ...

  9. jsp文件断点上传

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

  10. php中文件断点上传怎么实现?

    1.使用PHP的创始人 Rasmus Lerdorf 写的APC扩展模块来实现(http://pecl.php.net/package/apc) APC实现方法: 安装APC,参照官方文档安装,可以使 ...

随机推荐

  1. linux-2.6.38 IIC驱动框架分析

    在linux-2.6内核中,IIC的驱动程序可以大概分为三部分: (1)IIC核心代码:/drivers/i2c/i2c-core.c IIC核心提供了IIC总线驱动和设备驱动的注册.注销方法和IIC ...

  2. win服务器 解决apache 80端口被占用问题

    是系统的服务占用了80端口,所以要么结束系统服务,要么修改apache端口. PID4的服务是World Wide Web Publishing Service 这里选择结束这个系统服务,运行serv ...

  3. Java基础 @org.junit.Test-单元测试方法 + 操纵Collection和Map的工具类 : Collections 的sort/binarySearch/max/min等静态方法

      单元测试代码:  ( 在IDEA中先输入'@Test '然后根据提示进行自动修订即可!!运行时直接运行即可! 若有多个单元测试块的时候,直接把鼠标放在哪里就自动在哪里运行那个单元块) import ...

  4. 数组的新方法 forEach some filter findIndex

    forEach  some  filter  findIndex这些都属于数组的新方法,都会对数组中的每一项,进行遍历,执行相关的操作: 只不过在循环的时候有些不一样 参考资料:https://wan ...

  5. IIS设置网站为HTTPS并且将HTTP重定向到HTTPS

    第一步:下载证书,导入证书到IIS https://help.aliyun.com/knowledge_detail/95502.html 站点绑定https 第二部:安装URL重写模块 rewrit ...

  6. 2019牛客多校第四场J free——分层图&&最短路

    题意 一张无向图,每条边有权值,可以选择不超过 $k$ 条路使其权值变成0,求 $S$ 到 $T$ 的最短路.(同洛谷 P4568) 分析 首先,分层图最短路可以有效解决这种带有 「阶段性」的最短路, ...

  7. C# 动态加载程序集

    定义动态程序集 namespace DynamicAssembly { public class CodeDriver : MarshalByRefObject { private string pr ...

  8. CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths (dsu on tree) 题解

    先说一下dsu算法. 例题:子树众数问题. 给出一棵树,每个点有点权,求每个子树中出现次数最多的数的出现次数. 树的节点数为n,\(n \leq 500000\) 这个数据范围,\(O(n \sqrt ...

  9. 【题解】求细胞数量-C++

    题目描述一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数.(1<=m,n<=100)? 输入输出格式输入格 ...

  10. cursor: hand和cursor:pointer的区别

    cursor:hand 与 cursor:pointer 的效果是一样的,都像光标指向链接一样,光标变成手行. cursor:hand :IE完全支持.但是在firefox是不支持的,没有效果. cu ...