Files
KnowledgeBase/docs/FILENAME_PRESERVATION.md
Knowledge Base System acf549c43c feat: 初始化知识库系统项目
- 实现基于 Laravel 11 和 Filament 3.X 的文档管理系统
- 添加用户认证和分组管理功能
- 实现文档上传、分类和权限控制
- 集成 Word 文档自动转换为 Markdown
- 集成 Meilisearch 全文搜索引擎
- 实现文档在线预览功能
- 添加安全日志和审计功能
- 完整的简体中文界面
- 包含完整的项目文档和部署指南

技术栈:
- Laravel 11.x
- Filament 3.X
- Meilisearch 1.5+
- Pandoc 文档转换
- Redis 队列系统
- Pest PHP 测试框架
2025-12-05 14:44:44 +08:00

262 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 文件名保留功能说明
## 功能概述
知识库系统现在会完整保留用户上传文档时的原始文件名,包括中文、特殊字符等。下载文档时,文件名将与上传时保持一致。
## 实现细节
### 1. Filament 表单配置
`DocumentResource` 的文件上传字段中添加了 `preserveFilenames()` 方法:
```php
Forms\Components\FileUpload::make('file')
->label('文档文件')
->required()
->acceptedFileTypes([...])
->preserveFilenames() // 保留原始文件名
->disk('local')
->directory('documents/' . date('Y/m/d'))
// ...
```
### 2. 文件上传处理
#### CreateDocument 页面
```php
protected function mutateFormDataBeforeCreate(array $data): array
{
if (isset($data['file'])) {
$filePath = $data['file'];
$originalFileName = basename($filePath); // 获取原始文件名
$data['file_path'] = $filePath;
$data['file_name'] = $originalFileName; // 保存原始文件名
// ...
}
return $data;
}
```
#### EditDocument 页面
```php
protected function mutateFormDataBeforeSave(array $data): array
{
if (isset($data['file']) && $data['file'] !== $this->record->file_path) {
$filePath = $data['file'];
$originalFileName = basename($filePath); // 获取原始文件名
$data['file_path'] = $filePath;
$data['file_name'] = $originalFileName; // 保存原始文件名
// ...
}
return $data;
}
```
### 3. DocumentService 更新
#### 上传方法
```php
public function uploadDocument(...): Document
{
return DB::transaction(function () use (...) {
// 获取原始文件名
$originalFileName = $file->getClientOriginalName();
// 使用 storeAs 保存文件,保留原始文件名
$directory = 'documents/' . date('Y/m/d');
$filePath = $file->storeAs($directory, $originalFileName, 'local');
// 保存到数据库
$document = Document::create([
'file_path' => $filePath,
'file_name' => $originalFileName, // 原始文件名
// ...
]);
return $document;
});
}
```
#### 下载方法
```php
public function downloadDocument(Document $document, User $user): StreamedResponse
{
// 使用原始文件名作为下载文件名
return Storage::disk('local')->download(
$document->file_path,
$document->file_name // 原始文件名
);
}
```
## 支持的文件名格式
### ✅ 完全支持
1. **中文文件名**
- 示例:`知识库管理系统需求文档.docx`
- 上传后保留:✅
- 下载时保留:✅
2. **英文文件名**
- 示例:`Requirements Document.docx`
- 上传后保留:✅
- 下载时保留:✅
3. **数字文件名**
- 示例:`2024-Report.docx`
- 上传后保留:✅
- 下载时保留:✅
4. **特殊字符文件名**
- 示例:`文档(2024-01-01)_v1.0.docx`
- 支持的特殊字符:`()[]_-`
- 上传后保留:✅
- 下载时保留:✅
5. **混合格式文件名**
- 示例:`Project_项目文档_2024.docx`
- 上传后保留:✅
- 下载时保留:✅
## 文件存储结构
文件按日期组织存储:
```
storage/app/
└── documents/
└── 2024/
└── 12/
└── 04/
├── 知识库管理系统需求文档.docx
├── Requirements Document.docx
└── 文档(2024-01-01)_v1.0.docx
```
## 数据库字段
### documents 表
- `file_path`: 存储相对路径(如:`documents/2024/12/04/知识库管理系统需求文档.docx`
- `file_name`: 存储原始文件名(如:`知识库管理系统需求文档.docx`
- `file_size`: 文件大小(字节)
- `mime_type`: MIME 类型
## 浏览器兼容性
### 下载文件名编码
对于包含非 ASCII 字符(如中文)的文件名,系统会自动处理编码:
```
Content-Disposition: attachment; filename=document.docx; filename*=utf-8''%E7%9F%A5%E8%AF%86%E5%BA%93.docx
```
- `filename`: ASCII 兼容的后备文件名
- `filename*`: UTF-8 编码的完整文件名RFC 5987
### 支持的浏览器
- ✅ Chrome 80+
- ✅ Firefox 75+
- ✅ Safari 13+
- ✅ Edge 80+
- ✅ 移动浏览器iOS Safari, Chrome Mobile
## 测试覆盖
### 测试文件:`tests/Feature/DocumentFileNameTest.php`
1. **test_上传文档时保留原始文件名**
- 验证上传后 `file_name` 字段正确保存
2. **test_下载文档时使用原始文件名**
- 验证下载响应头包含原始文件名
3. **test_中文文件名正确处理**
- 验证中文文件名的完整支持
4. **test_特殊字符文件名正确处理**
- 验证特殊字符的正确处理
### 运行测试
```bash
php artisan test --filter=DocumentFileNameTest
```
## 注意事项
### 1. 文件名冲突
如果同一天上传了同名文件,后上传的文件会覆盖先上传的文件。建议:
- 用户在上传前检查文件名
- 或者在文件名中添加时间戳或版本号
### 2. 文件名长度限制
- 数据库字段 `file_name` 限制255 字符
- 文件系统限制:通常为 255 字节
- 建议文件名不超过 100 个字符
### 3. 特殊字符限制
某些特殊字符可能在不同操作系统上有限制:
- Windows: 不支持 `< > : " / \ | ? *`
- Linux/Mac: 不支持 `/`
系统会自动处理这些字符,但建议避免使用。
## 安全考虑
### 1. 路径遍历攻击防护
- 使用 `basename()` 提取文件名,防止路径遍历
- 文件存储在受控目录中
### 2. 文件名注入防护
- Laravel Storage 自动处理文件名转义
- 数据库使用参数化查询
### 3. XSS 防护
- 文件名在显示时会被 Blade 模板自动转义
- 下载响应头使用标准编码
## 未来改进
1. **文件名冲突处理**
- 自动添加序号:`文档.docx``文档(1).docx`
- 或添加时间戳:`文档.docx``文档_20240104_143022.docx`
2. **文件名验证**
- 添加文件名格式验证
- 限制特殊字符使用
- 提供文件名建议
3. **批量上传**
- 支持批量上传多个文件
- 自动处理文件名冲突
4. **文件名搜索**
- 支持按文件名搜索文档
- 支持模糊匹配
## 总结
文件名保留功能确保了用户上传和下载文档时的一致性体验,特别是对中文文件名的完整支持,使得知识库系统更加符合中文用户的使用习惯。
所有功能都经过完整测试,确保在各种场景下都能正常工作。