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和ACCESS写聊天室(六)
Oct 09 PHP
Php Mssql操作简单封装支持存储过程
Dec 11 PHP
PHP序列号生成函数和字符串替换函数代码
Jun 07 PHP
php版本的cron定时任务执行器使用实例
Aug 19 PHP
10个实用的PHP正则表达式汇总
Oct 23 PHP
thinkphp中session和cookie无效的解决方法
Dec 19 PHP
PHP实现批量修改文件后缀名的方法
Jul 30 PHP
php根据日期或时间戳获取星座信息和生肖等信息
Oct 20 PHP
PHP用户注册邮件激活账户的实现代码
May 31 PHP
PHP 实现页面静态化的几种方法
Jul 23 PHP
tp5框架的增删改查操作示例
Oct 31 PHP
6个常见的 PHP 安全性攻击实例和阻止方法
Dec 16 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
smarty静态实验表明,网络上是错的~呵呵
2006/11/25 PHP
PHP面向对象精要总结
2014/11/07 PHP
推荐一本PHP程序猿都应该拜读的书
2014/12/31 PHP
thinkphp项目部署到Linux服务器上报错“模板不存在”如何解决
2016/04/27 PHP
PHP实现获取ip地址的5种方法,以及插入用户登录日志操作示例
2019/02/28 PHP
用jquery ajax获取网站Alexa排名的代码
2009/12/12 Javascript
让textarea自动调整大小的js代码
2011/04/12 Javascript
解析jquery中的ajax缓存问题
2013/12/19 Javascript
Javascript前端UI框架Kit使用指南之kitjs的对话框组件
2014/11/28 Javascript
限制上传文件大小和格式的jQuery插件实例
2015/01/24 Javascript
javascript学习笔记之函数定义
2015/06/25 Javascript
关于事件mouseover ,mouseout ,mouseenter,mouseleave的区别
2015/10/12 Javascript
JS实现模拟百度搜索“2012世界末日”网页地震撕裂效果代码
2015/10/31 Javascript
JavaScript+html5 canvas实现图片破碎重组动画特效
2016/02/22 Javascript
分离与继承的思想实现图片上传后的预览功能:ImageUploadView
2016/04/07 Javascript
jquery移除了live()、die(),新版事件绑定on()、off()的方法
2016/10/26 Javascript
微信小程序 Windows2008 R2服务器配置TLS1.2方法
2016/12/05 Javascript
浅谈angular2路由预加载策略
2017/10/04 Javascript
Vue 创建组件的两种方法小结(必看)
2018/02/23 Javascript
JavaScript实现表单注册、表单验证、运算符功能
2018/10/15 Javascript
JavaScript数组去重的方法总结【12种方法,号称史上最全】
2019/02/28 Javascript
element-ui多文件上传的实现示例
2019/04/10 Javascript
[01:24:51]2014 DOTA2华西杯精英邀请赛 5 25 LGD VS NewBee第二场
2014/05/26 DOTA
在python中只选取列表中某一纵列的方法
2018/11/28 Python
Python散点图与折线图绘制过程解析
2019/11/30 Python
Python文件时间操作步骤代码详解
2020/04/13 Python
python设置表格边框的具体方法
2020/07/17 Python
Perfumetrader荷兰:香水、化妆品和护肤品在线商店
2017/09/15 全球购物
洛杉矶生活休闲而精致的基础品牌:Mika Jaymes
2018/01/07 全球购物
Java面试题:Java类的Main方法如果是Private将会怎么样
2016/08/18 面试题
儿子婚宴答谢词
2014/01/09 职场文书
工作表现自我评价
2014/02/08 职场文书
员工保密协议书
2014/09/27 职场文书
店铺转让协议书
2014/12/02 职场文书
仓库保管员岗位职责
2015/02/09 职场文书
详解Laravel框架的依赖注入功能
2021/05/27 PHP