美文网首页PHP
PHP+JS大文件切割异步上传

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

作者: 7c3b293d3b97 | 来源:发表于2018-10-10 10:14 被阅读0次

用到的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;

    }

相关文章

网友评论

    本文标题:PHP+JS大文件切割异步上传

    本文链接:https://www.haomeiwen.com/subject/citpaftx.html