PHP+JS实现文件分块上传的示例代码

 更新时间:2022年11月04日 11:05:07   作者:huaweichenai  
我们在上传大文件时,可能会由于服务器的原因导致文件上传失败,文件过大时由于服务器的配置或响应事件过长导致上传文件失败,这时候我们可以将一个大的文件分为若干块,然后分批次上传到服务端。本文介绍了实现的方法,需要的可以参考一下

我们在上传大文件时,可能会由于服务器的原因导致文件上传失败,文件过大时由于服务器的配置或响应事件过长导致上传文件失败,这时候我们可以将一个大的文件分为若干块,然后分批次上传到服务端,当所有文件块上传完成后再由服务器将各个文件块整合成我们上传的文件

一、分块上传流程

1:由前端js将上传的文件信息进行切割成若干块,然后循环将若干块的文件块上传到服务端

2:服务端接收到文件块信息后保存起来,当所有文件块上传完毕后,将所有上传的文件块整合成文件并保存起来

二、实现代码

HTML

<input type="file" id="file">
<input type="button" id="upload" value="上传">
<input type="button" id="stop" value="停止">
<input type="button" id="restart" value="继续上传">
上传进度:<span id="progress"></span>

JS

//获取节点
var fileForm = document.getElementById("file");
var uploadBtn = document.getElementById('upload');
var stopBtn = document.getElementById('stop');
var restartBtn = document.getElementById('restart');
//定义常量
const LENGTH = 100 * 1024;//每个上传的文件块大小(100KB)
var start = 0;
var end = LENGTH + start;
var blob;
var is_stop = 0;
var blob_num = 1;
var file = null;
var upload_instance = new Upload();
//上传事件
uploadBtn.onclick = function () {
   upload_instance.addFileAndSend(fileForm);
   return false;
}
stopBtn.onclick = function () {
   upload_instance.stop();
   return false;
}
restartBtn.onclick = function () {
   upload_instance.start();
   return false;
}
function Upload() {
    //判断浏览器类型
    if (window.XMLHttpRequest){
        //IE7+, Firefox, Chrome, Opera, Safari
        var xhr=new XMLHttpRequest();
    }else{
        //IE6, IE5
        var xhr=new ActiveXObject("Microsoft.XMLHTTP");
    }
   //上传文件
   this.addFileAndSend = function (that) {
       file = that.files[0];
       blob = cutFile(file);
       //上传
       uploadFile(blob, file);
       blob_num += 1;
   }
   //停止文件上传
   this.stop = function () {
       xhr.abort();
       is_stop = 1;
   }
   this.start = function () {
       uploadFile(blob, file);
       is_stop = 0;
   }
   //切割文件
   function cutFile(file) {
       var file_blob = file.slice(start, end);
       start = end;
       end = start + LENGTH;
       return file_blob;
   };
    //上传文件
    function uploadFile(blob, file) {
        var form_data = new FormData();
        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', './test.php', false);
        xhr.onreadystatechange = function () {
            //获取上传进度
            if (total_blob_num == 1) {
                progressText = '100%';
            } else {
                progressText = (Math.min(100, (blob_num / total_blob_num) * 100)).toFixed(2) + '%';
            }
            var progress = document.getElementById('progress');
            progress.innerHTML = progressText;
            
            //循环执行上传,直到所有文件块上传完成
            var t = setTimeout(function () {
                if (start < file.size && is_stop == 0) {
                    blob = cutFile(file);
                    uploadFile(blob, file);
                    blob_num += 1;
                } else {
                    //所有文件块上传完成
                }
            }, 1000);
        }
        xhr.send(form_data);
        //每次文件块上传后,清空上传信息
        form_data = "";
    }
}

PHP

上传类

class Upload
{
    /**
     * @var string 上传目录
     */
    private $filepath = './upload'; //上传目录
    /**
     * @var string 块文件临时存储的位置
     */
    private $tmpPath;
    /**
     * @var integer 第几个文件块
     */
    private $blobNum;
    /**
     * @var integer //文件块总数
     */
    private $totalBlobNum;
    /**
     * @var string 上传文件名
     */
    private $fileName;
    public function __construct($tmpPath, $blobNum,$totalBlobNum,$fileName, $filepath = ''){
        if (!empty($filepath)) {
            $this->filepath = $filepath;
        }
        $this->tmpPath = $tmpPath;
        $this->blobNum = $blobNum;
        $this->totalBlobNum = $totalBlobNum;
        $this->fileName = $fileName;
        //保存文件块
        $this->moveFile();
        //保存文件
        $this->fileMerge();
    }
    private function fileMerge(){
        //当文件块都上传后将文件块整合成文件
        if($this->blobNum == $this->totalBlobNum){
            for($i=1; $i<= $this->totalBlobNum; $i++){
                $blob = '';
                $blob = file_get_contents($this->filepath.'/'. $this->fileName.'__'.$i);
                file_put_contents($this->filepath.'/'. $this->fileName, $blob, FILE_APPEND );
                unset($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);
    }
    //上传返回
    public function uploadReturn(){
        if($this->blobNum == $this->totalBlobNum){
            if(file_exists($this->filepath.'/'. $this->fileName)){
                return [
                    'code' => 2,
                    'message' => 'success',
                    'file_path' => 'http://'.$_SERVER['HTTP_HOST'].str_replace('.','',$this->filepath).'/'. $this->fileName,
                    'local_path' => str_replace('.','',$this->filepath).'/'. $this->fileName
                ];
            }
        }
        return [
            'code' => 1,
            'message' => 'waiting',
        ];
    }
    /**
     * 创建目录
     */
    private function touchDir(){
        if(!file_exists($this->filepath)){
            return mkdir($this->filepath);
        }
    }
}

调用上传类

$tmpName = $_FILES['file']['tmp_name'];
$blobNum = $_POST['blob_num'];
$totalBlobNum = $_POST['total_blob_num'];
$fileName = $_POST['file_name'];
$upload = new Upload($tmpName, $blobNum, $totalBlobNum, $fileName);
$data = $upload->uploadReturn();
header('Content-type: application/json');
return json_encode($data);

根据如上步骤就可以实现将文件分成若干块进行上传功能

到此这篇关于PHP+JS实现文件分块上传的示例代码的文章就介绍到这了,更多相关PHP JS文件分块上传内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 利用Laravel事件系统如何实现登录日志的记录详解

    利用Laravel事件系统如何实现登录日志的记录详解

    这篇文章主要给大家介绍了利用Laravel事件系统如何实现登录日志记录的相关资料,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-05-05
  • php获取英文姓名首字母的方法

    php获取英文姓名首字母的方法

    这篇文章主要介绍了php获取英文姓名首字母的方法,涉及php中explode及strtoupper函数操作php字符串分割及大小写转换的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • php删除路径下的所有文件夹和文件的代码

    php删除路径下的所有文件夹和文件的代码

    这篇文章主要介绍了php删除路径下的所有文件夹和文件的代码的相关资料(php清空目录代码),需要的朋友可以参考下
    2023-03-03
  • PHP结合jQuery实现找回密码

    PHP结合jQuery实现找回密码

    本文将使用PHP+Mysql+jQuery来实现一个密码找回的功能,分享给大家思路和具体的代码,有需要的小伙伴可以参考下。
    2015-07-07
  • php如何利用pecl安装mongodb扩展详解

    php如何利用pecl安装mongodb扩展详解

    这篇文章主要给大家介绍了关于php如何利用pecl安装mongodb扩展的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • 解析PHP高效率写法(详解原因)

    解析PHP高效率写法(详解原因)

    本篇文章是对PHP高效率写法进行了详细的分析介绍,需要的朋友参考下
    2013-06-06
  • PHP实现的消息实时推送功能【基于反ajax推送】

    PHP实现的消息实时推送功能【基于反ajax推送】

    这篇文章主要介绍了PHP实现的消息实时推送功能,结合实例形式分析了php基于反ajax推送实现的消息实时推送前台ajax提交、后台数据处理等相关操作技巧,需要的朋友可以参考下
    2018-03-03
  • 举例详解PHP脚本的测试方法

    举例详解PHP脚本的测试方法

    这篇文章主要介绍了PHP脚本的测试方法,包括使用PHPUNIT来对PHP代码进行单元测试的示例,需要的朋友可以参考下
    2015-08-08
  • php比较相似字符串的方法

    php比较相似字符串的方法

    这篇文章主要介绍了php比较相似字符串的方法,通过php中similar_text函数来实现字符串的相似性比较功能,需要的朋友可以参考下
    2015-06-06
  • PHP实现数据库统计时间戳按天分组输出数据的方法

    PHP实现数据库统计时间戳按天分组输出数据的方法

    这篇文章主要介绍了PHP实现数据库统计时间戳按天分组输出数据的方法,涉及php基于时间的运算与数据库查询相关操作技巧,需要的朋友可以参考下
    2017-10-10

最新评论