PHP分片上传

2018-4-22 liyangweb.com 李杨 JavaScript

本文参考了下面的内容,但是测试中发现其中的代码有bug,我又拿出来重新整理了一下。

https://www.cnblogs.com/2017sss/p/6654659.html

PHP的上传受一些配置的影响,一般默认上传最大文件为2M,如果我们需要上传一个10M的文件怎么做呢?

简单实现的话,我们可以通过修改PHP的配置文件来实现:

upload_max_filesize = 2M //PHP最大能接受的文件大小
post_max_size = 8M //PHP能收到的最大POST值
memory_limit = 128M //内存上限
max_execution_time = 30 //最大执行时间
但是如果我们需要上传一个100M的文件呢?单纯修改上面的配置是不行的,即使测试中能把文件传上去,等到生产环境多个用户一起访问,服务器配置再强大也得挂掉。
所以我们就需要在前端把文件拆分开,也就是所谓的分片上传。

分片上传用到了一些HTML5的新特性,所以对于一些比较老的浏览器就不能用了,我们可以提示用户去下载现代浏览器,或者使用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{
            width: 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="width: 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();
        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 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','./upload.php',false);
            xhr.onreadystatechange  = function () {
                var progress;
                var progressObj = document.getElementById('finish');
                if(total_blob_num == blob_num){
                    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
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();


标签: PHP分片上传 js分片上传 PHP大文件上传

评论:

pikapnsk
2019-01-18 02:00
<a href="http://www.tomscave.com/adidas-samba-primeknit-fg-marr%C3%B3n-blanco-azul-butya">adidas samba primeknit fg marr贸n blanco azul</a> <a href="http://www.veronicaloman.com/gray-carolina-panthers-jersey-nflu">gray carolina panthers jersey</a> <a href="http://www.casagranderox.com/nike-hyperrev-2016-blu-cielo-blu-kurpesb">nike hyperrev 2016 blu cielo blu</a> <a href="http://www.elitoyreviews.com/nike-zoom-pegasus-33-verkauf-used-schuhed">nike zoom pegasus 33 verkauf used</a> <a href="http://www.grassmannword.com/adidas-yeezy-boost-350-triple-blanc-elephant-schuheg">adidas yeezy boost 350 triple blanc elephant</a> <a href="http://www.harryselite.com/unisex-nike-roshe-run-blum%C3%A4nner-gold-schwarz-kurpesd">unisex nike roshe run blum盲nner gold schwarz</a>
pikapnsk http://www.pikapnsk.com/
bringribben
2019-01-04 18:15
<a href="http://www.ictbel.com/nike-paul-rodriguez-9-womens-purple-skob">nike paul rodriguez 9 womens purple</a> <a href="http://www.ioioland.com/st-louis-blues-camo-hat-hata">st louis blues camo hat</a> <a href="http://www.sesliesenyurt.com/nike-air-max-shoes-for-ladies-2015-runninge">nike air max shoes for ladies 2015</a> <a href="http://www.wethinkjerky.com/nike-kobe-8-elite-svart-gull-jewelry-schuhea">nike kobe 8 elite svart gull jewelry</a> <a href="http://www.dadees.com/new-blance-620-b%C3%B8rn-lyser%C3%B8d-guld-scarpec">new blance 620 b酶rn lyser酶d guld</a> <a href="http://www.pickwickcrc.com/nike-air-max-2019-green-uk-shoeso">nike air max 2019 green uk</a>
bringribben http://www.bringribben.com/
vtgumc6t
2019-01-02 08:46
<a href="http://www.b7tb99r5.com/kvinders-nike-air-max-thea-print-fl%C3%A5den-bl%C3%A5-lyser%C3%B8d-kurpesc">kvinders nike air max thea print fl氓den bl氓 lyser酶d</a> <a href="http://www.0hicvn40.com/air-jordan-horizon-sort-mintgr%C3%B8n-schuhea">air jordan horizon sort mintgr酶n</a> <a href="http://www.1o5i1ylp.com/hommes-nike-sb-stefan-janoski-max-blanc-bleu-kurpesf">hommes nike sb stefan janoski max blanc bleu</a> <a href="http://www.yzdmnx48.com/adidas-gazelle-boost-verde-tea-chaussuresa">adidas gazelle boost verde tea</a> <a href="http://www.4vgdg8la.com/nike-air-max-zero-kvinners-gr%C3%A5-svart-kurpesg">nike air max zero kvinners gr氓 svart</a> <a href="http://www.svmn5v0b.com/air-jordan-retro-1-maschiota-verde-bianca-schuhee">air jordan retro 1 maschiota verde bianca</a>
vtgumc6t http://www.vtgumc6t.com/
nedshare
2019-01-02 07:50
<a href="http://www.ehomeoclinic.com/nfl-nike-buffalo-bills-83-andre-reed-royal-blue-backer-long-sleeve-t-shirt-nflw">nfl nike buffalo bills 83 andre reed royal blue backer long sleeve t shirt</a> <a href="http://www.geuwompo.com/nike-free-clearance-salg-chaussuresa">nike free clearance salg</a> <a href="http://www.inckua.com/nike-air-max-2015-gris-azul-butya">nike air max 2015 gris azul</a> <a href="http://www.infantocursos.com/nike-city-sandal-ii-barn-gr%C3%A5-gul-butyc">nike city sandal ii barn gr氓 gul</a> <a href="http://www.omegaspark.com/nike-shox-current-sko-salg-obuvf">nike shox current sko salg</a> <a href="http://www.radsportland.com/hommes-nike-free-5.0-noir-vert-kurpesa">hommes nike free 5.0 noir vert</a>
[url=http://www.nedshare.com/]nedshare[/url]
gkpassword
2018-12-30 19:53
<a href="http://www.lakefrontlane.com/jordan-5-fire-rojo-cdp-scarpea">jordan 5 fire rojo cdp</a> <a href="http://www.minickphoto.com/nike-lebron-soldier-10-brun-gr%C3%B8nn-chaussuresg">nike lebron soldier 10 brun gr酶nn</a> <a href="http://www.multinutwraps.com/adidas-nitrocharge-footbtutti-arancia-bianca-kurpese">adidas nitrocharge footbtutti arancia bianca</a> <a href="http://www.paulacorley.com/nike-dynamo-free-ps-kinder-rot-braun-obuva">nike dynamo free ps kinder rot braun</a> <a href="http://www.catcogroup.com/ralph-lauren-hommes-marron-blanc-polo-polo-stripes-long-sleeved-polot">ralph lauren hommes marron blanc polo polo stripes long sleeved</a> <a href="http://www.charlesklamut.com/air-jordan-6-retro-for-venta-ky-schuhed">air jordan 6 retro for venta ky</a>
gkpassword http://www.gkpassword.com/
天津网站建设
2018-09-21 17:47
感谢大佬分享,会常来的
代寫essay
2018-04-27 01:48
很好的分享,赞赞。

发表评论:

Powered by emlog 冀ICP备13011830号-1