php+上传视频大文件
理清思路:
引入了两个概念:块(block)和片(chunk)。每个块由一到多个片组成,而一个资源则由一到多个块组成
块是服务端的永久数据存储单位,片则只在分片上传过程中作为临时存储的单位。服务端会以约一个月为单位周期性的清除上传后未被合并为块的数据片
实现过程:
将文件分割,分片上传,然后合并
前端核心code:
var fileForm = document.getElementById("file");
var upstartBtn = document.getElementById('upstart');
var stopBtn = document.getElementById('stop');
var startBtn = document.getElementById('restart');
var rate = document.getElementById('rate');
var divlog = document.getElementById('divlog');
//---------------------------
const LENGTH = 1024 * 1024 * 1;
var start = 0;
var end = start + LENGTH;
var blob;
var blob_num = 1;
var is_stop = 0
var file = null;
var md5filename = '';
//-----------------------------
var upload_instance = new Upload();
fileForm.onchange = function()
{
browserMD5File(fileForm.files[0], function (err, md5) { //如果文件大,md5值生成较慢 md5值生成后才能上传处理,自己优化下吧
md5filename = md5; //如果需要刷新后也能断点,可利用cookie记录,自行完善
divlog.innerHTML = '文件md5为:' + md5filename;
});
}
upstartBtn.onclick = function(){
upload_instance.addFileAndSend(fileForm);
}
stopBtn.onclick = function(){
upload_instance.stop();
}
startBtn.onclick = function(){
upload_instance.start();
}
function Upload(){
var xhr = new XMLHttpRequest();
var form_data = new FormData();
//对外方法,传入文件对象
this.addFileAndSend = function(that){
file = that.files[0];
blob = cutFile(file);
sendFile(blob,file);
blob_num += 1;
}
//停止文件上传
this.stop = function(){
xhr.abort();
is_stop = 1;
}
this.start = function(){
sendFile(blob,file);
is_stop = 0;
}
//切割文件
function cutFile(file){
var file_blob = file.slice(start,end);
start = end;
end = start + LENGTH;
return file_blob;
};
//发送文件
function sendFile(blob,file){
var total_blob_num = Math.ceil(file.size / LENGTH);
form_data.append('file',blob);
form_data.append('blob_num',blob_num);
form_data.append('total_blob_num',total_blob_num);
form_data.append('md5_file_name',md5filename);
form_data.append('file_name',file.name);
xhr.open('POST','./index.php',false);
xhr.onreadystatechange = function () {
var progress;
var progressObj = document.getElementById('finish');
if(total_blob_num == 1){
progress = '100%';
}else{
progress = (Math.min(100,(blob_num/total_blob_num)* 100 )).toFixed(2) +'%';
}
console.log('progress-----'+progress);
progressObj.style.width = progress;
rate.innerHTML = progress;
var t = setTimeout(function(){
if(start < file.size && is_stop === 0){
blob = cutFile(file);
sendFile(blob,file);
blob_num += 1;
}else{
//setTimeout(t);
}
},1000);
}
xhr.send(form_data);
}
}
后端code
<?php
class Upload{
private $filepath = './upload'; //上传目录
private $tmpPath; //PHP文件临时目录
private $blobNum; //第几个文件块
private $totalBlobNum; //文件块总数
private $fileName; //文件名
private $md5FileName;
public function __construct($tmpPath,$blobNum,$totalBlobNum,$fileName, $md5FileName){
$this->tmpPath = $tmpPath;
$this->blobNum = $blobNum;
$this->totalBlobNum = $totalBlobNum;
$this->fileName = $this->createName($fileName, $md5FileName);
$this->moveFile();
$this->fileMerge();
}
//判断是否是最后一块,如果是则进行文件合成并且删除文件块
private function fileMerge(){
if($this->blobNum == $this->totalBlobNum){
$blob = '';
for($i=1; $i<= $this->totalBlobNum; $i++){
$blob .= file_get_contents($this->filepath.'/'. $this->fileName.'__'.$i);
}
file_put_contents($this->filepath.'/'. $this->fileName,$blob);
$this->deleteFileBlob();
}
}
//删除文件块
private function deleteFileBlob(){
for($i=1; $i<= $this->totalBlobNum; $i++){
@unlink($this->filepath.'/'. $this->fileName.'__'.$i);
}
}
private function moveFile(){
$this->touchDir();
$filename = $this->filepath.'/'. $this->fileName.'__'.$this->blobNum;
move_uploaded_file($this->tmpPath,$filename);
}
//API返回数据
public function apiReturn(){
if($this->blobNum == $this->totalBlobNum){
if(file_exists($this->filepath.'/'. $this->fileName)){
$data['code'] = 2;
$data['msg'] = 'success';
$data['file_path'] = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['DOCUMENT_URI']).str_replace('.','',$this->filepath).'/'. $this->fileName;
}
}else{
if(file_exists($this->filepath.'/'. $this->fileName.'__'.$this->blobNum)){
$data['code'] = 1;
$data['msg'] = 'waiting';
$data['file_path'] = '';
}
}
header('Content-type: application/json');
echo json_encode($data);
}
private function touchDir(){
if(!file_exists($this->filepath)){
return mkdir($this->filepath);
}
}
private function createName($fileName, $md5FileName){
return $md5FileName . '.' . pathinfo($fileName)['extension'];
}
}
$upload = new Upload($_FILES['file']['tmp_name'],$_POST['blob_num'],$_POST['total_blob_num'],$_POST['file_name'],$_POST['md5_file_name']);
$upload->apiReturn();
效果展示:
详细代码可参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/php%e4%b8%8a%e4%bc%a0%e5%a4%a7%e6%96%87%e4%bb%b6-3/
php+上传视频大文件的更多相关文章
- php上传视频大文件
理清思路: 引入了两个概念:块(block)和片(chunk).每个块由一到多个片组成,而一个资源则由一到多个块组成 块是服务端的永久数据存储单位,片则只在分片上传过程中作为临时存储的单位.服务端会以 ...
- 框架基础:ajax设计方案(三)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组
马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...
- 前端通信:ajax设计方案(四)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组
马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...
- ASP.NET 使用ajaxfileupload.js插件出现上传较大文件失败的解决方法(ajaxfileupload.js第一弹)
在写这篇的时候本来想把标题直接写成报错的提示,如下: “SecurityError:Blocked a frame with origin "http://localhost:55080&q ...
- asp.net 文件上传,大文件上传。
新建一个asp.net页面,在工具栏里拖入 FileUpload 上传控件.一个按钮 Button ! ! ! 进入Button事件 //----------------------- ...
- ASP.NET 使用ajaxupload.js插件出现上传较大文件失败的解决方法
在网上下载了一个ajaxupload.js插件,用于无刷新上传图片使的,然后就按照demo的例子去运行了一下,上传啊什么的都OK,但是正好上传的示例图片有一个比较大的,4M,5M的样子,然后上传就会报 ...
- NetCore3.0 文件上传与大文件上传的限制
NetCore文件上传两种方式 NetCore官方给出的两种文件上传方式分别为“缓冲”.“流式”.我简单的说说两种的区别, 1.缓冲:通过模型绑定先把整个文件保存到内存,然后我们通过IFormFile ...
- B/S结构下上传下载大文件(1G以上)的解决方案
以ASP.NET Core WebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API ,包括文件的上传和下载. 准备文件上传的API #region 文件上传 ...
- php+html5实现无刷新上传,大文件分片上传,断点续传
核心原理: 该项目核心就是文件分块上传.前后端要高度配合,需要双方约定好一些数据,才能完成大文件分块,我们在项目中要重点解决的以下问题. * 如何分片: * 如何合成一个文件: * 中断了从哪个分片开 ...
随机推荐
- PHPexcel使用 技巧
phpexcel不用多说了 导出表格时经常会用到 本帖主要记录一下几个经常用到的操作 # 设置自动换行 $PHPExcel->getActiveSheet()->getStyle(&q ...
- LeetCode 142——环形链表II(JAVA)
给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 - ...
- CSP2019螺旋升天爆炸记
Day -N 半年没碰OI的我终于又回到了这个熟悉又陌生的地方.然后颓废了两天就过了初赛? 初赛rp爆棚考了全校第一,然并卵 然后就是打了遍树状数组模板,写挂了(没错我现在连树状数组都会写挂) 看一眼 ...
- poj 1064 求解最大化问题
对于二分而言,如果判断条件比较简单的话,在求解最大化或者最小化问题的时候就比较适用但是这道题目吖的卡精度.. #include<cstdio> #include<iostream&g ...
- java lesson20homework
package com.xt.lesson20; /** * 简易自动提款机 1. 创建用户类User(包含卡号.姓名.密码.余额等属性),用户开卡时录入的姓名和密码(自动分配一个卡号.初始金额设置为 ...
- Advanced Installer 不弹出预安装的软件的窗口
需求:当他电脑上没有sql server client 的时候,或没有localdb的时候,那么安装包会弹出窗口,让他选择 一个组件 一个组件的安装 太麻烦. 有没有办法,打开安装包就安装 安装的过程 ...
- 利用宏方便地书写raw string literals
以前一直没用过标准库的regex,今天写一个hlsl的解析工具的时候用了一下,发现用字符串字面值写regular expression的时候非常不方便,特别是每个“\”字符都要被识别为转义,只能写成“ ...
- WebStorm 使用技巧
常用快捷键 代码编辑 ctrl + d:复制行 ctrl + y:删除行 ctrl + x:剪切行 ctrl + shift + ↑: 行移动 ctrl + shift + enter: 换行 ctr ...
- docker容器生态技术链
图片来源:https://blog.51cto.com/liuleis/2067116 说明:学习Docker容器技术,先纵向了解大致内容架构,再横向逐一分解涉及的各项技术内容,对容器所涉及的技术体系 ...
- JavaMaven【一、概述&环境搭建】
课程概述 JavaMaven[一.概述&环境搭建] JavaMaven[二.目录结构&HelloMaven] JavaMaven[三.常用指令] JavaMaven[四.坐标& ...