zoukankan      html  css  js  c++  java
  • JS 异步分段上传文件

    为了解决大文件上传 (PHP上传最大限制2GB)

    同时为了解决文件上传是对服务器造成的压力

    可以通过分段上传解决这个问题,这得益于HTML5开发的file API

    前台代码:

    引用了进度条插件myProgress.js

    <link href="__PUBLIC__/admin/css/myProgress.css" rel="stylesheet"> 
    <script src="__PUBLIC__/admin/js/jquery.myProgress.js"></script>
    
    <div>
        <div>
            <form id="myForm">
              <div>
                //上传文件时由用户指定文件名
                <label for="FileName">File Name</label>
                <input type="text" name="title" class="form-control" id="FileName">
              </div>
              <div>
                <label for="myFile">Chose File</label>
                <input type="file" id="myFile">
                <div class="progress-out" id="progress">
                    <div class="percent-show"><span>0</span>%</div>
                    <div class="progress-in"></div>
                </div>
              </div>
            </form>
            <button type="button" class="btn btn-default" id="btn">Submit</button>
        </div>
    </div>
    <script>
    //初始化上传
    function initUpload() {
        var chunk = 1000*1024;   //每片大小
        var input = document.getElementById("myFile");  //input file
        input.onchange = function (e) {
            //获得上传的文件
            var file = this.files[0];
            //如果大于指定大小 提示错误
            if(file.size > 1*1024*1024*1024){
                $('#help_msg').removeClass('help-block').addClass('error-block');
                return ;
            }else{
                $('#help_msg').css('display','none');
            }
            // 开启进度条
            $("#progress").css('display','block');
            $("#progress").myProgress({speed: 1000, percent: 0,  "200px", height: "12px"});
            
            var query = {};
            var chunks = [];
    
            if (!!file) {
                var start = 0;
                //文件分片
                for (var i = 0; i < Math.ceil(file.size / chunk); i++) {
                    //最后一段取文件的真实大小
                    var end = 0;
                    if(i == (Math.ceil(file.size / chunk)-1)){
                        end = file.size;
                    }else{
                        end = start + chunk;
                    }
                    chunks[i] = file.slice(start , end);
                    start = end;
                }
                
                // 采用post方法上传文件
                // url query上拼接以下参数,用于记录上传偏移
                // post body中存放本次要上传的二进制数据
                query = {
                    fileName : file.name,
                    fileSize: file.size,
                    dataSize: chunk,
                    nextOffset: 0
                }
    
                upload(chunks, query, successPerUpload);
            }
        }
    }
    
    // 执行上传
    function upload(chunks, query, cb) {
        //对象转字符串 用&连接
        var queryStr = Object.getOwnPropertyNames(query).map(key => {
            return key + "=" + query[key];
        }).join("&");
    
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "/Shop/index.php/Admin/File/upload_file?" + queryStr);
        xhr.overrideMimeType("application/octet-stream");
        
        //获取post body中二进制数据
        var index = Math.floor(query.nextOffset / query.dataSize);
        getFileBinary(chunks[index], function (binary) {
            if (xhr.sendAsBinary) {
                xhr.sendAsBinary(binary);
            } else {
                xhr.send(binary);
            }
    
        });
    
        xhr.onreadystatechange = function (e) {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    var resp = JSON.parse(xhr.responseText);
                    //通过返回数据更新进度条
                    var precent = Math.ceil((resp.offset / query.fileSize) * 100);
                    $("#progress").myProgress({speed: 1000, percent: precent,  "200px", height: "12px"});
                    // 接口返回nextoffset
                    // resp = {
                    //     isFinish:false,
                    //     offset:100*1024
                    // }
                    if (typeof cb === "function") {
                        cb.call(this, resp, chunks, query)
                    }
                }
            }
        }
    }
    
    // 每片上传成功后执行
    function successPerUpload(resp, chunks, query) {
        if (resp.isFinish === true) {
            //上传完成给出提示
            $('#help_msg').css('display','block').addClass('error-block').html('success!');
        } else {
            //未上传完毕
            query.nextOffset = resp.offset;
            upload(chunks, query, successPerUpload);
        }
    }
    
    // 获取文件二进制数据
    function getFileBinary(file, cb) {
        var reader = new FileReader();
        reader.readAsArrayBuffer(file);
        reader.onload = function (e) {
            if (typeof cb === "function") {
                cb.call(this, this.result);
            }
        }
    }
    //初始化上传
    initUpload();
    
    //ajax模拟提交表单
    $(function(){
        $('#btn').click(function(){
            var fd = new FormData(document.querySelector('#myForm'));
            var input = document.getElementById("myFile");    //input file
            var file = input.files[0];
            if(!file){
                $('#help_msg').css('display','block').addClass('error-block').html('please chose the file !');
                return ;
            }
            fd.append('FileName',file.name);
            fd.append('size',file.size);
            $.ajax({
                url : "/Shop/index.php/Admin/File/add",
                type: "POST",
                async : true,
                data: fd,
                processData: false,  // 不处理数据
                contentType: false,   // 不设置内容类型
                success : function(result){
                    console.log(result);
                    if(result.res == 1){
                        window.location.href = "http://localhost:8080/Shop/index.php/Admin/File/index";
                    }else{
                        $("#help_msg_1").css('display','block').html('upload faild ' + $result.msg);
                    }
                }
            });
        })
    })
    
    </script>

    后台PHP代码   

        public function add(){
            if($_POST){
                $Attach = D('Attachment');
                $file_path = './Upload/File/'.$_POST['FileName'];
                //如果是win系统将文件名改成GBK编码
                if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'){
                    $file_path = iconv('UTF-8', 'GBK', $file_path);
                }
                if(file_exists($file_path)){
                    //获得拓展名
                    $ext = strtolower(trim(substr(strrchr($_POST['FileName'], '.'), 1)));
                    //生成新的文件名
                    $url = './Upload/File/'.date("Ymdhms").rand(1000,9999).'.'.$ext;
                    $_POST['url'] = $url ;
                    //将上传的文件改名,将新的路径存入数据库
                    if(rename($file_path, $url)){
                        $res = $Attach -> add_file($_POST);
                        if($res['res']){
                            $log['remark'] = session('userinfo')['name'].'在'.date("Y-m-d H:i:s").'上传了文件';
                            D('ActionLog') -> add_log($log);
                            $this -> ajaxReturn(array('res' => 1));
                        }else{
                            $this -> ajaxReturn(array('res' => 0 , 'msg' => $res['msg']));
                        }
                    }
                }else{
                    $this -> ajaxReturn(array('res' => 0, 'msg' => '上传文件不存在'));
                }    
            }else{
                $this -> show();
            }
        }
        //异步分段上传文件
        public function upload_file(){
            
            $path = './Upload/File/'.$_GET['fileName'];
            if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'){
                $path = iconv('UTF-8', 'GBK', $path);
            }
            if(!file_exists($path)){
                $handle = fopen($path, "a+");
                fclose($handle);
            }
            file_put_contents($path, file_get_contents('php://input'),FILE_APPEND|LOCK_EX);
            $offset = filesize($path);
            if( $offset >= $_GET['fileSize'] ){
                 $this -> ajaxReturn(array('isFinish' => true));
            }else{
                $this -> ajaxReturn(array('isFinish' => false , 'offset' => $offset));
            }
        }
  • 相关阅读:
    服务器架构前面加了防火墙,Nginx如何获取客户端真实ip???
    Prometheus学习笔记(5)Grafana可视化展示
    Prometheus学习笔记(4)什么是pushgateway???
    Prometheus学习笔记(3)什么是node_exporter???
    Prometheus学习笔记(2)Prometheus部署
    Prometheus学习笔记(1)Prometheus架构简介
    Centos 7 中的ulimit -n 65535 对进程的文件句柄限制不生效??
    Jenkins实用发布与回滚PHP项目生产实践
    Ansible入门笔记(3)之Playbook
    Ansible入门笔记(2)之常用模块
  • 原文地址:https://www.cnblogs.com/xiaoliwang/p/8347231.html
Copyright © 2011-2022 走看看