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 相关文章推荐
火车头discuz6.1 完美采集的php接口文件
Sep 13 PHP
PHP中将ip地址转成十进制数的两种实用方法
Aug 15 PHP
PHP采用自定义函数实现遍历目录下所有文件的方法
Aug 19 PHP
PHP访问Google Search API的方法
Mar 05 PHP
PHP判断是否连接上网络的方法
Jul 01 PHP
深入理解PHP之OpCode原理详解
Jun 01 PHP
简单PHP会话(session)说明介绍
Aug 21 PHP
详解PHP数据压缩、加解密(pack, unpack)
Dec 17 PHP
thinkPHP5.0框架API优化后的友好性分析
Mar 17 PHP
php中Ioc(控制反转)和Di(依赖注入)
May 07 PHP
PHP从尾到头打印链表实例讲解
Sep 27 PHP
TP5框架实现签到功能的方法分析
Apr 05 PHP
thinkphp ajaxfileupload实现异步上传图片的示例
Aug 28 #PHP
PHP实现超简单的SSL加密解密、验证及签名的方法示例
Aug 28 #PHP
PHP实现的简单对称加密与解密方法实例小结
Aug 28 #PHP
php检查函数必传参数是否存在的实例详解
Aug 28 #PHP
浅谈Laravel队列实现原理解决问题记录
Aug 19 #PHP
yii2 commands模式以及配置crontab定时任务的方法
Aug 19 #PHP
利用 fsockopen() 函数开放端口扫描器的实例
Aug 19 #PHP
You might like
基于Zend的Config机制的应用分析
2013/05/02 PHP
PHP生成自定义长度随机字符串的函数分享
2014/05/04 PHP
确保Laravel网站不会被嵌入到其他站点中的方法
2019/10/18 PHP
document.getElementById介绍
2011/09/13 Javascript
如何让页面在打开时自动刷新一次让图片全部显示
2012/12/17 Javascript
简单时间提示DEMO从0开始一直进行计时
2013/11/19 Javascript
jquery.post用法关于type设置问题补充
2014/01/03 Javascript
利用try-catch判断变量是已声明未声明还是未赋值
2014/03/12 Javascript
javascritp添加url参数将参数加入到url中
2014/09/25 Javascript
jquery+html5烂漫爱心表白动画代码分享
2015/08/24 Javascript
深入剖析JavaScript编程中的对象概念
2015/10/21 Javascript
将html页面保存成图片,图片写入pdf的实现方法(推荐)
2016/09/17 Javascript
jQuery表单验证之密码确认
2017/05/22 jQuery
react native仿微信PopupWindow效果的实例代码
2017/08/07 Javascript
vue项目tween方法实现返回顶部的示例代码
2018/03/02 Javascript
微信小程序实现刷脸登录
2018/05/25 Javascript
element ui 表格动态列显示空白bug 修复方法
2018/09/04 Javascript
微信小程序实现上传多个文件 超过10个
2020/03/30 Javascript
vue使用canvas实现移动端手写签名
2020/09/22 Javascript
python通过加号运算符操作列表的方法
2015/07/28 Python
Python 遍历子文件和所有子文件夹的代码实例
2016/12/21 Python
Python优先队列实现方法示例
2017/09/21 Python
对numpy中向量式三目运算符详解
2018/10/31 Python
python实现简单flappy bird
2018/12/24 Python
详解Python3 对象组合zip()和回退方式*zip
2019/05/15 Python
Python批量生成幻影坦克图片实例代码
2019/06/04 Python
Python查找不限层级Json数据中某个key或者value的路径方式
2020/02/27 Python
META-INF文件夹中的MANIFEST.MF的作用
2016/06/21 面试题
创业资金计划书
2014/02/06 职场文书
建筑专业毕业生求职信
2014/09/30 职场文书
党建工作整改措施
2014/10/28 职场文书
大客户经理岗位职责
2015/04/09 职场文书
大学生实习介绍信
2015/05/05 职场文书
酒店宣传语大全
2015/07/13 职场文书
MySQL读取JSON转换的方式
2022/03/18 MySQL
分析MySQL优化 index merge 后引起的死锁
2022/04/19 MySQL