网站文件夹名称乡镇网站建设内容规划
网站文件夹名称,乡镇网站建设内容规划,福建建设工程交易网站,wordpress 建站赚钱重庆老码农的「百元预算大文件传输」解决方案 一、项目开场白
各位同行好#xff01;老张我今年45岁#xff0c;头发都快掉光了还在写代码。最近接了个「20G文件夹上传」的活儿#xff0c;客户要求用原生JSPHP实现#xff0c;预算100块还要7*24小时支持…#xff08;掏出…重庆老码农的「百元预算大文件传输」解决方案一、项目开场白各位同行好老张我今年45岁头发都快掉光了还在写代码。最近接了个「20G文件夹上传」的活儿客户要求用原生JSPHP实现预算100块还要7*24小时支持…掏出速效救心丸不过咱是讲武德的人既然接了活儿就得办漂亮二、技术选型穷人版组件替代方案成本WebUploader自己造轮子原生JSFlash回退0元SM4加密调用WebCrypto APIAES兼容模式0元断点续传localStorageMySQLOSS分片存储0元文件夹上传0元三、前端核心代码Vue3兼容版export default { data() { return { isIE8: /*cc_on!*/false || !!document.documentMode, progress: 0, apiUrl: /api/upload.php, chunkSize: 5 * 1024 * 1024, // 5MB分片 fileId: } }, methods: { triggerFileInput() { if (this.isIE8) { // IE8特殊处理弹窗提示用Flash alert(请使用上方Flash按钮上传文件夹); } else { document.getElementById(fileInput).click(); } }, async handleFileSelect(e) { const files e.target.files; if (!files.length) return; // 生成唯一文件ID保留路径结构 this.fileId this.generateFileId(files[0]); // 初始化进度记录 localStorage.setItem(progress_${this.fileId}, 0); // 并行上传所有文件演示简化版 for (let i 0; i files.length; i) { await this.uploadFile(files[i]); } }, generateFileId(file) { // 兼容IE8的路径处理 const path file.webkitRelativePath || (file.fullPath ? file.fullPath.split(\\).join(/) : ); return ${path}-${file.size}-${file.lastModified}; }, async uploadFile(file) { const totalChunks Math.ceil(file.size / this.chunkSize); let uploadedChunks parseInt(localStorage.getItem(progress_${this.fileId}) || 0); for (let i uploadedChunks; i totalChunks; i) { const start i * this.chunkSize; const end Math.min(file.size, start this.chunkSize); const blob file.slice(start, end); // 加密数据AES兼容模式 const encrypted await this.encryptData(blob, AES); // 上传分片 const formData new FormData(); formData.append(file, encrypted, chunk_${i}); formData.append(fileId, this.fileId); formData.append(chunkIndex, i); formData.append(totalChunks, totalChunks); try { await fetch(this.apiUrl, { method: POST, body: formData }); // 更新进度 uploadedChunks i 1; localStorage.setItem(progress_${this.fileId}, uploadedChunks); this.progress Math.round((uploadedChunks / totalChunks) * 100); } catch (err) { console.error(上传失败:, err); // 失败后自动重试3次 i--; if (i 0) break; } } // 上传完成后清理记录 if (uploadedChunks totalChunks) { localStorage.removeItem(progress_${this.fileId}); alert(上传完成); } }, // 简易加密实际项目请用WebCrypto encryptData(data, algorithm) { return new Promise(resolve { // 这里只是演示实际要用SM4/AES加密库 const reader new FileReader(); reader.onload (e) { // 假装加密了... resolve(new Blob([e.target.result])); }; reader.readAsArrayBuffer(data); }); } } }四、PHP后端代码穷人版your-access-key,accessKeySecretyour-secret-key,endpointoss-cn-hangzhou.aliyuncs.com,bucketyour-bucket];// 接收参数$fileId$_POST[fileId]??;$chunkIndex$_POST[chunkIndex]??0;$totalChunks$_POST[totalChunks]??1;// 保存分片到临时目录$tempDir/tmp/uploads/{$fileId};if(!is_dir($tempDir)){mkdir($tempDir,0777,true);}$tempPath{$tempDir}/chunk_{$chunkIndex};move_uploaded_file($_FILES[file][tmp_name],$tempPath);// 记录上传进度实际项目请用Redis$dbnewmysqli(localhost,root,password,file_db);$stmt$db-prepare(INSERT INTO upload_progress (file_id, chunk_index, total_chunks, uploaded_at) VALUES (?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE updated_at NOW());$stmt-bind_param(sii,$fileId,$chunkIndex,$totalChunks);$stmt-execute();// 检查是否所有分片都已上传$result$db-query(SELECT COUNT(*) as count FROM upload_progress WHERE file_id {$fileId} AND chunk_index {$totalChunks});$row$result-fetch_assoc();if($row[count]$totalChunks){// 合并分片并上传到OSS简化版$finalPath/tmp/{$fileId}.dat;$cmdcat{$tempDir}/chunk_* {$finalPath};exec($cmd);// 上传到OSS实际项目请用阿里云SDK$ossPathuploads/{$fileId}.dat;$cmdossutil64 cp{$finalPath}oss://{$ossConfig[bucket]}/{$ossPath};exec($cmd);// 清理临时文件array_map(unlink,glob({$tempDir}/*));rmdir($tempDir);unlink($finalPath);echojson_encode([successtrue,message文件合并完成]);}else{echojson_encode([successtrue,message分片保存成功]);}// 数据库表结构/* CREATE TABLE upload_progress ( id INT AUTO_INCREMENT PRIMARY KEY, file_id VARCHAR(255) NOT NULL, chunk_index INT NOT NULL, total_chunks INT NOT NULL, uploaded_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, UNIQUE KEY (file_id, chunk_index) ); */?五、IE8兼容方案魔法版Flash回退方案使用SWFUpload组件处理文件夹上传通过ExternalInterface与JS通信示例代码太长群里见…ActiveX控件终极方案function uploadFolder() { try { const folderPath prompt(请输入文件夹路径如C:\\data:); if (folderPath) { uploaderCtrl.UploadFolder(folderPath, http://your-server/api/ie8_upload.php); } } catch (e) { alert(请安装我们的专用上传控件); } }六、部署指南白嫖版服务器配置安装PHP MySQL Nginx配置ossutil工具阿里云官方命令行工具设置/tmp/uploads目录权限为777数据库初始化CREATEDATABASEfile_db;USEfile_db;-- 上传进度表见PHP代码部分定时清理任务# 每天凌晨清理未完成的上传00* * *rm-rf/tmp/uploads/*七、项目总结预算控制代码全部自己写0元服务器用阿里云学生机10元/月域名用免费TK域名0元技术支持加入QQ群374992201喊一声老张救命优先响应后续优化方向替换Flash为WebAssembly方案增加P2P加速上传实现真正的SM4加密需要C扩展最后声明本方案仅供学习交流实际项目请考虑购买商业授权主要是怕律师函。群里经常发红包进来薅羊毛也值了安装环境PHP:7.2.14调整块大小NOSQLNOSQL不需要任何配置可以直接访问测试SQL创建数据库您可以直接复制脚本进行创建配置数据库连接安装依赖访问页面进行测试数据表中的数据效果预览文件上传文件刷新续传支持离线保存文件进度在关闭浏览器刷新浏览器后进行不丢失仍然能够继续上传文件夹上传支持上传文件夹并保留层级结构同样支持进度信息离线保存刷新页面关闭页面重启系统不丢失上传进度。免费下载示例点击下载完整示例