javascript + PHP 实现文件的大文件分块上传(适用于视频等大文件)

js代码

<html lang="cn">
<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>分块上传</title>
    <style>
        #progressBlo {
            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);
        }
        #progress {
            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="progressBlo">
    <div id="progress" style="width: 0%;" progress="0"></div>
</div>
<form action="upload.php">
    <input type="file" name="file" id="file">
    <div id="msg">等待开始</div>
    <input type="button" value="停止" id="stopBtn">
</form>
<script>
    var fileElem = document.getElementById("file");
    var progressObj = document.getElementById('progress');
    var msgElem = document.getElementById("msg");
    var stopBtn = document.getElementById('stopBtn');
    var upload = null;

    fileElem.onchange = function () {
        if (this.files.length > 0) {
            upload = new Upload(this.files[0]);
            upload.start();
            this.value = null;
        }
    }

    stopBtn.onclick = function () {
        upload.stop();
    }

    function Upload(file)
    {
        var file = file;
        var status = 0;
        const BLOCK_SIZE = 1024 * 256;    // 256k
        var blockIdx = 1;
        var blockTotal = Math.ceil(file.size / BLOCK_SIZE);
        var blobStart = 0;
        var blobEnd = blobStart + BLOCK_SIZE;
        // 开始上传
        this.start = function () {
            msgElem.innerText = "正在上传:" + file.name;
            status = 1;
            sendFile(cutFile());
        }
        //  停止文件上传
        this.stop = function() {
            if (status != 1) {
                msgElem.innerText = "已停止";
                return;
            }
            msgElem.innerText = "正在停止";
            status = -1;
        }
        //  切割文件
        function cutFile() {
            var fileBlob = file.slice(blobStart, blobEnd);
            blobStart = blobEnd;
            blobEnd = blobStart + BLOCK_SIZE;
            return fileBlob;
        };
        //  发送文件
        function sendFile(blob) {
            var formData = new FormData();
            formData.append('file', blob);
            formData.append('blockIdx', blockIdx);
            formData.append('blockTotal', blockTotal);
            formData.append('fileName', file.name);

            var xhr = new XMLHttpRequest();
            xhr.open('POST', 'upload.php', true);
            xhr.onreadystatechange = function () {
                // 请求已完成
                if (xhr.readyState == 4) {
                    blockIdx += 1;
                    // 是否停止
                    if (status != 1) {
                        msgElem.innerText = "已停止";
                        return false;
                    }
                    // 继续上传下一块
                    if (blobStart < file.size) {
                        progressObj.style.width = Math.min(100, (blockIdx / blockTotal) * 100) + '%';
                        sendFile(cutFile());
                    } else {
                        progressObj.style.width = '100%';
                        msgElem.innerText = "上传完成";
                        status = 2;
                    }
                }
            }
            xhr.send(formData);
        }
    }

</script>
</body>
</html>

后端PHP

<?php

class Upload
{
    private $saveDir = './uploads/down'; //上传目录
    private $tmpFile;       // PHP文件临时目录
    private $fileName;      //  文件名
    private $blockIdx;       //  第几个文件块
    private $blockTotal;  //  文件块总数

    public function __construct($tmpPath, $fileName, $blobNum, $totalBlobNum)
    {
        $this->tmpFile = $tmpPath;
        $this->fileName = $fileName;
        $this->blockIdx = $blobNum;
        $this->blockTotal = $totalBlobNum;
        // 文件夹
        if (file_exists($this->saveDir) == false) {
            mkdir($this->saveDir, 0666, true);
        }
        $this->moveFile();
        $this->fileMerge();
    }

    //  判断是否是最后一块,如果是则进行文件合成并且删除文件块
    private function fileMerge()
    {
        if ($this->blockIdx == $this->blockTotal) {
            $blob = '';
            for ($i = 1; $i <= $this->blockTotal; $i++) {
                $blob .= file_get_contents($this->saveDir . '/' . $this->fileName . '__' . $i);
            }
            file_put_contents($this->saveDir . '/' . $this->fileName, $blob);
            $this->deleteFileBlob();
        }
    }

    //  删除文件块
    private function deleteFileBlob()
    {
        for ($i = 1; $i <= $this->blockTotal; $i++) {
            @unlink($this->saveDir . '/' . $this->fileName . '__' . $i);
        }
    }

    //  移动文件
    private function moveFile()
    {
        $this->touchDir();
        $filename = $this->saveDir . '/' . $this->fileName . '__' . $this->blockIdx;
        move_uploaded_file($this->tmpFile, $filename);
    }

    //  API返回数据
    public function apiReturn()
    {
        if ($this->blockIdx == $this->blockTotal) {
            if (file_exists($this->saveDir . '/' . $this->fileName)) {
                $data['code'] = 2;
                $data['file_path'] = 'http://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['DOCUMENT_URI']) . str_replace('.', '', $this->saveDir) . '/' . $this->fileName;
            }
        } else {
            if (file_exists($this->saveDir . '/' . $this->fileName . '__' . $this->blockIdx)) {
                $data['code'] = 1;
                $data['file_path'] = '';
            }
        }
        header('Content-type: application/json');
        echo json_encode($data);
    }

    //  建立上传文件夹
    private function touchDir()
    {
        if (!file_exists($this->saveDir)) {
            return mkdir($this->saveDir);
        }
    }
}

//实例化并获取系统变量传参
$upload = new Upload($_FILES['file']['tmp_name'], $_POST['fileName'], $_POST['blockIdx'], $_POST['blockTotal']);
//调用方法,返回结果
$upload->apiReturn();

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值