PHP+JS大文件切割异步上传

用到的PHP文件系统函数

bool move_uploaded_file ( string filename , stringdestination ) 将上传的文件移动到新位置

bool file_exists ( string $filename ) 检查文件或目录是否存在。

[resource fopen ( string filename , stringmode [, bool use_include_path = false [, resourcecontext ]] )](http://php.net/manual/zh/function.fopen.php) 打开文件或者 URL

int filesize ( string $filename ) 取得文件大小

string fread ( resource handle , intlength ) 读取文件(可安全用于二进制文件)

int fwrite ( resource handle , stringstring [, int $length ] )写入文件(可安全用于二进制文件)

bool fclose ( resource $handle ) 关闭一个已打开的文件指针

[bool unlink ( string filename [, resourcecontext ] )](http://php.net/manual/zh/function.unlink.php) 删除文件

[string md5_file ( string filename [, boolraw_output = FALSE ] )](http://php.net/manual/zh/function.md5-file.php) 计算指定文件的 MD5 散列值


upload.html


<form method="post" enctype="multipart/form-data" class="form-horizontal" action="">

    <tableclass="table table-hover">

        <tr>

            <tdclass="right">

                <strong>上传App</strong>

            </td>

            <tdclass="left">

                <div id="progress">

                    <div id="finish" style="width: 0%;" progress="0"></div>

                </div>

                <span id="new_file">

                    <input type="file" value="" name="gz_app_b_android"  onchange="onchangeUpload(this,'finish','new_file')" class="input" size="50" id="file">

                </span>

                <input type="hidden" value="" name="gz_app_c_android" id="gz_app_c_android">

                <p class="help-block"></p>

            </td>

        </tr>

    </table>

</form>

<script type="text/javascript" src="__PUBLIC__/Js/upload.js"></script>

<script type="text/javascript" src="__PUBLIC__/Js/spark-md5.js"></script>


upload.js


function onchangeUpload(obj,progress_id,self_id)

{

    var blob= obj.files[0];

    browserMD5File(blob, function (err, md5) {

        //console.log(md5); // 97027eb624f85892c69c4bcec8ab0f11

        var time= Math.floor((new Date().valueOf())/ 1000);

        var bytesPerPiece= 1024 * 1024 * 2; // 文件切片大小定义.

        var totalPieces;

        var x= 4, y= 0;

        var rand= '';

        for (var i= 0; i< 5; i++) {

            rand+= parseInt(Math.random()* (x- y+ 1)+ y);

        }

        var start= 0;

        var end;

        var index= 1;

        var filesize= blob.size;

        var filename= time+ rand+ '.apk';

        var that= obj;

        //计算文件切片总数

        totalPieces= Math.ceil(filesize/ bytesPerPiece);

        var progress;

        var progressObj= document.getElementById(progress_id);

        //重新上传则清空进度条

        progress= '0%';

        progressObj.style.width= progress;

        var upload_status= true;

        while(start< filesize)

        {

             end= start+ bytesPerPiece;

            if (end> filesize) {

                  end= filesize;

            }

            var chunk= blob.slice(start, end);//切割文件

            // 兼容firefox

            /*if(blob.mozSlice){

            var chunk =  blob.mozSlice(startByte,endByte);

            }*/

            //传参

            var formData= new FormData();

            formData.append("file", chunk, filename+ index);

            formData.append("file_name", filename);

            formData.append("total_pieces", totalPieces);

            formData.append("now_pieces", index);

            formData.append("md5", md5);

            $.ajax({

                url: './asyncUploadAjax',

                type: 'POST',

                cache: false,

                data: formData,

                processData: false,

                contentType: false,

                async: true // true:异步,false:同步

            }).done(function (res) {

                if (JSON.parse(res).code== 1) {

                    progress= Math.min(100, ((JSON.parse(res).n+1)/ totalPieces)* 100)+ '%';

                    progressObj.style.width= progress;

                }else if (JSON.parse(res).code== 2) {

                    //判断是否有上传失败的节点

                    if(upload_status== true)

                    {

                        progress= '100%';

                        progressObj.style.width= progress;

                        document.getElementById(that.name).value= JSON.parse(res).file_path;

                        //清空file  防止将文件大小计算到表单里

                        document.getElementById(self_id).innerHTML= '<input type="file" value="" name="'+that.name+'" onchange="onchangeUpload(this,\''+progress_id+'\', \''+self_id+'\')"  class="input" size="50" id="file">';

                        alert(blob.name+ ' 上传完成');

                    }else{

                         alert(blob.name+ JSON.parse(res).msg);

                    }

                }else {

                      upload_status= false;

                }

            }).fail(function (res) {

                  upload_status= false;

            });

            start= end;

            index++;

        }

})

}


spark-md5.js


upload.php


/*

    * 异步上传

    * */

    public function asyncUploadAjax()

    {

        $data['code'] = 1;

        $data['msg'] = 'waiting for all';

        $data['file_path'] = '';

        $form_data = $_POST;

        $file = $_FILES;

        $new_file_path = $_SERVER['SINASRV_DATA_DIR'].'/'. $_FILES['file']['name'];

        if (move_uploaded_file($file['file']['tmp_name'], $new_file_path)) {

            //判断是否上传完成

            $status = self::checkUploadAccomplish($form_data['file_name'], $form_data['total_pieces']);

            if($status['status'])

            {

                //合并切片文件

                $file_path = self::mergeSlices($form_data['file_name'], $form_data['total_pieces']);

                //验证文件安全

                if(md5_file($file_path) == $form_data['md5'])

                {

                    $data['code'] = 2;

                    $data['msg'] = 'upload success';

                    $data['file_path'] = $file_path;

                }else{

                    $data['code'] = 0;

                    $data['msg'] = '文件不安全,请重新上传';

                }

            }else{

                $data['n'] = $status['n'];

            }

        } else {

            $data['code'] = 0;

            $data['msg'] = 'upload fail';

        }

        echo json_encode($data);

    }

    /*

    * 判断文件是否上传完成

    * */

    public function checkUploadAccomplish($file_name='', $total_pieces)

    {

        $file_name = substr($file_name, 0, 15);

        $n = 0;

        $status = true;

        for($i=1; $i<=$total_pieces; $i++)

        {

            if(!file_exists($_SERVER['SINASRV_DATA_DIR'].'/'. $file_name.'.apk'.$i))

            {

                $status = false;

            }else{

                $n++;

            }

        }

        return ['n'=>$n, 'status'=>$status];

    }

    /*

    * 合并切片文件

    * */

    public function mergeSlices($file_name='', $total_pieces)

    {

        $file_name = substr($file_name, 0, 15);

        $new_file_name = $_SERVER['SINASRV_DATA_DIR'].'/'.$file_name.'.apk';

        $fp = fopen($new_file_name,"wb");

        for($i=1; $i<=$total_pieces; $i++)

        {

            $tmp_name = $_SERVER['SINASRV_DATA_DIR'].'/'. $file_name.'.apk'.$i;

            //只读方式打开文件 指针指向文件头

            $handle = fopen($tmp_name,"rb");

            //切片文件写入新文件

            fwrite($fp,fread($handle,filesize($tmp_name)));

            //关闭切片文件

            fclose($handle);

            unset($handle);

            //删除切片

            unlink($tmp_name);

        }

        fclose($fp);

        return $new_file_name;

    }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容