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程序
Feb 04 PHP
PHP中使用gettext解决国际化问题的例子(i18n)
Jun 13 PHP
php通过array_unshift函数添加多个变量到数组前端的方法
Mar 18 PHP
Ubuntu12下编译安装PHP5.3开发环境
Mar 27 PHP
php基于ob_start(ob_gzhandler)实现网页压缩功能的方法
Feb 18 PHP
php实现的错误处理封装类实例
Jun 20 PHP
IOS 开发之NSDictionary转换成JSON字符串
Aug 14 PHP
PHP实现的简单路由和类自动加载功能
Mar 13 PHP
Centos7 Yum安装PHP7.2流程教程详解
Jul 02 PHP
Yii框架参数配置文件params用法实例分析
Sep 11 PHP
php面试实现反射注入的详细方法
Sep 30 PHP
jQuery+PHP实现图片上传并提交功能
Jul 27 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
第八节 访问方式 [8]
2006/10/09 PHP
PHP APC缓存配置、使用详解
2014/03/06 PHP
如何让CI框架支持service层
2014/10/29 PHP
Zend Framework入门教程之Zend_Session会话操作详解
2016/12/08 PHP
PHP让网站移动访问更加友好方法
2019/02/14 PHP
js操作二级联动实现代码
2010/07/27 Javascript
window.addEventListener来解决让一个js事件执行多个函数
2012/12/26 Javascript
js复制网页内容并兼容各主流浏览器的代码
2013/12/17 Javascript
jQuery中Dom的基本操作小结
2014/01/23 Javascript
jquery 页面滚动到底部自动加载插件集合
2014/01/31 Javascript
javascript函数中参数传递问题示例探讨
2014/07/31 Javascript
jquery处理页面弹出层查询数据等待操作实例
2015/03/25 Javascript
JavaScript实现图片自动加载的瀑布流效果
2016/04/11 Javascript
jQuery实现的小图列表,大图展示效果幻灯片示例
2016/10/25 Javascript
微信公众号支付H5调用支付解析
2016/11/04 Javascript
详解A标签中href=&quot;&quot;的几种用法
2017/08/20 Javascript
Javascript中 toFixed四舍六入方法
2017/08/21 Javascript
nodejs中安装ghost出错的原因及解决方法
2017/10/23 NodeJs
js实现移动端轮播图
2020/12/21 Javascript
微信小程序实现同一页面取值的方法分析
2019/04/30 Javascript
JS Math对象与Math方法实例小结
2019/07/05 Javascript
在Vue mounted方法中使用data变量详解
2019/11/05 Javascript
Python表示矩阵的方法分析
2017/05/26 Python
深入了解Python中pop和remove的使用方法
2018/01/09 Python
详解Python下载图片并保存本地的两种方式
2019/05/15 Python
Python 实现将numpy中的nan和inf,nan替换成对应的均值
2020/06/08 Python
python读取图像矩阵文件并转换为向量实例
2020/06/18 Python
CSS3教程(1):什么是CSS3
2009/04/02 HTML / CSS
TALLY WEiJL法国网上商店:服装、时装及配饰
2019/08/31 全球购物
Fox Racing英国官网:越野摩托车和山地自行车服装
2020/02/26 全球购物
面向对象编程的优势是什么
2015/12/17 面试题
公司活动方案范文
2014/03/06 职场文书
“学雷锋活动月”总结
2014/03/09 职场文书
nginx搭建图片服务器的过程详解(root和alias的区别)
2021/03/31 Servers
浅谈resultMap的用法及关联结果集映射
2021/06/30 Java/Android
手把手带你彻底卸载MySQL数据库
2022/06/14 MySQL