ajax xhr 大文件分块上传前端和后端代码
【HTML部分】
<div id="container">
<a id="selectfiles" href="javascript:void(0);" class='btn' onclick="document.getElementById('c-files').click();">选择文件</a>
<input id="c-files" class="form-control" name="file" type="file" style="display: none">
<a id="postfiles" href="javascript:void(0);" class='btn'>开始上传</a>
<p id="filetypeTips" class="goods_sx">支持上传文件格式:PDF,PSD,AI,CDR</p>
<p class="goods_sx">当前选择:<span id="file_info"></span></p>
<p class="goods_sx">上传文件:<span id="server_info"></span></p>
</div>
<div class="step_line"><div id="step_line"></div></div>
【Javascript部分】
<script>
var selectfiles_button =document.getElementById("c-files");
var postfiles_button =document.getElementById("postfiles");
var file_info_button =document.getElementById("file_info");
var step_line_button =document.getElementById('step_line');
var server_info_button =document.getElementById('server_info');
//上传文件侦测侦测
selectfiles_button.addEventListener("change",(e)=>{
//console.log(e.target.files[0]);
step_line_button.innerHTML ='';
file_info_button.innerHTML ='';
var reader = new FileReader();
var file =e.target.files[0];
//reader.readAsDataURL(e.target.files[0]);
reader.readAsDataURL(file);
reader.onloadstart= function(){
console.log(reader.result);
//selectfiles_button.setAttribute("value",reader.result);
file_info_button.innerHTML= file.name;
}
})
//上传POST
postfiles_button.addEventListener("click", function(){
// 文件对象
var file = selectfiles_button.files[0];
// 分块的大小 默认4M
var block = 1024 * 1024 * 10;
// 文件大小
var fileSize = file.size;
// 总的分块数
var totalCount = Math.ceil(fileSize / block);
var start = 0,
end = 0;
// 原文件名
var fileName = file.name;
// 生成随机的前缀
var prfix = Math.random();
//返回服务器文件地址
var server_url ='1';
var init_b =0;
for(var num = 0; num <totalCount; num++) {
//块数据
start = num * block;
end = start + block;
blockFile = file.slice(start, end);
// 组装 FormData() 对象
var formData = new FormData();
formData.append('file', blockFile);
formData.append('num', num);
formData.append('fileName', fileName);
formData.append('prfix', prfix);
formData.append('totalCount', totalCount);
//AJAX请求
var xhr =new XMLHttpRequest(num);
//采用同步的方式
xhr.open('post','user.php?act=blob',false);
//获取进度条对象
var jdt=document.querySelector('#step_line');
//返回状态
xhr.onload = function(dd) {
//console.log('ff_'+num);
//console.log(jdt);
if (xhr.readyState === 4) {
if (xhr.status === 200) {
//console.log(this.response);
//刷新进度条
var curr =num+1;
var total =totalCount;
var percent = Math.ceil((curr/total)*100);
var len = percent * 300 /100;
jdt.innerHTML=percent+'%';
jdt.setAttribute("style","width:"+len+"px;background:green;border-radius: 10px;");
//赋值
var result =JSON.parse(this.response);
//console.log(result);
if(result.code==1){
if(typeof(result.url)=='undefined'||result.url==''||result.url==null){
server_info_button.innerHTML='';
}else{
server_info_button.innerHTML=result.url;
}
}else{
//失败要回滚 删除临时缓存
}
} else {
console.error(xhr.statusText);
}
}
};
//设置请求超时的时间
//xhr.timeout = 3000;
init_b =1;
//发送请求
xhr.send(formData);
}
});
</script>
【PHP后端】
/**分块上传**/
function action_blob(){
//设置json格式
header('content-type:application/json;charset=utf-8');
// 接收 post 和FILES参数
$data = $_POST;
$file = $_FILES;
if(!$file['file']){
exit(json_encode(['code'=>0,'msg'=>'文件不存在']));
}
//创建目录
$dir=ROOT_PATH .'data/block/'; //块临时目录
$save_dir=ROOT_PATH .'data/printfile/'; //最终目录
if(!is_dir($dir)){
mkdir($dir,0777);
}
if(!is_dir($save_dir)){
mkdir($save_dir,0777);
}
// 分块文件位置
$block_path =$dir. $data['prfix']. '_';
//临时保存分块
$save_key =$dir.$data['prfix'].'_' . $data['num'];
move_uploaded_file($file['file']['tmp_name'],$save_key );
$done = 0;
$file_url='';
// 判断文件是否上传完成
if ($data['num'] == ($data['totalCount'] - 1)) {
$ext = pathinfo($data['fileName'], PATHINFO_EXTENSION);
$newFileName = $data['prfix'] . '.' . $ext;
// 合并文件 注意file_put_contents 添加FILE_APPEND 避免替换数据
for($i = 0; $i < $data['totalCount']; $i++) {
file_put_contents($save_dir. $newFileName, file_get_contents($block_path.$i),FILE_APPEND);
}
// 合并完成后删除分块文件
for($i = 0; $i < $data['totalCount']; $i++) {
unlink($dir. $data['prfix'] . '_' . $i);
}
$done = 1;
$file_url=$save_dir.$newFileName;
//上传完成后返回
exit(json_encode(['code'=>1,'msg'=>'文件上传成功','url'=>$file_url]));
}
//返回状态
exit(json_encode(['code'=>1,'msg'=>'分块上传成功']));
}