news 2026/3/12 8:02:44

机械制造行业PHP如何解决500M大文件的上传问题?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
机械制造行业PHP如何解决500M大文件的上传问题?

咱就是说,作为一个福州信息安全专业的大三狗,最近被毕业设计折腾得头发都快薅成“地中海”了——老师拍板要做一个文件管理系统,美其名曰“兼顾实用性和技术深度”,结果我翻遍全网找大文件上传的代码,要么是残缺的“demo片段”,要么是“需要付费授权”的商业代码,连个能完整跑通的项目都找不到!最气的是,遇到问题想找作者问问,要么微信拉黑,要么QQ装死,群里喊破喉咙都没人理……(拍桌)

不过咱是谁?信息安全专业的“卷王”(自封的)!既然网上没现成的,咱就自己造轮子!刚好老师说“作品能直接答辩演示”,咱必须整出个“能打”的系统——大文件上传(10G+)、断点续传(关浏览器重启都不怕)、文件夹上传(保留层级)、加密传输+加密存储,还要兼容IE8这种“古董浏览器”(学校机房的老机器哭晕在厕所)。

先唠唠踩过的坑(血泪史版)

  1. 大文件上传:用WebUploader吧,文档不全;自己用H5 File API?分片、合并、进度保存全得自己写,头秃。
  2. 断点续传:想存进度?localStorage容量不够(10G文件的分片信息得存到后端);关浏览器就丢?那得用IndexedDB或者后端数据库存进度。
  3. 文件夹上传:webkitdirectory属性IE不认,IE8连File API都没有,只能让用户一个个选文件,再手动拼层级(用户骂骂咧咧但能凑合用)。
  4. 加密:传输要HTTPS,存储要AES加密,密钥得存后端(不然被偷库就完犊子)。
  5. 兼容IE8:放弃H5新特性,用iframe模拟异步上传,表单提交……(体验差但能跑)。

甩干货:核心代码(附调试说明)

咱直接上“能跑通”的代码,毕业答辩绝对稳!(PS:部分细节需要根据实际环境调整,群里喊我帮你调~)

前端:Vue3 + 原生JS(大文件分片上传+断点续传)

(兼容IE9+,IE8用iframe fallback,代码里标了注释)

export default { data() { return { uploading: false, progress: 0, chunkSize: 2 * 1024 * 1024, // 分片大小2MB(10G文件分5000片) file: null, fileHash: '', // 文件哈希(用于断点续传标识) uploadedChunks: [] // 已上传的分片序号 }; }, methods: { async handleFileSelect(e) { const files = e.target.files; if (!files.length) return; this.file = files[0]; // 计算文件哈希(用于断点续传,用SparkMD5库) this.fileHash = await this.calculateFileHash(this.file); // 检查后端是否已有部分分片(断点续传关键!) const { data } = await this.$http.get(`/api/checkChunks?hash=${this.fileHash}`); this.uploadedChunks = data.uploadedChunks || []; // 开始上传 this.uploadFile(); }, // 计算文件哈希(用Web Worker防卡顿) calculateFileHash(file) { return new Promise((resolve) => { const spark = new SparkMD5.ArrayBuffer(); const reader = new FileReader(); const chunkSize = this.chunkSize; const chunks = Math.ceil(file.size / chunkSize); let currentChunk = 0; reader.onload = (e) => { spark.append(e.target.result); currentChunk++; if (currentChunk < chunks) { loadNext(); } else { resolve(spark.end()); } }; const loadNext = () => { const start = currentChunk * chunkSize; const end = Math.min(start + chunkSize, file.size); reader.readAsArrayBuffer(file.slice(start, end)); }; loadNext(); }); }, // 上传文件(分片+断点续传) async uploadFile() { this.uploading = true; const totalChunks = Math.ceil(this.file.size / this.chunkSize); for (let i = 0; i < totalChunks; i++) { // 跳过已上传的分片 if (this.uploadedChunks.includes(i)) { this.progress = (i / totalChunks) * 100; continue; } const start = i * this.chunkSize; const end = Math.min(start + this.chunkSize, this.file.size); const chunk = this.file.slice(start, end); // 加密分片(AES加密,密钥从后端获取) const encryptedChunk = await this.encryptChunk(chunk); // 构造FormData(包含分片、文件哈希、当前分片序号) const formData = new FormData(); formData.append('file', encryptedChunk, `${this.fileHash}_${i}`); formData.append('hash', this.fileHash); formData.append('chunkIndex', i); formData.append('totalChunks', totalChunks); try { await this.$http.post('/api/uploadChunk', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); this.uploadedChunks.push(i); this.progress = (i / totalChunks) * 100; } catch (err) { console.error('上传失败:', err); break; } } // 所有分片上传完成,通知后端合并 if (this.uploadedChunks.length === totalChunks) { await this.$http.post('/api/mergeChunks', { hash: this.fileHash, fileName: this.file.name, totalChunks: totalChunks }); alert('上传成功!'); } this.uploading = false; }, // AES加密分片(密钥从后端获取,这里用伪代码) async encryptChunk(chunk) { const key = await this.$http.get('/api/getEncryptKey'); // 后端返回AES密钥 const iv = crypto.getRandomValues(new Uint8Array(16)); // 随机IV const cipher = new CryptoJS.AES.encrypt( chunk, CryptoJS.enc.Hex.parse(key), { iv: CryptoJS.enc.Hex.parse(iv.toString()) } ); return new Blob([cipher.toString()], { type: 'application/octet-stream' }); } } };
后端:PHP(分片接收+合并+加密存储)

(兼容IE8的表单上传 fallback,用$_FILES接收)

prepare("INSERT INTO upload_progress (hash, chunk_index) VALUES (?, ?) ON DUPLICATE KEY UPDATE chunk_index=?");$stmt->execute([$hash,$chunkIndex,$chunkIndex]);echojson_encode(['code'=>200,'msg'=>'分片上传成功']);exit;}// 合并分片接口:/api/mergeChunksif($_SERVER['REQUEST_METHOD']==='POST'&&isset($_POST['hash'])){$hash=$_POST['hash'];$fileName=$_POST['fileName'];$totalChunks=(int)$_POST['totalChunks'];$tempDir=__DIR__."/uploads/temp/{$hash}";$finalPath=__DIR__."/uploads/files/{$fileName}";// 按顺序合并分片(加密后上传到OSS)$fp=fopen($finalPath,'wb');for($i=0;$i<$totalChunks;$i++){$chunkContent=file_get_contents("{$tempDir}/{$i}");fwrite($fp,aesEncrypt($chunkContent,getEncryptKey()));// 加密存储unlink("{$tempDir}/{$i}");// 删除临时分片}fclose($fp);rmdir($tempDir);// 删除临时目录// 清理数据库记录$pdo=newPDO("mysql:host=".DB_HOST.";dbname=".DB_NAME,DB_USER,DB_PASS);$pdo->exec("DELETE FROM upload_progress WHERE hash='{$hash}'");echojson_encode(['code'=>200,'msg'=>'文件合并成功']);exit;}// 检查已上传分片接口:/api/checkChunksif($_SERVER['REQUEST_METHOD']==='GET'&&isset($_GET['hash'])){$hash=$_GET['hash'];$pdo=newPDO("mysql:host=".DB_HOST.";dbname=".DB_NAME,DB_USER,DB_PASS);$stmt=$pdo->prepare("SELECT chunk_index FROM upload_progress WHERE hash=?");$stmt->execute([$hash]);$uploadedChunks=$stmt->fetchAll(PDO::FETCH_COLUMN,0);echojson_encode(['code'=>200,'uploadedChunks'=>$uploadedChunks]);exit;}// AES加密函数(密钥从环境变量获取,别硬编码!)functionaesEncrypt($data,$key){$iv=openssl_random_pseudo_bytes(16);$encrypted=openssl_encrypt($data,'AES-256-CBC',$key,0,$iv);returnbase64_encode($iv.$encrypted);// 存IV+密文}functionaesDecrypt($data,$key){$decoded=base64_decode($data);$iv=substr($decoded,0,16);$encrypted=substr($decoded,16);returnopenssl_decrypt($encrypted,'AES-256-CBC',$key,0,$iv);}functiongetEncryptKey(){// 从阿里云KMS或环境变量获取密钥(别直接写死!)returngetenv('AES_ENCRYPT_KEY');}?>
兼容IE8的“土味方案”

IE8不支持File APIFormData,只能用传统的iframe模拟异步上传:

// IE8检测 if (/*@cc_on!@*/false) { document.getElementById('fileInput').style.display = 'none'; document.getElementById('ie8FileInput').addEventListener('change', function(e) { document.getElementById('ie8UploadForm').submit(); }); }

吐槽+安利:群里见!

咱最近建了个QQ群(374992201),专门拉拢“被毕业设计逼疯”的兄弟姐妹们~群里福利拉满:

  • 新人加群送1~99元红包(手慢无!);
  • 推荐客户成交拿20%提成(2万项目提4千,比外卖自由香多了!);
  • 大神在线指导代码(不会写?直接@我,远程帮你调!);
  • 内推工作(学长学姐在互联网大厂蹲坑,直接甩岗位链接!)。

咱这毕业设计要是成了,答辩老师看了都得夸“这学生有点东西”~ 赶紧加群,一起卷死同学,顺便搞钱!(PS:群里还有人分享“如何用AI写论文”的玄学技巧,亲测能过查重!)

最后,求师哥师姐推荐工作!福州信息安全行业的岗位,求内推!(鞠躬)

安装环境

PHP:7.2.14

调整块大小

NOSQL

NOSQL不需要任何配置,可以直接访问测试

SQL

创建数据库

您可以直接复制脚本进行创建

配置数据库连接

安装依赖

访问页面进行测试

数据表中的数据

效果预览

文件上传

文件刷新续传

支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传

文件夹上传

支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。

免费下载示例

点击下载完整示例

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/10 22:10:10

如何看待与应用AI元人文:一份非终极的行动指南

如何看待与应用AI元人文&#xff1a;一份非终极的行动指南一、如何理解&#xff1a;这不是答案&#xff0c;而是邀请在深入AI元人文构想前&#xff0c;必须进行一次彻底的“认知复位”&#xff1a;这不是一个等待你“信奉”的理论教义&#xff0c;而是一份邀请你“参与”的文明…

作者头像 李华
网站建设 2026/3/11 12:37:06

2.3 资源控制与容量规划:避免系统被突发流量打垮

2.3 资源控制与容量规划:避免系统被突发流量打垮 引言 在高并发的分布式系统中,资源控制和容量规划是保障系统稳定性的关键环节。特别是在面对突发流量时,如果没有合理的资源控制机制和充足的容量规划,系统很容易因为资源耗尽而崩溃,导致服务不可用。 本节我们将深入探…

作者头像 李华
网站建设 2026/3/11 15:32:32

Qwen3-Reranker-8B入门指南:理解rerank任务与传统BM25/Embedding差异

Qwen3-Reranker-8B入门指南&#xff1a;理解rerank任务与传统BM25/Embedding差异 1. 什么是rerank&#xff1f;为什么它比BM25和基础Embedding更关键 你可能已经用过搜索功能——输入几个关键词&#xff0c;系统返回一堆文档。但有没有发现&#xff0c;排在最前面的结果&…

作者头像 李华
网站建设 2026/3/9 3:00:51

StructBERT-WebUI保姆级教学:Web界面响应式适配原理与移动端触摸交互优化

StructBERT-WebUI保姆级教学&#xff1a;Web界面响应式适配原理与移动端触摸交互优化 1. 项目概述 StructBERT文本相似度计算工具是一个基于百度StructBERT大模型实现的高精度中文句子相似度计算服务。它能够准确判断两个中文句子在语义上的相似程度&#xff0c;广泛应用于文…

作者头像 李华
网站建设 2026/3/11 22:49:51

DCT-Net模型剪枝教程:轻量化部署指南

DCT-Net模型剪枝教程&#xff1a;轻量化部署指南 1. 为什么需要给DCT-Net做剪枝 你可能已经用过DCT-Net&#xff0c;知道它能把一张普通照片变成日漫风、3D风或者手绘风的卡通形象&#xff0c;效果确实惊艳。但实际用起来会发现一个问题&#xff1a;模型文件动辄几百MB&#…

作者头像 李华
网站建设 2026/3/11 6:53:55

关于Linux服务器的协作问题

问题1: 我有两台电脑, 一台A在家, 一台B在学校, 我有一个Linux远程服务器, 在这两台电脑上使用VSCode的remote-ssh进行交互, 我的目的是能够让两台电脑的工作进度同步,两台电脑需不需要用不同的用户(比如一个用Howrun1, 另一个用Howrun2)一个用户能不能让两个主机同时使用? 如…

作者头像 李华