PHP 实现文件秒传


 

秒传思路:

在前端计算出文件的md5值,与后端数据库记录的md5列表进行对比,若存在相同文件则直接使用原有文件并跳过上传步骤。

说明:

1,示例使用了JS库“js-spark-md5”计算文件的MD5信息,可以在下文提供的demo包中找到。

2,示例代码使用文本文档存储文件MD5及路径信息,实际使用时建议用数据库或其他形式存储。

3,示例代码中同时提交了文件流及MD5信息,实际使用时要先对比MD5后再决定是否上传文件。

 

示例demo下载:点击下载


 

示例demo中index.php内容如下:

<?php
    if($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES))
    {
        $file = fopen("./fileList", "r+");
        $md5List = $fileList = [];
        
        $i = 1;
        while(!feof($file))
        {
            $tmpInfo = fgets($file);
            
            if(!empty($tmpInfo))
            {
                $tmpInfoList = explode(' ', $tmpInfo);
                
                $md5List[$i] = $tmpInfoList[0];
                $fileList[$i] = trim($tmpInfoList[1]);
                
                $i ++;
            }
        }
        
        if($key = array_search($_POST['md5'], $md5List))
        {
            echo "重复文件已存在,秒传成功 <br>";
            echo $fileList[$key];
        }
        else
        {
            $tmpList = explode('.', $_FILES["file"]["name"]);
            $ext = end($tmpList);
            $uploadPath = './file/' . time() . mt_rand(1000, 9999) . '.' . $ext;
            
            move_uploaded_file($_FILES['file']['tmp_name'], $uploadPath);
            fwrite($file, $_POST['md5'] . ' ' . $uploadPath . "\n");
            
            echo "重复文件不存在,上传成功 <br>";
            echo $uploadPath;
        }
        
        fclose($file);
        echo "<br><a href='./index.php'>继续上传</a>";
        die();
    }
?>

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>PHP文件秒传 —— XMSB</title>
    <script src="./js/spark-md5.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
    <form action="" method="POST" enctype="multipart/form-data">
        <input type="file" name="file" id="file" value="" />
        <input type="hidden" name="md5" id="md5" value="" />
        <br>
    
        <pre id="log"></pre>
        
        <br>
        <input type="submit" value="确认上传"/>
    </form>
    
    <script type="text/javascript">
        var log = document.getElementById("log");
        var md5 = document.getElementById("md5");
        
        document.getElementById("file").addEventListener("change", function()
        {
            var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
            file = this.files[0],
            chunkSize = 2097152, // 每次读取2MB
            chunks = Math.ceil(file.size / chunkSize),
            currentChunk = 0,
            spark = new SparkMD5.ArrayBuffer(),
            frOnload = function(e)
            {
                log.innerHTML += "\n读取文件 " + parseInt(currentChunk+1) + " of " + chunks;
                spark.append(e.target.result);
                currentChunk ++;
                if(currentChunk < chunks)
                {
                    loadNext();
                }
                else
                {
                    var theMd5 = spark.end();
                    
                    log.innerHTML += "\n读取完成!\n\n文件md5:" + theMd5 + "\n";
                    md5.value = theMd5;
                }
            },
            frOnerror = function()
            {
                log.innerHTML += "\n出错了.";
            };
            function loadNext()
            {
                var fileReader = new FileReader();
                    fileReader.onload = frOnload;
                    fileReader.onerror = frOnerror;
                
                var start = currentChunk * chunkSize,
                    end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
                
                fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
            };
            
            log.style.display = "inline-block";
            log.innerHTML = "选择文件: " + file.name + " (" + file.size.toString().replace(/\B(?=(?:\d{3})+(?!\d))/g, ',') + " bytes)\n";
            loadNext();
        });
    </script>
</body>
</html>
posted @ 2021-01-05 13:25  何效名  阅读(234)  评论(0编辑  收藏  举报