código de muestra de carga de fragmento de archivo grande php + ajax

idea de código

Cuando PHP carga archivos muy grandes, no puede simplemente dejar que el backend php cargue , y perderá fácilmente la mitad de los beneficios de las pruebas internas. El front-end debe cooperar con el back-end para procesar juntos, y la carga del archivo debe usar el método AJAX en lugar del método de envío del formulario.

El front-end divide el objeto de archivo en archivos de cierto tamaño de acuerdo con un cierto tamaño (por ejemplo, según 2M o 5M) y carga los archivos divididos en el backend uno por uno. Después de que el backend recibe los archivos fragmentados, el Primero se colocan en un directorio temporal. Cuando se recibe la solicitud de datos completada por el front-end, los archivos en el directorio temporal se ensamblan en un nuevo archivo. Después de guardar, elimine los archivos en el directorio temporal.

Código de muestra

Código HTML:

1

2

3

<div class="a">

    上传<input id="myfile" type="file" name="myfile"/>

</div>

Aquí para explicar, no use enviar para cargar, use ajax para cargar.

Código JS :

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

dieciséis

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

sesenta y cinco

<script>

$(function(){

let myfile = document.getElementById("myfile");

myfile.onchange = function(){

let file = myfile.files[0]; // 这里可以得到上传的文件对象

let length = 1024 * 1024 * 5; // 这里是每一个分片的大小

let total_number = Math.ceil(file.size/length); // 使用进一法,来确定分片的个数

let start = 0; // 分片的初始位置

let end = length; // 分片的结束位置

let parr = []; // 这里为promise.all方法准备一个数组

for(let i = 1;i<=total_number;i++){

// 这里开始分片,并且把每一个分片上传到服务器

let bolb = file.slice(start,end); // 得到一个分片

start = end; // 调整下一个分片的起始位置

end = start+length; // 调整下一个分片的结束位置

if(end > file.size){

end=file.size; // 这里对最后的一个分片结束位置进行调整

}

let formdata = new FormData(); // 创建一个FormData对象,准备传送数据

formdata.append("file",blob); // 将分片数据放入formdata

formdata.append("tempfilename",i+"_"+file.name); // 同时为这个分片设置一个名称,其中的i帮助后端进行排序处理

// formdata组装好之后,调用pro()函数,返回一个promise对象,并把它放入parr数组中,方便后面的promise.all方法使用

parr.push(pro(formadata));

}

// 以上for循环结束之后,parr数组中就全部是分片上传的promise的对象了,此时我们使用promise.all方法,等待所有上传都成功执行后,再向服务器发送一个请求,也就是上传完成,让服务器组装分片的请求

Promise.all(parr).then(res=>{

if(res.length == parr.length){ // 如果返回成功的数组长度和parr的数组长度相等,说明分片全部上传成功

// 此时对上传接口再次发送请求,同时把上传的文件名带上,方便后台查找要组装的分片文件名,因为是请求同一个上传接口,所以我们还要传一个flag=1表示这是一个数据组装的请求

                    $.ajax({

                        type:"post",

                        url:"http://xxx.com/index/upload/getupload",

                        data:{flag:1,filename:file.name}, // 这里flag=1表示上传完成,请求组装,filename表示要组成哪一组文件分片

                        success:function(res){

                            if(res.length == parr.length){

                                console.log(111);

                            }

                        },

                        fail: function () {

                            reject()

                        }

                    })

}

})

}

})

// 这个函数用来上传分片文件,返回的是一个promise对象,方便后面使用promise.all还判断所有分片是否是上传成功的

// 这里要说明一下,$.post()是不可以上传文件的,只能用$.ajax()并且要把contentType:false和processData:false带上

    function pro(formData){

        return new Promise((resolve,reject)=>{

            $.ajax({

                type:"post",

                url:"http://xxx.com/index/upload/getupload", // 后台上传文件的地址

                data:formData,

                contentType: false// 这个不能少,ajax上传文件是不能少的

                processData: false// 这个不能少,ajax上传文件必传false

                success:function(res){

                    resolve(res)

                },

                fail: function () {

                    reject()

                }

            })

        })

    }

</script>

Lo anterior es la parte central del front-end js, y los comentarios básicamente se pueden entender.

codigo php :

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

dieciséis

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

<?php

// tp5框架

public function getUpload(){

$tempdir = APP_PATH."../public/tempdir"// 这里分片的文件指定了一个临时目录,后面会用到

$flag = input("flag",0); // 接收参数flag如果没有这个参数就默认为0,如果flag=1,表示要组装分片

if($flag == 0){

// 这里是上传分片

$file = request()->file("file"); // 接收到这个分片

$tempfilename = input("tempfilename"); // 接收到这个分片的名称,注意:这个名称中含有排序信息

if(!file_exists($tempdir)){

mkdir($tempdir,0755,true); // 如果临时目录不存在,则创建一个临时目录

}

$fileinfo $file->move($tempdir,$tmpfilename);

if($fileinfo){ // 把分片的文件保存在了临时目录中,返回有点简单,可以根据需求返回相应的数据

return josn(['error'=>0]);

}else{

return json(['error'=>1]);

}

}elseif($flag == 1){

// 如果flag为1表示,分片已上传完成了

$filename = input("filename");

// 通过文件名的字符串匹配,找上所有的分片,返回一个文件路径的数组

$fileArr glob($tempdir."/*".$filename);

// 这里的*是一个通配符,将所有的文件名中包含的$filename的文件都找到

// 说明一下,$fileArr中的数组的顺序不是我们想要的,所以我们新建一个数组来整理一下顺序

$newfileArr = [];

foreach($fileArr as $f){

    // js前端把文件的名称前加了'序号+_',以下划线来分开并把序号写在key中

$fileBaseName basename($f); // $f是一个个的路径,这里使用basename得到文件名

$fileBaseNameSplit explode("_"$fileBaseName); // 通过下划线分割文件名

$newfileArr[$fileBaseNameSplit[0]] = $f// 构造了一个新的数组,其中数组的key就是顺序号,数组的值就是分片文件的路径

}

// 分片的序号和路径都准备好了,就可以组装了

$num count($newfileArr); // 得到的所有分片的个数,为后面使用for循环做准备

// 开始使用for循环来组装

$newfilename "new-".$filename// 这里为组装后的文件起一个名字

for($i=1; $i<=$num$i++){

            // 这里以追加的方式,把分片文件都写入到了一个文件中

            file_put_contents($newfilename,file_get_contents($newfileArr[$i]),FILE_APPEND);

        }

// ......

// 删除临时文件中的分片文件,这里可以使用try catch来判断是否有错误

foreach($newfileArr as $fi){

unlink($fi);

}

// 最后给前端返回保存的文件名就可以

}

}

El método anterior, cargué un archivo de 650M localmente y solo tomó 20 segundos. No lo he probado en el servidor. Puedes probar este método.

Supongo que te gusta

Origin blog.csdn.net/winkexin/article/details/131017197
Recomendado
Clasificación