php大文件上传
Posted 极客攻略
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php大文件上传相关的知识,希望对你有一定的参考价值。
问题
服务端为什么不能直接传大文件?跟php.ini里面的几个配置有关:
1upload_max_filesize = 2M //PHP最大能接受的文件大小
2post_max_size = 8M //PHP能收到的最大POST值'
3memory_limit = 128M //内存上限
4max_execution_time = 30 //最大执行时间
当然不能简单粗暴的把上面几个值调大,否则服务器内存资源吃光是迟早的问题。
解决思路
好在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<!doctype html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport"
6 content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
7 <meta http-equiv="X-UA-Compatible" content="ie=edge">
8 <title>Document</title>
9 <style>
10 #progress{
11 width: 300px;
12 height: 20px;
13 background-color:#f7f7f7;
14 box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);
15 border-radius:4px;
16 background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);
17 }
18
19 #finish{
20 background-color: #149bdf;
21 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);
22 background-size:40px 40px;
23 height: 100%;
24 }
25 form{
26 margin-top: 50px;
27 }
28 </style>
29</head>
30<body>
31<div id="progress">
32 <div id="finish" style="width: 0%;" progress="0"></div>
33</div>
34<form action="./upload.php">
35 <input type="file" name="file" id="file">
36 <input type="button" value="停止" id="stop">
37</form>
38<script>
39 var fileForm = document.getElementById("file");
40 var stopBtn = document.getElementById('stop');
41 var upload = new Upload();
42
43 fileForm.onchange = function(){
44 upload.addFileAndSend(this);
45 }
46
47 stopBtn.onclick = function(){
48 this.value = "停止中";
49 upload.stop();
50 this.value = "已停止";
51 }
52
53 function Upload(){
54 var xhr = new XMLHttpRequest();
55 var form_data = new FormData();
56 const LENGTH = 1024 * 1024;
57 var start = 0;
58 var end = start + LENGTH;
59 var blob;
60 var blob_num = 1;
61 var is_stop = 0
62 //对外方法,传入文件对象
63 this.addFileAndSend = function(that){
64 var file = that.files[0];
65 blob = cutFile(file);
66 sendFile(blob,file);
67 blob_num += 1;
68 }
69 //停止文件上传
70 this.stop = function(){
71 xhr.abort();
72 is_stop = 1;
73 }
74 //切割文件
75 function cutFile(file){
76 var file_blob = file.slice(start,end);
77 start = end;
78 end = start + LENGTH;
79 return file_blob;
80 };
81 //发送文件
82 function sendFile(blob,file){
83 var total_blob_num = Math.ceil(file.size / LENGTH);
84 form_data.append('file',blob);
85 form_data.append('blob_num',blob_num);
86 form_data.append('total_blob_num',total_blob_num);
87 form_data.append('file_name',file.name);
88
89 xhr.open('POST','./upload.php',false);
90 xhr.onreadystatechange = function () {
91 var progress;
92 var progressObj = document.getElementById('finish');
93 if(total_blob_num == 1){
94 progress = '100%';
95 }else{
96 progress = Math.min(100,(blob_num/total_blob_num)* 100 ) +'%';
97 }
98 progressObj.style.width = progress;
99 var t = setTimeout(function(){
100 if(start < file.size && is_stop === 0){
101 blob = cutFile(file);
102 sendFile(blob,file);
103 blob_num += 1;
104 }else{
105 setTimeout(t);
106 }
107 },1000);
108 }
109 xhr.send(form_data);
110 }
111 }
112
113</script>
114</body>
115</html>
PHP部分代码
1<?php
2class Upload{
3 private $filepath = './upload'; //上传目录
4 private $tmpPath; //PHP文件临时目录
5 private $blobNum; //第几个文件块
6 private $totalBlobNum; //文件块总数
7 private $fileName; //文件名
8
9 public function __construct($tmpPath,$blobNum,$totalBlobNum,$fileName){
10 $this->tmpPath = $tmpPath;
11 $this->blobNum = $blobNum;
12 $this->totalBlobNum = $totalBlobNum;
13 $this->fileName = $fileName;
14
15 $this->moveFile();
16 $this->fileMerge();
17 }
18
19 //判断是否是最后一块,如果是则进行文件合成并且删除文件块
20 private function fileMerge(){
21 if($this->blobNum == $this->totalBlobNum){
22 $blob = '';
23 for($i=1; $i<= $this->totalBlobNum; $i++){
24 $blob .= file_get_contents($this->filepath.'/'. $this->fileName.'__'.$i);
25 }
26 file_put_contents($this->filepath.'/'. $this->fileName,$blob);
27 $this->deleteFileBlob();
28 }
29 }
30
31 //删除文件块
32 private function deleteFileBlob(){
33 for($i=1; $i<= $this->totalBlobNum; $i++){
34 @unlink($this->filepath.'/'. $this->fileName.'__'.$i);
35 }
36 }
37
38 //移动文件
39 private function moveFile(){
40 $this->touchDir();
41 $filename = $this->filepath.'/'. $this->fileName.'__'.$this->blobNum;
42 move_uploaded_file($this->tmpPath,$filename);
43 }
44
45 //API返回数据
46 public function apiReturn(){
47 if($this->blobNum == $this->totalBlobNum){
48 if(file_exists($this->filepath.'/'. $this->fileName)){
49 $data['code'] = 2;
50 $data['msg'] = 'success';
51 $data['file_path'] = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['DOCUMENT_URI']).str_replace('.','',$this->filepath).'/'. $this->fileName;
52 }
53 }else{
54 if(file_exists($this->filepath.'/'. $this->fileName.'__'.$this->blobNum)){
55 $data['code'] = 1;
56 $data['msg'] = 'waiting for all';
57 $data['file_path'] = '';
58 }
59 }
60 header('Content-type: application/json');
61 echo json_encode($data);
62 }
63
64 //建立上传文件夹
65 private function touchDir(){
66 if(!file_exists($this->filepath)){
67 return mkdir($this->filepath);
68 }
69 }
70}
71
72//实例化并获取系统变量传参
73$upload = new Upload($_FILES['file']['tmp_name'],$_POST['blob_num'],$_POST['total_blob_num'],$_POST['file_name']);
74//调用方法,返回结果
75$upload->apiReturn();
76
PHP后台处理
1/**
2 * 大文件切片上传
3 */
4 public function VideoUpload(){
5 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
6 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
7 header("Cache-Control: no-store, no-cache, must-revalidate");
8 header("Cache-Control: post-check=0, pre-check=0", false);
9 header("Pragma: no-cache");
10 if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
11 exit; // finish preflight CORS requests here
12 }
13 if ( !empty($_REQUEST[ 'debug' ]) ) {
14 $random = rand(0, intval($_REQUEST[ 'debug' ]) );
15 if ( $random === 0 ) {
16 header("HTTP/1.0 500 Internal Server Error");
17 exit;
18 }
19 }
20 // header("HTTP/1.0 500 Internal Server Error");
21 // exit;
22 // 5 minutes execution time
23 @set_time_limit(5 * 60);
24 // Uncomment this one to fake upload time
25 // usleep(5000);
26 // Settings
27 // $targetDir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload";
28 $targetDir = './Fadonghui/College/uploadfile/cache/';
29 $uploadDir = './Fadonghui/College/uploadfile/cache/';
30 $cleanupTargetDir = true; // 开启文件缓存删除
31 $maxFileAge = 60*60*24; // 文件缓存时间超过时间自动删除
32 // 验证缓存目录是否存在不存在创建
33 if (!file_exists($targetDir)) {
34 @mkdir($targetDir);
35 }
36 // 验证缓存目录是否存在不存在创建
37 if (!file_exists($uploadDir)) {
38 @mkdir($uploadDir);
39 }
40 // Get 或 file 方式获取文件名
41 if (isset($_REQUEST["name"])) {
42 $fileName = $_REQUEST["name"];
43 } elseif (!empty($_FILES)) {
44 $fileName = $_FILES["file"]["name"];
45 } else {
46 $fileName = uniqid("file_");
47 }
48 $oldName = $fileName;//记录文件原始名字
49 $filePath = $targetDir . $fileName;
50 // $uploadPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
51 // Chunking might be enabled
52 $chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
53 $chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 1;
54 // 删除缓存校验
55 if ($cleanupTargetDir) {
56 if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
57 die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
58 }
59 while (($file = readdir($dir)) !== false) {
60 $tmpfilePath = $targetDir . $file;
61 // If temp file is current file proceed to the next
62 if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
63 continue;
64 }
65 // Remove temp file if it is older than the max age and is not the current file
66 if (preg_match('/\.(part|parttmp|mp4)$/', $file) && (@filemtime($tmpfilePath) < time() - $maxFileAge)) {
67 @unlink($tmpfilePath);
68 }
69 }
70 closedir($dir);
71 }
72 // 打开并写入缓存文件
73 if (!$out = @fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
74 die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
75 }
76 if (!empty($_FILES)) {
77 if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
78 die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
79 }
80 // Read binary input stream and append it to temp file
81 if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
82 die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
83 }
84 } else {
85 if (!$in = @fopen("php://input", "rb")) {
86 die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
87 }
88 }
89 while ($buff = fread($in, 4096)) {
90 fwrite($out, $buff);
91 }
92 @fclose($out);
93 @fclose($in);
94 rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");
95 $index = 0;
96 $done = true;
97 for( $index = 0; $index < $chunks; $index++ ) {
98 if ( !file_exists("{$filePath}_{$index}.part") ) {
99 $done = false;
100 break;
101 }
102 }
103 //文件全部上传 执行合并文件
104 if ( $done ) {
105 $pathInfo = pathinfo($fileName);
106 $hashStr = substr(md5($pathInfo['basename']),8,16);
107 $hashName = time() . $hashStr . '.' .$pathInfo['extension'];
108 $uploadPath = $uploadDir .$hashName;
109 if (!$out = @fopen($uploadPath, "wb")) {
110 die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
111 }
112 if ( flock($out, LOCK_EX) ) {
113 for( $index = 0; $index < $chunks; $index++ ) {
114 if (!$in = @fopen("{$filePath}_{$index}.part", "rb")) {
115 break;
116 }
117 while ($buff = fread($in, 4096)) {
118 fwrite($out, $buff);
119 }
120 @fclose($in);
121 @unlink("{$filePath}_{$index}.part");
122 }
123 flock($out, LOCK_UN);
124 }
125 @fclose($out);
126 /*/腾讯云--对象存储
127 vendor('TencentYun/TencentYunSendFile');
128 $Yun = new \TencentYunSendFile();
129 $res = $Yun->uploadYun(array('tmp_name'=>$uploadPath,'name'=>$hashName),'video');
130 var_dump($res);*/
131 //引用第三方类库
132 /*vendor('getid3.getid3');
133 $getID3 = new \getID3(); //实例化类
134 $ThisFileInfo = $getID3->analyze($uploadPath);//分析文件*/
135 $response = array(
136 'success'=>true,
137 'oldName'=>$oldName,
138 //'filePaht'=>$hashName,
139 //'filePaht'=>substr($uploadPath,1),
140 'fileSuffixes'=>$pathInfo['extension'],
141 'time' =>$ThisFileInfo['playtime_string'],
142 );
143 //删除源文件
144 /*unlink($uploadPath);*/
145 die(json_encode($response));
146 }
147 // Return Success JSON-RPC response
148 die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');
149 }
欢迎订阅
以上是关于php大文件上传的主要内容,如果未能解决你的问题,请参考以下文章