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>
欢迎转载,转载时请注明来源。