zoukankan      html  css  js  c++  java
  • PHP大文件分割上传(分片上传)

    服务端为什么不能直接传大文件?跟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{
                 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=" 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();
  • 相关阅读:
    Android AHandle AMessage
    android java 与C 通过 JNI双向通信
    android 系统给应用的jar
    UE4 unreliable 同步问题
    UE4 difference between servertravel and openlevel(多人游戏的关卡切换)
    UE4 Run On owing Client解析(RPC测试)
    UE4 TSubclassOf VS Native Pointer
    UE4 内容示例网络同步Learn
    UE4 多人FPS VR游戏制作笔记
    UE4 分层材质 Layerd Materials
  • 原文地址:https://www.cnblogs.com/ghjbk/p/7443765.html
Copyright © 2011-2022 走看看