PHP大文件分割分片上传实现代码


Posted in PHP onDecember 09, 2020

服务端为什么不能直接传大文件?跟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 相关文章推荐
实现dedecms全站URL静态化改造的代码
Mar 29 PHP
php设计模式 Composite (组合模式)
Jun 26 PHP
php4与php5的区别小结(配置异同)
Dec 20 PHP
php include和require的区别深入解析
Jun 17 PHP
php使用fopen创建utf8编码文件的方法
Oct 31 PHP
PHP实现的简单mock json脚本分享
Feb 10 PHP
Laravel中使用阿里云OSS Composer包分享
Feb 10 PHP
PHP输出两个数字中间有多少个回文数的方法
Mar 23 PHP
php使用curl打开https网站的方法
Jun 17 PHP
PHP常用的排序和查找算法
Aug 06 PHP
PHP实现基于图的深度优先遍历输出1,2,3...n的全排列功能
Nov 10 PHP
laravel实现按时间日期进行分组统计方法示例
Mar 23 PHP
PHP rsa加密解密算法原理解析
Dec 09 #PHP
PHP如何解决微信文章图片防盗链
Dec 09 #PHP
PHP sdk文档处理常用代码示例解析
Dec 09 #PHP
PHP sdk实现在线打包代码示例
Dec 09 #PHP
基于PHP实现生成随机水印图片
Dec 09 #PHP
PHP实现腾讯短网址生成api接口实例
Dec 08 #PHP
win10下 php安装seaslog扩展的详细步骤
Dec 04 #PHP
You might like
PHP获取当前文件所在目录 getcwd()函数
2009/05/13 PHP
PHP中foreach循环中使用引用要注意的地方
2011/01/02 PHP
PHP跨时区(UTC时间)应用解决方案
2013/01/11 PHP
基于PHP中的常用函数回顾
2013/07/11 PHP
php不允许用户提交空表单(php空值判断)
2013/11/12 PHP
php+mysql数据库实现无限分类的方法
2014/12/12 PHP
PHP中iconv函数知识汇总
2015/07/02 PHP
php session 写入数据库
2016/02/13 PHP
php实现自定义中奖项数和概率的抽奖函数示例
2017/05/26 PHP
ThinkPHP5&amp;5.1框架关联模型分页操作示例
2019/08/03 PHP
PHP tp5中使用原生sql查询代码实例
2020/10/28 PHP
自动更新作用
2006/10/08 Javascript
Jquery 弹出层插件实现代码
2009/10/24 Javascript
js实现图片无缝滚动特效
2020/03/19 Javascript
深入浅析search 搜索框的写法
2016/08/02 Javascript
浅谈Web页面向后台提交数据的方式和选择
2016/09/23 Javascript
jQuery实现鼠标滑过图片移动特效
2016/12/08 Javascript
vue2.0使用swiper组件实现轮播效果
2017/11/27 Javascript
Ant Design的Table组件去除
2020/10/24 Javascript
Python中os和shutil模块实用方法集锦
2014/05/13 Python
Python实现提取文章摘要的方法
2015/04/21 Python
Python cookbook(数据结构与算法)实现查找两个字典相同点的方法
2018/02/18 Python
Python3.5局部变量与全局变量作用域实例分析
2019/04/30 Python
python numpy 常用随机数的产生方法的实现
2019/08/21 Python
python对Excel按条件进行内容补充(推荐)
2019/11/24 Python
用HTML5制作一个简单的桌球游戏的教程
2015/05/12 HTML / CSS
Chain Reaction Cycles俄罗斯:世界上最大的在线自行车商店
2019/08/27 全球购物
怎样让char类型的东西转换成int类型
2013/12/09 面试题
机械专业毕业生自荐信
2013/11/02 职场文书
2013年学期结束动员演讲稿
2014/01/07 职场文书
校园公益广告语
2014/03/13 职场文书
奥巴马的演讲稿
2014/05/15 职场文书
县委班子四风对照检查材料思想汇报
2014/09/29 职场文书
龙猫观后感
2015/06/09 职场文书
公司周年庆典致辞
2015/07/30 职场文书
Hive导入csv文件示例
2022/06/25 数据库