当前位置: 首页 > news >正文

PHP如何实现500M以上大文件上传的解决方案?

开发者日记:2023年X月X日 星期X 武汉 阴

项目背景
今日正式启动客户的大文件传输系统项目,需求明确:支持20G文件/文件夹上传下载、跨平台(Windows/macOS/Linux)、全浏览器兼容(含IE8)、断点续传、保留文件夹层级结构。后端使用PHP + MySQL,存储用阿里云OSS,前端为Vue3 CLI + WebUploader/H5。客户强调高频文件夹上传场景,需极致优化用户体验。免费开源代码和7*24支持的压力依旧,但技术栈熟悉度较高,信心渐增。


技术选型与调整

  1. 前端框架

    • Vue3 CLI:组件化开发,配合@babel/polyfill兼容IE8。
    • WebUploader:核心上传组件,深度定制文件夹解析逻辑。
    • H5 File API:现代浏览器备用方案,IE8回退到Flash上传。
  2. 后端架构

    • PHP 8.1:处理分片上传、MySQL元数据存储、OSS直传。
    • MySQL 8.0:存储文件路径、分片状态、用户ID(InnoDB引擎保证事务)。
  3. 核心难点

    • 高频文件夹上传:优化递归解析性能,避免前端卡顿。
    • 断点续传稳定性:MySQL事务保证分片记录一致性。
    • IE8兼容性:Flash上传需处理跨域问题(crossdomain.xml)。

前端代码实现(Vue3 + WebUploader)

1. 文件夹上传组件
// src/components/FolderUploader.vueimport{ref,onMounted}from'vue';importWebUploaderfrom'webuploader';import'webuploader/dist/webuploader.css';exportdefault{setup(){constuploader=ref(null);constfolderTree=ref([]);onMounted(()=>{// 动态加载Flash(IE8兼容)if(!WebUploader.Uploader.support('HTML5')){WebUploader.Uploader.register({name:'flash',fn:()=>'/assets/Uploader.swf'});}uploader.value=newWebUploader.Uploader({swf:'/assets/Uploader.swf',server:'/api/upload.php',chunked:true,chunkSize:4*1024*1024,// 4MB分片formData:{fileId:'',relativePath:''// 关键:记录文件相对路径}});});consttriggerFolderInput=()=>{document.getElementById('folderInput').click();};// 递归解析文件夹(兼容现代浏览器)consthandleFolderSelect=(e)=>{constitems=e.target.files;if(items){consttree=[];for(leti=0;i<items.length;i++){constfile=items[i];constpath=file.webkitRelativePath||file.name;// 相对路径constsegments=path.split('/');// 构建树形结构letcurrentLevel=tree;segments.slice(0,-1).forEach(segment=>{letdir=currentLevel.find(item=>item.name===segment);if(!dir){dir={name:segment,type:'directory',children:[]};currentLevel.push(dir);}currentLevel=dir.children;});// 添加文件节点currentLevel.push({name:segments.pop(),type:'file',file:file,relativePath:path});}folderTree.value=tree;uploadFolder(tree);}};// 上传文件夹内容constuploadFolder=(tree)=>{tree.forEach(node=>{if(node.type==='directory'){uploadFolder(node.children);// 递归上传子目录}else{constformData=uploader.value.option('formData');formData.relativePath=node.relativePath;uploader.value.addFile(node.file,node.relativePath);}});uploader.value.upload();// 触发上传};return{triggerFolderInput,folderTree};}};
2. IE8兼容性处理

后端代码实现(PHP + MySQL)

1. 分片上传接口
setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);$stmt=$pdo->prepare(" INSERT INTO upload_progress (file_id, chunk_index, total_chunks, uploaded_at) VALUES (?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE updated_at = NOW() ");$stmt->execute([$fileId,$chunkIndex,$totalChunks]);// 如果是最后一块,合并并上传OSSif($chunkIndex===$totalChunks-1){$finalPath="{$tempDir}/final_file";$fp=fopen($finalPath,'wb');for($i=0;$i<$totalChunks;$i++){$chunk=file_get_contents("{$tempDir}/chunk_{$i}");fwrite($fp,$chunk);}fclose($fp);// 上传OSS(需引入阿里云OSS SDK)require_once'oss-sdk/autoload.php';$ossClient=newOSS\OssClient($OSS_KEY,$OSS_SECRET,$OSS_ENDPOINT);$ossClient->putObject($OSS_BUCKET,"uploads/{$fileId}",$finalPath);// 清理临时文件array_map('unlink',glob("{$tempDir}/*"));rmdir($tempDir);// 保存文件元数据到MySQL$metaStmt=$pdo->prepare(" INSERT INTO file_metadata (file_id, relative_path, size, uploaded_at) VALUES (?, ?, ?, NOW()) ");$metaStmt->execute([$fileId,$relativePath,filesize($finalPath)]);}echojson_encode(['success'=>true,'fileId'=>$fileId]);}catch(Exception$e){http_response_code(500);echojson_encode(['error'=>$e->getMessage()]);}?>
2. MySQL表结构
-- 文件分片进度表CREATETABLE`upload_progress`(`id`int(11)NOTNULLAUTO_INCREMENT,`file_id`varchar(64)NOTNULLCOMMENT'文件唯一ID',`chunk_index`int(11)NOTNULLCOMMENT'分片索引',`total_chunks`int(11)NOTNULLCOMMENT'总分片数',`uploaded_at`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMP,`updated_at`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP,PRIMARYKEY(`id`),UNIQUEKEY`idx_file_chunk`(`file_id`,`chunk_index`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;-- 文件元数据表CREATETABLE`file_metadata`(`id`int(11)NOTNULLAUTO_INCREMENT,`file_id`varchar(64)NOTNULLCOMMENT'文件唯一ID',`relative_path`varchar(512)NOTNULLCOMMENT'文件相对路径',`size`bigint(20)NOTNULLCOMMENT'文件大小(字节)',`uploaded_at`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMP,PRIMARYKEY(`id`),UNIQUEKEY`idx_file_path`(`file_id`,`relative_path`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

断点续传实现

1. 前端恢复逻辑
// 检查未完成上传constcheckResume=async(fileId)=>{constres=awaitfetch(`/api/progress.php?fileId=${fileId}`);constdata=awaitres.json();if(data.completedChunks<data.totalChunks){uploader.value.option('formData',{fileId,chunk:data.completedChunks});uploader.value.upload();}};// 本地存储fileId(即使浏览器关闭)window.addEventListener('beforeunload',()=>{if(uploader.value.getFiles().length>0){localStorage.setItem('lastUploadId',uploader.value.option('formData').fileId);}});
2. 后端进度查询
'fileId is required']);exit;}try{$pdo=newPDO("mysql:host={$DB_HOST};dbname={$DB_NAME}",$DB_USER,$DB_PASS);$stmt=$pdo->prepare(" SELECT COUNT(*) AS completed, MAX(total_chunks) AS total FROM upload_progress WHERE file_id = ? ");$stmt->execute([$fileId]);$result=$stmt->fetch(PDO::FETCH_ASSOC);echojson_encode(['completedChunks'=>(int)$result['completed'],'totalChunks'=>(int)$result['total']]);}catch(Exception$e){http_response_code(500);echojson_encode(['error'=>$e->getMessage()]);}?>

今日总结

  • 进展:完成文件夹层级解析和PHP分片上传逻辑,IE8兼容性方案验证通过。
  • 问题
    1. WebUploader在IE8下对大文件夹性能较差,需优化DOM操作。
    2. MySQL事务需加强,避免分片记录残留。
  • 明日计划
    1. 实现OSS分片上传(避免本地合并临时文件)。
    2. 编写完整的开发文档和API接口说明。

求助:若有熟悉PHP文件处理或MySQL优化的高手,欢迎加入QQ群374992201指导!代码将完全开源回馈社区。


(注:实际项目需补充安全校验、OSS直传和性能监控代码。)

安装环境

PHP:7.2.14

调整块大小

NOSQL

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

SQL

创建数据库

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

配置数据库连接

安装依赖

访问页面进行测试

数据表中的数据

效果预览

文件上传

文件刷新续传

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

文件夹上传

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

批量下载

支持文件批量下载

下载续传

文件下载支持离线保存进度信息,刷新页面,关闭页面,重启系统均不会丢失进度信息。

文件夹下载

支持下载文件夹,并保留层级结构,不打包,不占用服务器资源。

免费下载示例

点击下载完整示例

http://www.jsqmd.com/news/354466/

相关文章:

  • Qt 6.10.1 安卓生成安装包
  • web页面如何通过PHP实现超大文件(500M+)上传?
  • 农业大数据平台如何优化UEDITOR的WORD表格粘贴?
  • 2026年评价高的手动加热压片机/防护压片机实力厂家 - 品牌宣传支持者
  • 技术拆解与选型避坑:2026年五大企业级BI平台深度横评报告
  • 政府网站如何通过UEDITOR实现PDF文档的在线批注?
  • 2026年质量好的嘉兴生鲜商超设备/制冷保温商超设备热门品牌厂家推荐 - 品牌宣传支持者
  • 医疗系统如何通过富文本编辑器实现DICOM图像转存?
  • 这次终于选对!风靡全网的AI论文工具 —— 千笔ai写作
  • 余华《活着》深度解读:在苦难废墟上,生命自有其庄严
  • 分析实力强的斜纹滚花辊供应商,忠平机械性价比高吗? - mypinpai
  • 原生Android程序如何实现多线程编程?
  • 基于深度学习YOLOv10的足球运动员检测系统(YOLOv10+YOLO数据集+UI界面+Python项目源码+模型)
  • 2026年口碑好的文丘里变风量阀/实验室变风量阀厂家推荐及选购指南 - 品牌宣传支持者
  • 用过才敢说!深得人心的降AIGC平台 —— 千笔·专业降AI率智能体
  • 聊聊售后完善的婚礼宴会厅,哪家性价比高值得关注 - 工业品网
  • 交易所源码开发:单语言VS多语言,到底该怎么选?
  • 2026年质量好的小型尿素包衣设备/硫包衣尿素包衣设备厂家推荐及选择参考 - 品牌宣传支持者
  • 2026年知名的全自动快速量热仪/氧弹式量热仪厂家选购参考汇总 - 品牌宣传支持者
  • 一次全文降AI省下两天时间:我的真实经历分享 - 我要发一区
  • 全国劳动争议律师推荐,北京敦行所孙征律师靠谱吗费用多少? - 工业品牌热点
  • 科研党收藏!降AIGC工具 千笔·降AI率助手 VS Checkjie,本科生专属高效选择
  • 2026年知名的复合肥设备生产线/滚筒筛复合肥设备厂家推荐及选择参考 - 品牌宣传支持者
  • 2026年不锈钢接地端子多少钱,四川靠谱厂家大盘点 - myqiye
  • 2026年口碑好的消除死区搅拌器/顶入式搅拌器厂家推荐及采购指南 - 品牌宣传支持者
  • 2026年佛山值得选的GEO服务品牌,新纪元智能网络解决方案揭秘 - 工业推荐榜
  • 2026年口碑好的煤炭化验设备检测/煤炭化验设备自动化厂家最新推荐 - 品牌宣传支持者
  • 2026年北大通史班服务,探讨哪家合适口碑好 - 工业品网
  • 2026年盐城比较好的中考复读培训学校推荐,鸿文不容错过 - myqiye
  • 2026年知名的退火炉/钢丝线材退火炉厂家实力参考 - 品牌宣传支持者