layui实现文件分片上传

html代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>layui</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="/static/layui/css/layui.css" media="all">
    <script src="/static/layui/layui.js" charset="utf-8"></script>
    <!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 -->
    <style type="text/css">
        .mask {
            position: fixed;
            width: 100%;
            height: 100%;
            top: 0;
            left: 0;
            background: #000;
            opacity: 0.8;
            filter: alpha(Opacity=80);
            -moz-opacity: 0.8;
            z-index: 999;
            display: none;
        }
 
        .loading {
            position: fixed;
            width: 300px;
            left: 50%;
            margin-left: -150px;
            top: 200px;
            height: 18px;
            border-radius: 10px;
            background: #fff;
            z-index: 9999;
            overflow: hidden;
            display: none;
        }
    </style>
</head>
<body>
<div class="layui-main">
    <form class="layui-form" method="post" action="">
        <input type="hidden" name="form_submit" value="ok"/>
        <div class="layui-form-item">
            <label class="layui-form-label">安装包:</label>
            <input type="hidden" id="totalPage" value="0"/>
            <input type="hidden" id="page" value="1"/>
            <input type="hidden" id="status" value="0"/>
            <div class="layui-input-block">
                <button type="button" class="layui-btn" id="fileUpload"><i class="layui-icon"></i>上传文件</button>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">安装包名:</label>
            <div class="layui-input-block">
                <input type="text" name="name" id="name" value="" lay-verify="title" autocomplete="off" readonly="true"
                       class="layui-input">
            </div>
        </div>
        <div class="layui-form-item layui-form-text">
            <label class="layui-form-label">下载地址</label>
            <div class="layui-input-block">
                <input type="text" name="downUrl" id="downUrl" value="" lay-verify="downUrl" autocomplete="off"
                       readonly="true" placeholder="" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-input-block">
                <button class="layui-btn" lay-submit="" lay-filter="submit">立即提交</button>
                <button type="reset" class="layui-btn layui-btn-primary">重置</button>
            </div>
        </div>
    </form>
</div>
<div class="mask"></div>
<div class="loading">
    <div class="layui-progress layui-progress-big" lay-showpercent="true" lay-filter="uploadProgress">
        <div class="layui-progress-bar layui-bg-red" lay-percent="0%"></div>
    </div>
</div>
<!-- 注意:如果你直接复制所有代码到本地,上述js路径需要改成你本地的 -->
<script>
    layui.use(['form', 'upload', 'element'], function () {
        var form = layui.form;
        var upload = layui.upload;
        var element = layui.element;
        var $ = layui.$;
        upload.render({
            elem: '#fileUpload',
            url: 'upload', //处理上传文件接口
            accept: 'file',
            auto: false,
            acceptMime: '*.*',//允许上传的文件类型
            choose: function (obj) {
                element.progress('uploadProgress', '0%');//进度条清0
                $('.mask').show();//遮罩层
                $('.loading').show();//显示进度条
                var data = this.data;
                var files = obj.pushFile();//选择的文件推入obj
                var LENGTH = 500 * 1024; //每片文件大小
                obj.preview(function (index, file, result) {
                    var totalSize = file.size;//文件总大小
                    var totalPage = Math.ceil(totalSize / LENGTH);//总共上传的片数
                    $('#totalPage').val(totalPage);
                    $('#page').val('1');
                    $('#status').val('1');
                    var fileName = file.name;//获取文件名
                    $('#name').val(fileName);
                    var fileExt = fileName.substr(fileName.lastIndexOf('.') + 1);//获取文件后缀
                    fileName = fileName.substr(0, fileName.lastIndexOf('.'));//获取不带后缀的文件名
                    var progressTimer = setInterval(function () {
                        var totalPage = parseInt($('#totalPage').val());
                        var page = parseInt($('#page').val());
                        var status = $('#status').val();
                        if (parseInt(totalPage) == parseInt(page) && (parseInt(status) == 2 || parseInt(status) == -1)) {
                            clearInterval(progressTimer);//上传成功或失败停止上传
                        } else {
                            //状态为1的时候上传
                            if (status == 1) {
                                $('#status').val('0');
                                data.fileName = fileName;
                                data.page = page;
                                data.totalPage = totalPage;
                                data.fileExt = fileExt;
                                obj.upload(index, file.slice((page - 1) * LENGTH, page * LENGTH));//从文件中截取进行分片上传
                            }
                        }
                    }, 100);
                });
            },
                done: function (res) {
                    if (res.status == 1) { //分片上传
                        var page = parseInt($('#page').val());
                        var totalPage = parseInt($('#totalPage').val());
                        element.progress('uploadProgress', Math.ceil(page * 100 / totalPage) + '%');//更新进度条
                        page = page + 1;//上传下一片
                        console.log(page);
                        $('#page').val(page);
                        $('#status').val('1');
                    } else if (res.status == 2) { //上传完成
                        element.progress('uploadProgress', '100%');
                        $('#status').val('2');
                        $('#downUrl').val(res.downUrl);
                        layer.msg('上传成功', {time: 1000, anim: 0}, function () {
                            $('.mask').hide();//隐藏遮罩层
                            $('.loading').hide();//隐藏进度条
                        });
                    } else { //上传错误
                        $('#status').val('-1');
                        element.progress('uploadProgress', '0%');
                        console.log(!typeof (res.downUrl) == "undefined");
                        if (typeof (res.downUrl) == "undefined") {
                        } else {
                            $('#downUrl').val(res.downUrl);
                        }
                        layer.msg("上传失败,请重试", {time: 3000, anim: 0}, function () {
                            $('.mask').hide();
                            $('.loading').hide();
                        });
                    }
                },
 
                error: function () {
                $('.mask').hide();
                $('.loading').hide();
            }
        });
    });
</script>
</body>
</html>

php代码

 public function upload()
    {
        $status = 1;
//上传文件要保存的路径
        $fname = sprintf(public_path() . 'tmp\%s.%s', $_POST['fileName'], $_POST['fileExt']);
        $data = file_get_contents($_FILES['file']['tmp_name']);
 
        if ($_POST['page'] == 1) {
            file_put_contents($fname, $data);
        } else {
            //其余文件追加到文件末尾
            file_put_contents($fname, $data, FILE_APPEND);
        }
//最后一片文件
        if ($_POST['totalPage'] == $_POST['page']) {
            $status = 2;
            $res1 = fen($fname);
        }
//返回上传状态
        $res = ['status' => $status, 'downUrl' =>isset($res1)?$res1:''];
        return json($res);
    }

common.php

function fen($file)
{
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
    $accessKeyId = "";
    $accessKeySecret = "";
// Endpoint以杭州为例,其它Region请按实际情况填写。
    $endpoint = "http://oss-cn-shanghai.aliyuncs.com";
// 设置存储空间名称。
    $bucket = "";
// 设置文件名称。
    $object = rand(1, 9999999999) . '.jpg';
// <yourLocalFile>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt。
    $uploadFile = $file;
    try {
        $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
 
        //返回uploadId。uploadId是分片上传事件的唯一标识,您可以根据uploadId发起相关的操作,如取消分片上传、查询分片上传等。
        $uploadId = $ossClient->initiateMultipartUpload($bucket, $object);
    } catch (OssException $e) {
        printf(__FUNCTION__ . ": initiateMultipartUpload FAILED
");
        printf($e->getMessage() . "
");
        return;
    }
    /*
     * 步骤2:上传分片。
     */
    $partSize = 10 * 1024 * 1024;
    $uploadFileSize = filesize($uploadFile);
    $pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
    $responseUploadPart = array();
    $uploadPosition = 0;
    $isCheckMd5 = true;
    foreach ($pieces as $i => $piece) {
        $fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
        $toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
        $upOptions = array(
            // 上传文件。
            $ossClient::OSS_FILE_UPLOAD => $uploadFile,
            // 设置分片号。
            $ossClient::OSS_PART_NUM => ($i + 1),
            // 指定分片上传起始位置。
            $ossClient::OSS_SEEK_TO => $fromPos,
            // 指定文件长度。
            $ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
            // 是否开启MD5校验,true为开启。
            $ossClient::OSS_CHECK_MD5 => $isCheckMd5,
        );
        // 开启MD5校验。
        if ($isCheckMd5) {
            $contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
            $upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
        }
        try {
            // 上传分片。
            $responseUploadPart[] = $ossClient->uploadPart($bucket, $object, $uploadId, $upOptions);
        } catch (OssException $e) {
            printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} FAILED
");
            printf($e->getMessage() . "
");
            return;
        }
    }
// $uploadParts是由每个分片的ETag和分片号(PartNumber)组成的数组。
    $uploadParts = array();
    foreach ($responseUploadPart as $i => $eTag) {
        $uploadParts[] = array(
            'PartNumber' => ($i + 1),
            'ETag' => $eTag,
        );
    }
    /**
     * 步骤3:完成上传。
     */
    try {
        $ossClient->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);
    } catch (OssException $e) {
        printf(__FUNCTION__ . ": completeMultipartUpload FAILED
");
        printf($e->getMessage() . "
");
        return;
    }
//生成鉴权url
    $timeout = 36000000;
    $options = array(
        OssClient::OSS_PROCESS => "image/resize,m_lfit,h_100,w_100");
    $signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "GET", $options);
    return $signedUrl;
}

 

你可能感兴趣的