PHP大文件分割上传 PHP分片上传


Posted in PHP onAugust 28, 2017

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

upload_max_filesize = 2M //PHP最大能接受的文件大小
post_max_size = 8M //PHP能收到的最大POST值'
memory_limit = 128M //内存上限
max_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代码

前端部分代码

<!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部分代码

<?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();

本文已被整理到了《php文件上传操作汇总》 ,更多精彩内容,欢迎大家学习阅读。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
php 应用程序安全防范技术研究
Sep 25 PHP
使用array mutisort 实现按某字段对数据排序
Jun 18 PHP
Apache实现Web Server负载均衡详解(不考虑Session版)
Jul 05 PHP
PHP将二维数组某一个字段相同的数组合并起来的方法
Feb 26 PHP
微信支付开发订单查询实例
Jul 12 PHP
PHP实现表单提交时去除斜杠的方法
Dec 26 PHP
PHP正则匹配反斜杠'\'和美元'$'的方法
Feb 08 PHP
php readfile下载大文件失败的解决方法
May 22 PHP
PHP实现求解最长公共子串问题的方法
Nov 17 PHP
php中通用的excel导出方法实例
Dec 30 PHP
使用swoole 定时器变更超时未支付订单状态的解决方案
Jul 24 PHP
thinkphp5.1框架模板赋值与变量输出示例
May 25 PHP
thinkphp ajaxfileupload实现异步上传图片的示例
Aug 28 #PHP
PHP实现超简单的SSL加密解密、验证及签名的方法示例
Aug 28 #PHP
PHP实现的简单对称加密与解密方法实例小结
Aug 28 #PHP
php检查函数必传参数是否存在的实例详解
Aug 28 #PHP
基于PHP的加载类操作以及其他两种魔术方法的应用实例
Aug 28 #PHP
Laravel学习教程之从入口到输出过程详解
Aug 27 #PHP
PHP使用栈解决约瑟夫环问题算法示例
Aug 27 #PHP
You might like
解析PHP中如何将数组变量写入文件
2013/06/06 PHP
PHP JS Ip地址及域名格式检测代码
2013/09/27 PHP
php使用gettimeofday函数返回当前时间并存放在关联数组里
2015/03/19 PHP
启用Csrf后POST数据时出现的400错误
2015/07/05 PHP
php 无限分类 树形数据格式化代码
2016/10/11 PHP
PHP基于socket实现客户端和服务端通讯功能
2017/07/13 PHP
ThinkPHP框架下微信支付功能总结踩坑笔记
2019/04/10 PHP
phpinfo的知识点总结
2019/10/10 PHP
TNC vs BOOM BO3 第二场2.13
2021/03/10 DOTA
怎么让脚本或里面的函数在所有图片都载入完毕的时候执行
2006/10/17 Javascript
另类调用flash无须激活的方法
2006/12/27 Javascript
自写简单JS判断是否已经弹出页面
2010/10/20 Javascript
固定背景实现的背景滚动特效示例分享
2013/05/19 Javascript
js使用removeChild方法动态删除div元素
2014/08/01 Javascript
JavaScript strike方法入门实例(给字符串加上删除线)
2014/10/17 Javascript
JavaScript通过字符串调用函数的实现方法
2015/03/18 Javascript
4种JavaScript实现简单tab选项卡切换的方法
2016/01/06 Javascript
下雪了 javascript实现雪花飞舞
2020/08/02 Javascript
vue用addRoutes实现动态路由的示例
2017/09/15 Javascript
浅谈Vue.js中ref ($refs)用法举例总结
2017/12/19 Javascript
在Vue组件中获取全局的点击事件方法
2018/09/06 Javascript
仅用500行Python代码实现一个英文解析器的教程
2015/04/02 Python
浅谈numpy数组中冒号和负号的含义
2018/04/18 Python
对python调用RPC接口的实例详解
2019/01/03 Python
django 快速启动数据库客户端程序的方法示例
2019/08/16 Python
用Python实现校园通知更新提醒功能
2019/11/23 Python
python利用xlsxwriter模块 操作 Excel
2020/10/14 Python
html5+css3进度条倒计时动画特效代码【推荐】
2016/03/08 HTML / CSS
详解Html5页面实现下载文件(apk、txt等)的三种方式
2018/10/22 HTML / CSS
吃透移动端 1px的具体用法
2019/12/16 HTML / CSS
介绍一下linux的文件权限
2012/02/15 面试题
初中数学教学反思
2014/01/16 职场文书
多媒体教室标语
2014/06/26 职场文书
学校读书活动总结
2014/06/30 职场文书
2015年全民国防教育日活动总结
2015/03/23 职场文书
2016年基层党组织创先争优承诺书
2016/03/25 职场文书