php h5 实现分片上传

前端

<meta charset="utf-8" />

<style>

body{


    font-family:Arial;


}


form{


    margin:50pxauto;


    width:600px;


}


input[type="button"]{


    cursor:pointer;


}


table{


    display:none;


    margin-top:15px;


    border:1pxsolid#ddd;


    border-collapse:collapse;


}


table th{


    color:#666;


}


table td, table th{


    padding:5px;


    border:1pxsolid#ddd;


    text-align:center;


    font-size:14px;


}
</style>
<form method="post" id="myForm" action="./fileTest.php" enctype="multipart/form-data">
    <input type="file" id="myFile" multiple="">
    <!-- 上传的文件列表 -->
    <table id="upload-list">
        <thead>
            <tr>
                <th width="35%">文件名</th>
                <th width="15%">文件类型</th>
                <th width="15%">文件大小</th>
                <th width="20%">上传进度</th>
                <th width="15%">
                    <input type="button" id="upload-all-btn" value="全部上传">
                </th>
            </tr>
        </thead>
        <tbody></tbody>
    </table>
</form>

<script src="./js/jquery.min.js" type="text/javascript"></script>
<script>

//全部上传操作


$('#upload-all-btn').live('click',function(){


    //未选择文件


    if(!$('#myFile').val()){


        $('#myFile').focus();


    }


    //模拟点击其他可上传的文件


    else{


        $('#upload-list .upload-item-btn').each(function(){


            $(this).click();


        });


    }


});




// 选择文件-显示文件信息

var uploadItem=[];
$('#myFile').change(function(e){


    var file,


        //uploadItemTpl=$('#file-upload-tpl').html(),
    
        uploadItemTpl = '<tr> <td width="35%">{{fileName}}</td><td width="15%">{{fileType}}</td><td width="15%">{{fileSize}}</td> <td width="20%" class="upload-progress">{{progress}}</td> <td width="15%"><input type="button" class="upload-item-btn" data-name="{{fileName}}" data-size="{{fileSize}}" data-state="default"    value="{{uploadVal}}"></td> </tr>',

        size,


        percent,


        progress='未上传',


        uploadVal='开始上传';




    for(var i=0,j=this.files.length;i<j;++i){


        file=this.files[i];




        percent=0;


        progress='未上传';


        uploadVal='开始上传';




        //计算文件大小


        size=file.size>1024?file.size/1024>1024?file.size/(1024*1024)>1024?(file.size/


            (1024*1024*1024)).toFixed(2)+'GB':(file.size/(1024*1024)).toFixed(2)+'MB':(file


            .size/1024).toFixed(2)+'KB':(file.size).toFixed(2)+'B';




        //初始通过本地记录,判断该文件是否曾经上传过


        percent=window.localStorage.getItem(file.name+'_p');


    console.log(percent);

        if(percent&&percent!=='100.0'){

            progress='已上传'+percent+'%';


            uploadVal='继续上传';


        }




        //更新文件信息列表

console.log(file);
        uploadItem.push(uploadItemTpl.replace(/{{fileName}}/g,file.name).replace('{{fileType}}',file.type||file.name.match(/\.\w+$/)+'文件').replace(/{{fileSize}}/g,size).replace('{{progress}}',progress).replace('{{totalSize}}',file.size).replace('{{uploadVal}}',uploadVal));


    }




    $('#upload-list').children('tbody').html(uploadItem.join('')).end().show();


});




/**


*
 上传文件时,提取相应匹配的文件项


*
 @param  {String} fileName   需要匹配的文件名


*
 @return {FileList}          匹配的文件项目


*/


function findTheFile(fileName){


    var files=$('#myFile')[0].files,theFile;



    for(var i=0,j=files.length;i<j;++i){

        if(files[i].name===fileName){


            theFile=files[i];


            break;


        }


    }



    return theFile?theFile:[];


}




//上传文件


$('.upload-item-btn').live('click',function(e){


    var $this=$(this),


        state=$this.attr('data-state'),


        msg={


            done:'上传成功',


            failed:'上传失败',


            in:'上传中...',


            paused:'暂停中...'


        },


        fileName=$this.attr('data-name'),


        $progress=$this.closest('tr').find('.upload-progress'),


        eachSize=1024,


        totalSize=$this.attr('data-size'),


        chunks=Math.ceil(totalSize/eachSize),


        percent,


        chunk,


        //暂停上传操作


        isPaused=0;




    //进行暂停上传操作


    //未实现,这里通过动态的设置isPaused值并不能阻止下方ajax请求的调用


    if(state==='uploading'){


        $this.val('继续上传').attr('data-state','paused');


        $progress.text(msg['paused']+percent+'%');


        isPaused=1;


        console.log('暂停:',isPaused);


    }


    //进行开始/继续上传操作


    else if(state==='paused' || state==='default'){


        $this.val('暂停上传').attr('data-state','uploading');


        isPaused=0;


    }




    //第一次点击上传


    startUpload('first');




    //上传操作 times: 第几次




    function startUpload(times){


        //上传之前查询是否以及上传过分片


        chunk=window.localStorage.getItem(fileName+'_chunk')||0;


        chunk=parseInt(chunk,10);


        //判断是否为末分片


        var isLastChunk=(chunk==(chunks-1)?1:0);




        //如果第一次上传就为末分片,即文件已经上传完成,则重新覆盖上传


        if(times==='first'&&isLastChunk===1){


            window.localStorage.setItem(fileName+'_chunk',0);


            chunk=0;


            isLastChunk=0;


        }




        //设置分片的开始结尾


        var blobFrom=chunk*eachSize,//分段开始


            blobTo=(chunk+1)*eachSize>totalSize?totalSize:(chunk+1)*eachSize,//分段结尾


            percent=(100*blobTo/totalSize).toFixed(1),//已上传的百分比


            timeout=5000,//超时时间

          fd=new FormData($('#myForm')[0]);

        fd.append('theFile',findTheFile(fileName).slice(blobFrom,blobTo));//分好段的文件
        //fd.append('theFile',123);

        fd.append('fileName',fileName);//文件名


        fd.append('totalSize',totalSize);//文件总大小


        fd.append('isLastChunk',isLastChunk);//是否为末段


        fd.append('isFirstUpload',times==='first'?1:0);//是否是第一段(第一次上传)
          var xhr = new XMLHttpRequest();
          xhr.open('POST', 'fileTest.php', true);
          
          xhr.upload.onprogress = function(e) {
            if (e.lengthComputable) {
              var percentComplete = (e.loaded / e.total) * 100;
              console.log(percentComplete + '% uploaded');
            }
          };

          xhr.onload = function() {
          rs=JSON.parse(this.response);




                //上传成功


                if(rs.status===200){


                    //记录已经上传的百分比


                    window.localStorage.setItem(fileName+'_p',percent);




                    //已经上传完毕


                    if(chunk===(chunks-1)){


                        $progress.text(msg['done']);


                        $this.val('已经上传').prop('disabled',true).css('cursor','not-allowed');


                        if(!$('#upload-list').find('.upload-item-btn:not(:disabled)').length){


                            $('#upload-all-btn').val('已经上传').prop('disabled',true).css('cursor',


                                'not-allowed');


                        }


                    }else{


                        //记录已经上传的分片


                        window.localStorage.setItem(fileName+'_chunk',++chunk);




                        $progress.text(msg['in']+percent+'%');


                        //这样设置可以暂停,但点击后动态的设置就暂停不了..


                        //
 if (chunk == 10) {


                        //    
 isPaused = 1;


                        //
 }


                        console.log(isPaused);


                        if(!isPaused){


                            startUpload();


                        }




                    }


                }


                //上传失败,上传失败分很多种情况,具体按实际来设置


                else if(rs.status===500){


                    $progress.text(msg['failed']);


                }
          /**
            if (this.status == 200) {
              var resp = JSON.parse(this.response);

              console.log('Server got:', resp);

              var image = document.createElement('img');
              image.src = resp.dataUrl;
              document.body.appendChild(image);
            };
            **/
          };

          xhr.send(fd);
            

/*
            fd=new FormData($('#myForm')[0]);

        fd.append('theFile',findTheFile(fileName).slice(blobFrom,blobTo));//分好段的文件
        //fd.append('theFile',123);

        fd.append('fileName',fileName);//文件名


        fd.append('totalSize',totalSize);//文件总大小


        fd.append('isLastChunk',isLastChunk);//是否为末段


        fd.append('isFirstUpload',times==='first'?1:0);//是否是第一段(第一次上传)

*/

        //上传


      /*  $.ajax({


            type:'post',


            url:'./fileTest.php',


            data:fd,


            processData:false,


            contentType:false,


            timeout:timeout,


            success:function(rs){


                rs=JSON.parse(rs);




                //上传成功


                if(rs.status===200){


                    //记录已经上传的百分比


                    window.localStorage.setItem(fileName+'_p',percent);




                    //已经上传完毕


                    if(chunk===(chunks-1)){


                        $progress.text(msg['done']);


                        $this.val('已经上传').prop('disabled',true).css('cursor','not-allowed');


                        if(!$('#upload-list').find('.upload-item-btn:not(:disabled)').length){


                            $('#upload-all-btn').val('已经上传').prop('disabled',true).css('cursor',


                                'not-allowed');


                        }


                    }else{


                        //记录已经上传的分片


                        window.localStorage.setItem(fileName+'_chunk',++chunk);




                        $progress.text(msg['in']+percent+'%');


                        //这样设置可以暂停,但点击后动态的设置就暂停不了..


                        //
 if (chunk == 10) {


                        //    
 isPaused = 1;


                        //
 }


                        console.log(isPaused);


                        if(!isPaused){


                            startUpload();


                        }




                    }


                }


                //上传失败,上传失败分很多种情况,具体按实际来设置


                else if(rs.status===500){


                    $progress.text(msg['failed']);


                }


            },


            error:function(){


                $progress.text(msg['failed']);


            }


        });*/


    }


});

</script>

后台

fileTest.php

<?php


    header('Content-type:text/plain; charset=utf-8');
/*
print_r($_FILES);
 
print_r($_REQUEST);
*/
    $files=$_FILES['theFile'];


    $fileName=iconv('utf-8','gbk',$_REQUEST['fileName']);


    $totalSize=$_REQUEST['totalSize'];


    $isLastChunk=$_REQUEST['isLastChunk'];


    $isFirstUpload=$_REQUEST['isFirstUpload'];


 


    if($_FILES['theFile']['error']>0){


        $status=500;


    }else{


        //此处为一般的文件上传操作


        /**
 if (!move_uploaded_file($_FILES['theFile']['tmp_name'], 'upload/'. $_FILES['theFile']['name'])) {


        //    
 $status = 501;


        //
 } else {


        //    
 $status = 200;


        //
 }**/


 


        //以下部分为文件断点续传操作


        //如果第一次上传的时候,该文件已经存在,则删除文件重新上传


        if($isFirstUpload=='1'&&file_exists('upload/'.$fileName)&&filesize('upload/'.$fileName)==$totalSize){


            unlink('upload/'.$fileName);


        }


 


        //否则继续追加文件数据

        if(!file_put_contents('upload/'.$fileName,file_get_contents($_FILES['theFile']['tmp_name']),FILE_APPEND)){


            $status=501;


        }else{


            //在上传的最后片段时,检测文件是否完整(大小是否一致)


            if($isLastChunk==='1'){


                if(filesize('upload/'.$fileName)==$totalSize){


                    $status=200;


                }else{


                    $status=502;


                }


            }else{


                $status=200;


            }


        }


    }


 


    echo json_encode(array(


        'status'=>$status,


        'totalSize'=>filesize('upload/'.$fileName),


        'isLastChunk'=>$isLastChunk


    ));


 


?>

  

posted on 2017-06-10 11:16  小乔流水人家  阅读(459)  评论(0)    收藏  举报

导航