关于 javascript+php 文件上传的那档子事

2022-10-12 11:24:00

一.--基本原理

二.--实现方法

三.--注意事项

一:1:利用原生js+php实现文件上传,在php中有一个$_FILES的全局变量,他能直接接收到前端 input:file所提交的file文件,但是上传一些小文件就还好,但是当文件足够大时,比如100mb,1000mb时,这种方法就可能造成上传超时或者说根本上传不上去的概况(因为有缓冲区超过了缓冲区会触发各种问题,除非严格限制文件上传的大小,比如php中的$_FILES最多就能获取2MB大小的文件,当然可以通过改配置去设置大小,但是能改100MB能改1000MB嘛,所以这个方法是治标不治本的),这种情况下就需要来一个文件分片上传

ps:什么是分片上传,顾名思义,就是把文件切成n片大小,然后一片一片的上传到后端,后端经过参数校验合格后存储到本地,当全部获取到后就待变文件上传成功了

(当看到这片文章的时候应该知道什么是分片上传了,但是还是想多嘴一句哈哈哈)

   2:分片以及上传原理

  让我们先来看一下

 

 

  

         

       

如上图,input:file中的内容存储在files中,是一个fileList的对象

Formdata对象:

官方解释如下:

FormData 对象用以将数据编译成键值对,以便用XMLHttpRequest来发送数据。其主要用于发送表单数据,但亦可用于发送带键数据 (keyed data),而独立于表单使用。如果表单enctype属性设为 multipart/form-data,则会使用表单的submit()方法来发送数据,从而,发送数据具有同样形式。

 

 

 

 

 基本方法:

new FormData(); 返回一个FormData对象    

FormData.append("name",value) 将一个名为name,值为value的字段添加到一个已经实例了的FormData的对象中

bolo对象:

官方解释如下:

Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。

Blob 表示的不一定是 JavaScript 原生格式的数据。File 接口基于 Blob,继承了 blob 的功能并将其扩展以支持用户系统上的文件。

Blob()返回一个新创建的 Blob 对象,其内容由参数中给定的数组拼接组成。

在bolo对象中有一个Blob.prototype.slice()方法

Blob.slice() 方法用于创建一个包含源 Blob的指定字节范围内的数据的新 Blob 对象。

var blob = instanceOfBlob.slice([start [, end [, contentType]]]};
start 可选

这个参数代表 Blob 里的下标,表示第一个会被会被拷贝进新的 Blob 的字节的起始位置。如果你传入的是一个负数,那么这个偏移量将会从数据的末尾从后到前开始计算。举例来说,-10 将会是 Blob 的倒数第十个字节。它的默认值是 0,如果你传入的 start 的长度大于源 Blob 的长度,那么返回的将会是一个长度为 0 并且不包含任何数据的一个 Blob 对象。

end 可选

这个参数代表的是 Blob 的一个下标,这个下标 -1 的对应的字节将会是被拷贝进新的Blob 的最后一个字节。如果你传入了一个负数,那么这个偏移量将会从数据的末尾从后到前开始计算。举例来说, -10 将会是 Blob 的倒数第十个字节。它的默认值就是它的原始长度 (size).

contentType 可选

给新的 Blob 赋予一个新的文档类型。这将会把它的 type 属性设为被传入的值。它的默认值是一个空的字符串。

返回值

一个新的 Blob 对象,它包含了原始 Blob 对象的某一个段的数据。

上文提到的input:file 中的fileList中的一项也属于是 bolo类型 可以直接使用slice

 

 

 

如上图不解释

另外,ajax中send能直接send(FormData)

 

 FormData中的字段发送后如上图

分片部分结束了接下来看看上传部分

还是如上图我设计的字段有

文件数据,文件名,文件大小,总片数,当前片段,类型文件上传

然后依次把文件的每一片依次上传到后台

后台接收到后创建文件夹,一一追加到文件中

二,实现方法 

  直接上代码把

前端部分
<!
DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="file" name="" id="file" multiple="multiple"> <script> class ajaxo_s{ constructor(model_name,parameter) { this.model_name=model_name; this.parameter=parameter; } str_pinjie(){ var data=''; var key=Object.keys(this.parameter.request_data); var value=Object.values(this.parameter.request_data); for(var request_len=0;request_len<key.length;request_len++){ data+=key[request_len]+"="+value[request_len]+"&"; } return data.slice(0,data.length-1); } implement(success){ var request_data=this.str_pinjie(); var XMLhttp=new XMLHttpRequest(); XMLhttp.onreadystatechange=function(){ if(XMLhttp.status==200&&XMLhttp.readyState==4){ success(XMLhttp.response); } } if(this.model_name=="POST"){ XMLhttp.open("post",this.parameter.url); XMLhttp.setRequestHeader('content-type','application/x-www-form-urlencoded'); XMLhttp.send(request_data); return; } if(this.model_name=="GET"){ XMLhttp.open('get',this.parameter.url+"?"+request_data); XMLhttp.send(); return; } } start(success){ this.implement(success); } } class cutFile{ file=null; maxSize=1*1024*1024; //5mb constructor(file){ this.file=file; } //传入file开始切割 cut(file){ let fileSize=file.size; let fileType=file.type; let fileName=file.name; let start=0; let end=this.maxSize+start; let data=[]; let data_p=new FormData(); let allPNum=Math.ceil(fileSize/this.maxSize); if(allPNum==1){ data_p.append("file_data",file); data_p.append("file_name",fileName); data_p.append("file_size",fileSize); data_p.append("allPNum",allPNum); data_p.append("current",1); data_p.append("type","fileUpload"); data.push(data_p) }else{ for(let i=0;i<allPNum;i++){ if(this.maxSize+start>fileSize){ data_p.append("file_data",file.slice(start,fileSize-start)); data_p.append("file_size",fileSize-start); }else{ data_p.append("file_data",file.slice(start,end)); data_p.append("file_size",this.maxSize); start=end; end=this.maxSize+start; } data_p.append("file_name",fileName); data_p.append("allPNum",allPNum); data_p.append("current",i+1); data_p.append("type","fileUpload"); data.push(data_p) data_p=new FormData(); } } return data; } run(){ let data=[]; // console.log(this.file.length); if(this.file instanceof FileList){ for(let j=0;j<this.file.length;j++){ data.push(this.cut(this.file[j])); } }else{ data.push(this.cut(this.file)); } return data; } } class sendFile{ local=null; file=null sendStatu=0; //0未发送 1分片发送中 2发送成功 sendNum=0; //查看当前发送到那一段了 constructor(local,file){ this.local=local; if(file instanceof Array){ this.file=file; }else{ return "请传入一个数组"; } } fileSend(file,i,thisClass){ var XMLhttp=new XMLHttpRequest(); XMLhttp.onreadystatechange=function(){ if(XMLhttp.status==200&&XMLhttp.readyState==4){ let return_data=JSON.parse(XMLhttp.responseText) console.log(return_data); if(return_data.content=="分片上传成功"&&return_data.statu==200){ i+=1; if(i<file.length){ return setTimeout(()=>{ thisClass.fileSend(file,i,thisClass) },0); }else{ console.log("哈哈哈哈代码出bug了吧") } }else if(return_data.content=="文件上传成功"){ console.log(return_data.fileUrl); } } } XMLhttp.open("POST",thisClass.local,false); XMLhttp.send(file[i]); } run(){ this.fileSend(this.file,0,this); } } var file=document.getElementById("file"); file.addEventListener("change",function(e){ var file_data=new cutFile(file.files[0]).run(); new sendFile("http://test.com/test123.php",file_data[0]).run(); }) </script> </body> </html>

 

 

后端部分
<?php use file_operate as GlobalFile_operate; header("Access-Control-Allow-Origin: *"); class file_operate{ public static function rewriteFile(string $path,string $data,int $time_out=2){ if(file_exists($path)){ $file_open=fopen($path,"w"); $get_file_lock=flock($file_open,LOCK_EX|LOCK_NB); $stime=microtime(true); while(!$get_file_lock){ $get_file_lock=flock($file_open,LOCK_EX|LOCK_NB); if((microtime(true)-$stime)>$time_out){ return "超时"; } } if(fwrite($file_open,$data)!==false){ fflush($file_open); flock($file_open, LOCK_UN);//释放锁 fclose($file_open); return "重写成功"; }else{ flock($file_open, LOCK_UN);//释放锁 fclose($file_open); return "重写失败"; } }else{ return "路径错误"; } } //读取文件 public static function readfile(string $path){ if(file_exists($path)){ return file_get_contents($path); }else{ return "路径错误"; } } // 创建文件 public static function creatFile(string $path){ if(file_exists($path)){ return "文件已存在"; }else{ fclose(fopen($path,"w")); } } // 检查文件 public static function fileExists(string $path){ return file_exists($path); } public static function unlinkFile(string $path){ return unlink($path); } // 将一个文件中的东西追加到另外一个文件 public static function fileAppend(string $targetFile,string $contentFile,bool $delContent=false,bool $creatTarget=true){ if(file_exists($contentFile)==false){ return "文件路径不存在"; } if(file_exists($targetFile)==false){ if($creatTarget==false){ return "文件路径不存在"; }else{ GlobalFile_operate::creatFile($targetFile); } } $content=file_get_contents($contentFile); file_put_contents($targetFile,$content,FILE_APPEND); if($delContent==true){ unlink($contentFile); } } } class onlyId{ // 获取随机数 public static function randNum(int $bit,int $returnType=1){ $a=[0,1,2,3,4,5,6,7,8,9]; $string=""; if($bit>10&&$returnType==1){ return false; } for($i=0;$i<$bit;$i++){ $string.=$a[rand(0,9)]; } if($returnType==1){ return (int)$string; }else{ return (string)$string; } } // 获取唯一id public static function getId(){ $sec=explode(' ',microtime())[1]; $random=onlyId::randNum(4,2); return $sec.$random; // list($msec,$sec) = explode(' ',microtime()); } } if($_POST["type"]=="fileUpload"){ $path=dirname(__FILE__)."/data/"; GlobalFile_operate::fileAppend($path.$_POST["file_name"],$_FILES["file_data"]["tmp_name"]); if($_POST["allPNum"]==$_POST["current"]){ $data=array( "content"=>"文件上传成功", "statu"=>200, "fileUrl"=>$path.$_POST["file_name"] ); echo json_encode($data,JSON_FORCE_OBJECT); }else{ $data=array( "content"=>"分片上传成功", "statu"=>200 ); echo json_encode($data,JSON_FORCE_OBJECT); } } // $data=array( // "content"=>"分片上传成功", // "statu"=>200 // ); // echo json_encode($data,JSON_FORCE_OBJECT); // var_dump($_FILES["file_data"]);

 

 三,暂时还没想好写啥

posted @ 2022-10-12 11:24  鬼灰也  阅读(75)  评论(0)    收藏  举报