php+js實現文件分塊上傳

咱們在上傳大文件時,可能會因爲服務器的緣由致使文件上傳失敗,文件過大時因爲服務器的配置或響應事件過長致使上傳文件失敗,這時候咱們能夠將一個大的文件分爲若干塊,而後分批次上傳到服務端,當全部文件塊上傳完成後再由服務器將各個文件塊整合成咱們上傳的文件php

一:分塊上傳流程:前端

1:由前端js將上傳的文件信息進行切割成若干塊,而後循環將若干塊的文件塊上傳到服務端json

2:服務端接收到文件塊信息後保存起來,當全部文件塊上傳完畢後,將全部上傳的文件塊整合成文件並保存起來瀏覽器

二:實現代碼:服務器

1:HTMLapp

<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>

2:JSthis

//獲取節點
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 = "";
    }
}

3:PHPspa

(1):上傳類:rest

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);
        }
    }
}

調用上傳類code

$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);

根據如上步驟就能夠實現將文件分紅若干塊進行上傳功能

相關文章
相關標籤/搜索