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函数
May 31 PHP
PHP警告Cannot use a scalar value as an array的解决方法
Jan 11 PHP
PHP 过滤页面中的BOM(实现代码)
Jun 29 PHP
PHP中捕获超时事件的方法实例
Feb 12 PHP
PHP中把数据库查询结果输出为json格式简单实例
Apr 09 PHP
js代码实现微博导航栏
Jul 30 PHP
WordPress中用于获取及自定义头像图片的PHP脚本详解
Dec 17 PHP
PHP框架性能测试报告
May 08 PHP
PHP微信公众号自动发送红包API
Jun 01 PHP
PHP实现mysqli批量执行多条语句的方法示例
Jul 22 PHP
PHP十六进制颜色随机生成器功能示例
Jul 24 PHP
TP5框架model常见操作示例小结【增删改查、聚合、时间戳、软删除等】
Apr 05 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使用Mysql事务实例解析
2014/09/08 PHP
教你识别简单的免查杀PHP后门
2015/09/13 PHP
php封装的pdo数据库操作工具类与用法示例
2019/05/08 PHP
获取任意Html元素与body之间的偏移距离 offsetTop、offsetLeft (For:IE5+ FF1 )[
2006/12/22 Javascript
不错的JS中变量相关的细节分析
2007/08/13 Javascript
jquery EasyUI的formatter格式化函数代码
2011/01/12 Javascript
jquery实现每个数字上都带进度条的幻灯片
2013/02/20 Javascript
jquery select多选框的左右移动 具体实现代码
2013/07/03 Javascript
js动态生成指定行数的表格
2013/07/11 Javascript
让jQuery与其他JavaScript库并存避免冲突的方法
2013/12/23 Javascript
JavaScript两种跨域技术全面介绍
2014/04/16 Javascript
js中string转int把String类型转化成int类型
2014/08/13 Javascript
Node.js和MongoDB实现简单日志分析系统
2015/04/25 Javascript
jquery validate和jquery form 插件组合实现验证表单后AJAX提交
2015/08/26 Javascript
Express之托管静态文件的方法
2018/06/01 Javascript
Javascript格式化并高亮xml字符串的方法及注意事项
2018/08/13 Javascript
vue 实现Web端的定位功能 获取经纬度
2019/08/08 Javascript
Vue v-bind动态绑定class实例方法
2020/01/15 Javascript
JS数组降维的实现Array.prototype.concat.apply([], arr)
2020/04/28 Javascript
Vue 打包的静态文件不能直接运行的原因及解决办法
2020/11/19 Vue.js
python装饰器初探(推荐)
2016/07/21 Python
django静态文件加载的方法
2018/05/20 Python
Python开发网站目录扫描器的实现
2019/02/21 Python
python绘制地震散点图
2019/06/18 Python
解决在pycharm运行代码,调用CMD窗口的命令运行显示乱码问题
2019/08/23 Python
python随机生成大小写字母数字混合密码(仅20行代码)
2020/02/01 Python
Anaconda的安装及其环境变量的配置详解
2020/04/22 Python
CSS3 translate导致字体模糊的实例代码
2019/08/30 HTML / CSS
欧缇丽加拿大官方网站:Caudalie加拿大
2019/07/18 全球购物
Sunglass Hut巴西网上商店:男女太阳镜
2020/10/04 全球购物
EM Cosmetics官网:由彩妆大神Michelle Phan创办的独立品牌
2020/04/27 全球购物
ruby如何进行集成操作?Ruby能进行多重继承吗?
2013/10/16 面试题
中文师范生自荐信
2014/01/30 职场文书
销售人员求职的自我评价分享
2014/03/15 职场文书
房地产置业顾问工作总结
2015/10/23 职场文书
Linux、ubuntu系统下查看显卡型号、显卡信息详解
2022/04/07 Servers