php 大文件上传

项目需上传大资源视频文件,服务端不能直接传大文件与php.ini几个配置有关,如max_execution_time等,需修改对应配置值。还可利用HTML5的FILE API在浏览器端切割文件,介绍了JS和PHP实现上传的思路,并提及有前端和PHP部分的DEMO代码。

最近项目需要上传大资源视频文件,撸!

服务端为什么不能直接传大文件?跟php.ini里面的几个配置有关

1

2

3

4

upload_max_filesize = 2M //PHP最大能接受的文件大小

post_max_size = 8M //PHP能收到的最大POST值'

memory_limit = 128M //内存上限

max_execution_time = 30 //最大执行时间

1、max_execution_time
变量max_execution_time设置了在强制终止脚本前PHP等待脚本执行完毕的时间,此时间以秒计算。当脚本进入了一个无限循环状态 时此变量非常有用。然而,当存在一个需要很长时间完成的合法活动时(例如上传大型文件),这项功能也会导致操作失败。在这样的情况下必须考虑将此变量值增 加,以避免PHP在脚本正在执行某些重要过程的时候将脚本关闭。
修改为:max_execution_time =800
2、file_uploads = On(原来问开就不用设置了)
3、upload_max_filesize =2M修改为800M
4、同表单提交相关的一个变量是post_max_size,它将控制在采用POST方法进行一次表单提交中PHP所能够接收的最大数据量。需要将默认的8 MB改得更大。相反,应当适当将其降到更为实际的数值。但如果希望使用PHP文件上传功能,则需要将此值改为比upload_max_filesize还 要大。
也修改为:post_max_size =900M
5、max_input_time
此变量可以以秒为单位对通过POST、GET以及PUT方式接收数据时间进行限制。如果应用程序所运行环境处在低速链路上,则需要增加此值以适应接收数据所需的更多时间.
修改为:max_input_time =900
6、memory_limit =10M(这里需要说明,尽量不要更改这里,我改动之后发现有错误提示,但是我改成默认的128M就又好了)
为了避免正在运行的脚本大量使用系统可用内存,PHP允许定义内存使用限额。通过memory_limit变量来指定单个脚本程序可以使用的最大内存容量
变量memory_limit的值(不要超出服务器内寸最大值)
修改为:memory_limit =128M

 

解决思路

好在HTML5开放了新的FILE API,也可以直接操作二进制对象,我们可以直接在浏览器端实现文件切割,按照以前的做法就得用Flash的方案,实现起来会麻烦很多。

JS思路

1.监听上传按钮的onchange事件

2.获取文件的FILE对象

3.把文件的FILE对象进行切割,并且附加到FORMDATA对象中

4.把FORMDATA对象通过AJAX发送到服务器

5.重复3、4步骤,直到文件发送完。

PHP思路

1.建立上传文件夹

2.把文件从上传临时目录移动到上传文件夹

3.所有的文件块上传完成后,进行文件合成

4.删除文件夹

5.返回上传后的文件路径

DEMO代码

前端部分代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

<!doctype html>

<html lang="en">

<head>

 <meta charset="UTF-8">

 <meta name="viewport"

   content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

 <meta http-equiv="X-UA-Compatible" content="ie=edge">

 <title>Document</title>

 <style>

  #progress{

   width: 300px;

   height: 20px;

   background-color:#f7f7f7;

   box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);

   border-radius:4px;

   background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);

  }

 

  #finish{

   background-color: #149bdf;

   background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);

   background-size:40px 40px;

   height: 100%;

  }

  form{

   margin-top: 50px;

  }

 </style>

</head>

<body>

<div id="progress">

 <div id="finish" style="width: 0%;" progress="0"></div>

</div>

<form action="./upload.php">

 <input type="file" name="file" id="file">

 <input type="button" value="停止" id="stop">

</form>

<script>

 var fileForm = document.getElementById("file");

 var stopBtn = document.getElementById('stop');

 var upload = new Upload();

 

 fileForm.onchange = function(){

  upload.addFileAndSend(this);

 }

 

 stopBtn.onclick = function(){

  this.value = "停止中";

  upload.stop();

  this.value = "已停止";

 }

 

 function Upload(){

  var xhr = new XMLHttpRequest();

  var form_data = new FormData();

  const LENGTH = 1024 * 1024;

  var start = 0;

  var end = start + LENGTH;

  var blob;

  var blob_num = 1;

  var is_stop = 0

  //对外方法,传入文件对象

  this.addFileAndSend = function(that){

   var file = that.files[0];

   blob = cutFile(file);

   sendFile(blob,file);

   blob_num += 1;

  }

  //停止文件上传

  this.stop = function(){

   xhr.abort();

   is_stop = 1;

  }

  //切割文件

  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('file_name',file.name);

 

   xhr.open('POST','./upload.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 ) +'%';

    }

    progressObj.style.width = 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);

  }

 }

 

</script>

</body>

</html>

PHP部分代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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

65

66

67

68

69

70

71

72

73

74

75

<?php

class Upload{

 private $filepath = './upload'; //上传目录

 private $tmpPath; //PHP文件临时目录

 private $blobNum; //第几个文件块

 private $totalBlobNum; //文件块总数

 private $fileName; //文件名

 

 public function __construct($tmpPath,$blobNum,$totalBlobNum,$fileName){

  $this->tmpPath = $tmpPath;

  $this->blobNum = $blobNum;

  $this->totalBlobNum = $totalBlobNum;

  $this->fileName = $fileName;

   

  $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 for all';

     $data['file_path'] = '';

    }

  }

  header('Content-type: application/json');

  echo json_encode($data);

 }

  

 //建立上传文件夹

 private function touchDir(){

  if(!file_exists($this->filepath)){

   return mkdir($this->filepath);

  }

 }

}

 

//实例化并获取系统变量传参

$upload = new Upload($_FILES['file']['tmp_name'],$_POST['blob_num'],$_POST['total_blob_num'],$_POST['file_name']);

//调用方法,返回结果

$upload->apiReturn();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值