医疗影像平台如何通过HTML+PHP实现DICOM视频的分片加密上传?
作为一名即将毕业的软件工程学生,我的毕业设计选题是,要求支持20GB文件传输、文件夹层级结构保留,并兼容IE8及国产信创浏览器(如龙芯浏览器、红莲花浏览器)。经过两周的技术攻关,现将关键实现细节和代码片段整理如下,供同样面临毕业设计挑战的同学参考。directory$md5$chunk$userId$md5$md5$i$md5$idirectory:目前国产浏览器(如奇安信)在文件夹上传时存在路径
开发者日记:毕业设计大文件管理系统开发实录
日期:2023年11月20日
天气:多云转晴
作为一名即将毕业的软件工程学生,我的毕业设计选题是基于WebUploader的大文件管理系统,要求支持20GB文件传输、文件夹层级结构保留,并兼容IE8及国产信创浏览器(如龙芯浏览器、红莲花浏览器)。经过两周的技术攻关,现将关键实现细节和代码片段整理如下,供同样面临毕业设计挑战的同学参考。
一、技术选型与兼容性方案
-
前端框架
- Vue3 CLI + WebUploader(主方案) + HTML5 File API(备选)
- 浏览器兼容性:
- IE8:使用
webuploader.flashonly.js+@babel/polyfill - 国产浏览器:测试发现红莲花浏览器需禁用
directory属性,改用递归上传
- IE8:使用
-
后端架构
- PHP 8.0 + 阿里云OSS SDK
- 分片上传:固定5MB分片,支持断点续传
- MD5秒传:通过文件哈希去重
-
存储方案
- 阿里云OSS存储文件本体
- MySQL记录元数据(文件路径、分片状态、用户权限)
二、核心代码实现
1. 前端兼容性处理(Vue3组件)
// src/components/FileUploader.vue
import WebUploader from 'webuploader';
import { isIE8, isLoongBrowser } from '@/utils/browserDetect';
export default {
mounted() {
const uploaderConfig = {
swf: '/static/Uploader.swf', // IE8必需
server: '/api/upload',
pick: '#picker',
accept: { title: 'All', extensions: '*' },
compress: false,
chunked: true,
chunkSize: 5 * 1024 * 1024, // 5MB分片
threads: 3,
formData: { token: localStorage.getItem('upload_token') }
};
// 国产浏览器降级方案
if (isLoongBrowser() || isIE8()) {
uploaderConfig.directory = false; // 禁用文件夹拖拽
uploaderConfig.dnd = false; // 禁用HTML5拖放
}
const uploader = WebUploader.create(uploaderConfig);
// 文件夹递归上传(非IE8环境)
if (!isIE8()) {
uploader.on('beforeFileQueued', (file) => {
if (file.relativePath) {
this.uploadFolder(file);
return false; // 阻止默认队列行为
}
});
}
// 分片上传进度
uploader.on('uploadProgress', (file, percentage) => {
this.$emit('progress', { name: file.name, progress: percentage });
});
},
methods: {
async uploadFolder(rootFile) {
// 递归解析文件夹结构(需配合HTML5 File API)
const entries = await this.readDirectory(rootFile);
entries.forEach(entry => {
if (entry.isFile) {
this.uploadSingleFile(entry, rootFile.relativePath);
}
});
}
}
};
2. 后端分片处理(PHP)
// api/upload.php
'your-aliyun-key',
'accessKeySecret' => 'your-aliyun-secret',
'endpoint' => 'oss-cn-hangzhou.aliyuncs.com',
'bucket' => 'your-bucket-name'
];
// 处理分片上传
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$chunk = $_POST['chunk'] ?? 0;
$chunks = $_POST['chunks'] ?? 1;
$md5 = $_POST['md5'] ?? '';
$relativePath = $_POST['relativePath'] ?? '';
$userId = $_SESSION['user_id'] ?? 0;
// 存储临时分片
$chunkPath = "/tmp/chunks/{$md5}_{$chunk}";
move_uploaded_file($_FILES['file']['tmp_name'], $chunkPath);
// 记录分片状态到MySQL
$pdo = new PDO('mysql:host=localhost;dbname=file_manager', 'user', 'password');
$stmt = $pdo->prepare("REPLACE INTO file_chunks (md5, chunk_index, user_id) VALUES (?, ?, ?)");
$stmt->execute([$md5, $chunk, $userId]);
// 合并分片(最后一个分片)
if ($chunk == $chunks - 1) {
$ossPath = "users/{$userId}/{$relativePath}" . basename($_POST['name']);
$this->mergeChunks($md5, $chunks, $ossPath, $config);
// 记录完整文件信息
$fileStmt = $pdo->prepare("INSERT INTO files (name, path, md5, size, user_id) VALUES (?, ?, ?, ?, ?)");
$fileStmt->execute([
$_POST['name'],
$ossPath,
$md5,
$_POST['size'],
$userId
]);
echo json_encode(['status' => 'completed', 'path' => $ossPath]);
} else {
echo json_encode(['status' => 'pending']);
}
}
function mergeChunks($md5, $chunks, $ossPath, $config) {
$ossClient = new OssClient($config['accessKeyId'], $config['accessKeySecret'], $config['endpoint']);
$tempFile = "/tmp/{$md5}_merged";
// 合并本地分片
for ($i = 0; $i < $chunks; $i++) {
file_put_contents($tempFile, file_get_contents("/tmp/chunks/{$md5}_{$i}"), FILE_APPEND);
}
// 上传至阿里云OSS
$ossClient->uploadFile($config['bucket'], $ossPath, $tempFile);
// 清理临时文件
unlink($tempFile);
for ($i = 0; $i < $chunks; $i++) unlink("/tmp/chunks/{$md5}_{$i}");
}
3. MySQL表设计(关键表)
-- 文件分片状态表
CREATE TABLE `file_chunks` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`md5` CHAR(32) NOT NULL COMMENT '文件MD5',
`chunk_index` INT NOT NULL COMMENT '分片序号',
`user_id` INT NOT NULL COMMENT '所属用户',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY `md5_chunk` (`md5`, `chunk_index`)
);
-- 文件元数据表
CREATE TABLE `files` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL COMMENT '文件名',
`path` VARCHAR(512) NOT NULL COMMENT 'OSS存储路径',
`md5` CHAR(32) NOT NULL COMMENT '文件哈希',
`size` BIGINT NOT NULL COMMENT '文件大小',
`user_id` INT NOT NULL COMMENT '上传用户',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
三、关键问题与解决方案
-
IE8文件夹上传
- 方案:禁用
directory属性,改用Flash版WebUploader的普通文件选择 - 代码:通过``实现多选文件
- 方案:禁用
-
红莲花浏览器兼容性
- 问题:拖拽上传会触发浏览器崩溃
- 解决:检测到红莲花浏览器时隐藏拖拽区域
-
20GB文件内存优化
- 前端:始终使用
FileReader.readAsArrayBuffer分片读取 - 后端:PHP配置
upload_max_filesize = 0(由分片逻辑接管)
- 前端:始终使用
四、毕业设计特色功能
-
信创浏览器适配
- 通过User-Agent自动切换兼容模式
// utils/browserDetect.js export function isLoongBrowser() { return navigator.userAgent.includes('LoongBrowser'); } -
管理员监控面板
- 基于Vue3 + ECharts实现上传速度实时图表
-
安全增强
- 文件下载需携带JWT令牌
- 阿里云OSS配置Bucket Policy限制访问
寻求帮助:目前国产浏览器(如奇安信)在文件夹上传时存在路径解析异常,欢迎加入QQ群 374992201 指导调试!
今日进度:完成基础分片上传,明日将攻克信创浏览器兼容性问题。
(签名)
浙江某高校 · 软件工程1901班 · 张明
2023年11月20日 夜
附:项目地址
GitHub(待开源):https://github.com/graduation-project/file-manager
演示视频:项目根目录/demo/文件夹内
致谢:感谢群里王工提供的国产浏览器测试环境,以及李学长分享的阿里云OSS断点续传方案!
安装环境
PHP:7.2.14
调整块大小

NOSQL
NOSQL不需要任何配置,可以直接访问测试
SQL
创建数据库
您可以直接复制脚本进行创建

配置数据库连接

安装依赖

访问页面进行测试

数据表中的数据

效果预览
文件上传

文件刷新续传
支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传
文件夹上传
支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。
免费下载示例
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)