签入版本
This commit is contained in:
@@ -1,21 +1,35 @@
|
||||
# 7.2 上传配置详解
|
||||
|
||||
:::tip 概述
|
||||
文件上传配置定义在 `config/file.php` 和 `.env` 中,控制上传目录、域名、大小限制、允许的文件类型等。所有值通过 `env()` 函数从 `.env` 文件读取,支持多环境切换。
|
||||
文件上传配置定义在 `config/file.php` 和 `.env` 中,控制上传目录、访问域名、大小限制、允许的文件类型等。所有值通过 `env()` 函数从 `.env` 读取,支持多环境切换;`config/file.php` 中的注释明确标注了每个配置的**读取方**。
|
||||
:::
|
||||
|
||||
## 配置文件
|
||||
|
||||
```php
|
||||
// config/file.php — 文件上传配置
|
||||
// 所有值通过 env() 函数从 .env 文件读取,支持多环境切换
|
||||
// config/file.php — 文件上传配置(来自项目实际代码,节选)
|
||||
return [
|
||||
'upload_dir' => env('file.upload_dir', ''), // 上传根目录(绝对路径)
|
||||
'domain_url' => env('file.domain_url', ''), // 文件访问域名(拼接完整 URL 用)
|
||||
'temp_dir' => 'temp', // 临时目录名(相对 upload_dir)
|
||||
'image_ext' => env('file.image_ext', 'gif,jpg,jpeg,png,bmp,webp,svg'), // 允许的图片后缀
|
||||
'file_ext' => env('file.file_ext', 'gif,jpg,jpeg,png,bmp,webp,svg,doc,docx,xls,xlsx,ppt,pptx,pdf,zip,rar,txt,csv,mp3,mp4,sql,js,css'), // 允许的文件后缀
|
||||
'max_size' => env('file.max_size', 10) * 1024 * 1024, // 最大大小(MB → 字节)
|
||||
// 文件上传根目录(相对 public),所有上传文件均存放于此
|
||||
// 读取方:UploadController::uploadFile()、save_file()、save_remote_file()
|
||||
'upload_dir' => env('FILE_UPLOAD_DIR', 'uploads'),
|
||||
|
||||
// 文件访问域名,用于拼接完整 URL;为空时返回相对路径
|
||||
// 读取方:get_file_url()、save_content()、processContentFieldsOnRead()
|
||||
'domain_url' => env('FILE_DOMAIN_URL', ''),
|
||||
|
||||
// 临时文件目录名(相对 upload_dir)
|
||||
// 读取方:UploadController::uploadFile()(上传落盘目录)、save_file()(识别 temp/ 开头的临时文件后迁移到正式目录)
|
||||
'temp_dir' => 'temp',
|
||||
|
||||
// 允许上传的图片后缀(逗号分隔)
|
||||
// 安全说明:svg 已移除,因其可内嵌 JavaScript 导致 XSS 风险
|
||||
'image_ext' => env('FILE_IMAGE_EXT', 'gif,jpg,jpeg,png,bmp,webp'),
|
||||
|
||||
// 允许上传的文件后缀(逗号分隔)
|
||||
'file_ext' => env('FILE_EXT', 'gif,jpg,jpeg,png,bmp,webp,doc,docx,xls,xlsx,ppt,pptx,pdf,zip,rar,txt,csv'),
|
||||
|
||||
// 单文件最大尺寸(MB),转换为字节存储
|
||||
'max_size' => (int) env('FILE_MAX_SIZE', 10) * 1024 * 1024,
|
||||
];
|
||||
```
|
||||
|
||||
@@ -23,67 +37,76 @@ return [
|
||||
|
||||
| 配置项 | .env 变量 | 默认值 | 说明 |
|
||||
|--------|----------|--------|------|
|
||||
| `upload_dir` | `[FILE] UPLOAD_DIR` | - | 上传根目录(绝对路径),所有文件存储于此 |
|
||||
| `domain_url` | `[FILE] DOMAIN_URL` | - | 文件访问域名,用于拼接完整 URL |
|
||||
| `temp_dir` | - | `temp` | 临时目录名(相对 upload_dir) |
|
||||
| `image_ext` | `[FILE] IMAGE_EXT` | `gif,jpg,jpeg,png,bmp,webp,svg` | 图片允许后缀 |
|
||||
| `file_ext` | `[FILE] FILE_EXT` | 多种后缀 | 文件允许后缀 |
|
||||
| `max_size` | `[FILE] MAX_SIZE` | `10` | 单文件最大大小(MB) |
|
||||
| `upload_dir` | `FILE_UPLOAD_DIR` | `uploads` | 上传根目录(**相对 `public/`**),所有文件存储于此 |
|
||||
| `domain_url` | `FILE_DOMAIN_URL` | (空) | 文件访问域名,用于拼接完整 URL |
|
||||
| `temp_dir` | — | `temp` | 临时目录名(相对 upload_dir),上传接口的落盘目录,`save_file()` 据此识别待迁移文件 |
|
||||
| `image_ext` | `FILE_IMAGE_EXT` | `gif,jpg,jpeg,png,bmp,webp` | 图片允许后缀(**无 svg**) |
|
||||
| `file_ext` | `FILE_EXT` | 图片+文档+压缩包等 | 文件允许后缀 |
|
||||
| `max_size` | `FILE_MAX_SIZE` | `10` | 单文件最大大小(MB,配置内自动转字节) |
|
||||
|
||||
### upload_dir — 上传根目录
|
||||
|
||||
```ini
|
||||
; .env
|
||||
[FILE]
|
||||
UPLOAD_DIR = D:/uploads/rxthinkcmf
|
||||
# .env
|
||||
FILE_UPLOAD_DIR=uploads
|
||||
```
|
||||
|
||||
**要求:**
|
||||
- 必须是绝对路径
|
||||
- 目录必须存在且有写入权限
|
||||
- 生产环境建议放在项目目录外(防止被 Web 直接访问)
|
||||
|
||||
- 本项目为**相对 `public/` 的目录**,Web 可直接访问其中的静态文件
|
||||
- 目录必须存在且有写入权限(Docker 镜像已创建并授权 `public/uploads`)
|
||||
- 上传文件随项目目录持久化(Docker 下即宿主机目录,不依赖命名卷)
|
||||
|
||||
**各环境示例:**
|
||||
|
||||
| 环境 | 路径示例 |
|
||||
|------|---------|
|
||||
| Windows 开发 | `D:/uploads/rxthinkcmf` |
|
||||
| Linux 开发 | `/home/www/uploads/rxthinkcmf` |
|
||||
| Linux 生产 | `/data/uploads/rxthinkcmf` |
|
||||
| Docker | `/uploads/rxthinkcmf`(挂载卷) |
|
||||
| 环境 | 值 | 实际位置 |
|
||||
|------|------|---------|
|
||||
| 本地开发 | `uploads` | `项目/public/uploads/` |
|
||||
| Linux 生产 | `uploads`(或绝对路径) | Nginx root 下可直接访问 |
|
||||
| Docker | `uploads` | 挂载的项目目录内 |
|
||||
|
||||
### domain_url — 文件访问域名
|
||||
|
||||
```ini
|
||||
; .env
|
||||
[FILE]
|
||||
DOMAIN_URL = https://cdn.example.com
|
||||
# .env
|
||||
FILE_DOMAIN_URL=https://cdn.example.com
|
||||
```
|
||||
|
||||
**要求:**
|
||||
- 不要以 `/` 结尾
|
||||
|
||||
- 不要以 `/` 结尾(读取方会 `rtrim` 处理,但配置时保持规范)
|
||||
- 必须是前端可访问的域名
|
||||
- 本地开发可留空(使用相对路径)
|
||||
- 本地开发可留空(接口返回相对路径,由同源/Vite 代理直接访问)
|
||||
|
||||
**各环境示例:**
|
||||
|
||||
| 环境 | 域名示例 |
|
||||
|------|---------|
|
||||
| 本地开发 | (留空,使用相对路径) |
|
||||
| 虚拟域名开发 | `http://file.laravel13.elevue` |
|
||||
| 测试环境 | `https://test-cdn.example.com` |
|
||||
| 生产环境 | `https://cdn.example.com` |
|
||||
| 对象存储 | `https://bucket-name.oss-cn-hangzhou.aliyuncs.com` |
|
||||
| 生产环境 | `https://cdn.example.com` 或对象存储域名 |
|
||||
|
||||
### temp_dir — 临时目录
|
||||
|
||||
```php
|
||||
// config/file.php
|
||||
'temp_dir' => 'temp',
|
||||
```
|
||||
|
||||
**说明:**
|
||||
|
||||
- 上传接口 `uploadFile` 把文件写入 `{upload_dir}/temp/Ymd/`,不直接落正式目录
|
||||
- `save_file()` / `save_content()` 依据 `temp/` 前缀把文件迁移到 Service 的 `fileSaveDir` 子目录
|
||||
- 正式目录未被表单引用的临时文件可按周期清理(见下方「问题 4」)
|
||||
|
||||
### max_size — 文件大小限制
|
||||
|
||||
```ini
|
||||
; .env
|
||||
[FILE]
|
||||
MAX_SIZE = 10
|
||||
# .env(单位 MB,config 内 ×1024×1024 转字节)
|
||||
FILE_MAX_SIZE=10
|
||||
```
|
||||
|
||||
**单位:** MB(配置文件中会自动转换为字节:`10 * 1024 * 1024`)
|
||||
|
||||
**建议值:**
|
||||
|
||||
| 场景 | 建议值 | 说明 |
|
||||
@@ -92,141 +115,95 @@ MAX_SIZE = 10
|
||||
| 文章封面 | 5 MB | 压缩后的图片 |
|
||||
| 通用文件上传 | 10 MB | 默认值 |
|
||||
| 文档上传 | 20 MB | PDF/Word 等 |
|
||||
| 视频上传 | 100 MB | 需配合分片上传 |
|
||||
|
||||
### image_ext — 图片允许后缀
|
||||
:::warning 双层限制
|
||||
业务层限制生效前,PHP 层必须放行:`php.ini` 的 `upload_max_filesize` / `post_max_size` 需 **大于等于** `FILE_MAX_SIZE`(建议 50M)。
|
||||
:::
|
||||
|
||||
### image_ext / file_ext — 后缀白名单
|
||||
|
||||
```ini
|
||||
; .env
|
||||
[FILE]
|
||||
IMAGE_EXT = gif,jpg,jpeg,png,bmp,webp,svg
|
||||
# .env
|
||||
FILE_IMAGE_EXT=gif,jpg,jpeg,png,bmp,webp # uploadFile?type=image 校验
|
||||
FILE_EXT=gif,jpg,jpeg,png,bmp,webp,doc,docx,xls,xlsx,ppt,pptx,pdf,zip,rar,txt,csv # uploadFile(默认 type=file)校验
|
||||
```
|
||||
|
||||
**默认值:** `gif,jpg,jpeg,png,bmp,webp,svg`
|
||||
**说明:**
|
||||
|
||||
**说明:** 用于 `uploadFile?type=image` 接口,只允许图片格式上传。
|
||||
|
||||
### file_ext — 文件允许后缀
|
||||
|
||||
```ini
|
||||
; .env
|
||||
[FILE]
|
||||
FILE_EXT = gif,jpg,jpeg,png,bmp,webp,svg,doc,docx,xls,xlsx,ppt,pptx,pdf,zip,rar,txt,csv,mp3,mp4,sql,js,css
|
||||
```
|
||||
|
||||
**默认值:** 包含图片、文档、压缩包、音视频等常见格式。
|
||||
|
||||
**说明:** 用于 `uploadFile` 接口,允许所有合法文件格式。
|
||||
- `image_ext` 用于 `type=image`,只允许图片格式;**svg 已移除**(内嵌 JS 的 XSS 风险)
|
||||
- `file_ext` 用于 `type=file`,允许图片、文档、压缩包等常见格式
|
||||
- 白名单为空数组时跳过校验(防御性兜底),生产环境务必保留非空配置
|
||||
|
||||
## .env 配置示例
|
||||
|
||||
### 开发环境
|
||||
|
||||
```ini
|
||||
[FILE]
|
||||
UPLOAD_DIR = D:/uploads/rxthinkcmf
|
||||
DOMAIN_URL =
|
||||
MAX_SIZE = 10
|
||||
```
|
||||
# 开发环境
|
||||
FILE_UPLOAD_DIR=uploads
|
||||
FILE_DOMAIN_URL=
|
||||
FILE_MAX_SIZE=10
|
||||
|
||||
### 测试环境
|
||||
|
||||
```ini
|
||||
[FILE]
|
||||
UPLOAD_DIR = /home/www/uploads/rxthinkcmf
|
||||
DOMAIN_URL = https://test-cdn.example.com
|
||||
MAX_SIZE = 10
|
||||
```
|
||||
|
||||
### 生产环境
|
||||
|
||||
```ini
|
||||
[FILE]
|
||||
UPLOAD_DIR = /data/uploads/rxthinkcmf
|
||||
DOMAIN_URL = https://cdn.example.com
|
||||
MAX_SIZE = 10
|
||||
IMAGE_EXT = jpg,jpeg,png,gif,bmp,webp
|
||||
FILE_EXT = jpg,jpeg,png,gif,bmp,webp,doc,docx,xls,xlsx,pdf,zip,rar
|
||||
```
|
||||
|
||||
### 对象存储(OSS)
|
||||
|
||||
```ini
|
||||
; 如果使用阿里云 OSS 等对象存储,domain_url 设为 OSS 域名
|
||||
[FILE]
|
||||
UPLOAD_DIR = /data/uploads/rxthinkcmf
|
||||
DOMAIN_URL = https://your-bucket.oss-cn-hangzhou.aliyuncs.com
|
||||
MAX_SIZE = 50
|
||||
# 生产环境(示例)
|
||||
FILE_UPLOAD_DIR=uploads
|
||||
FILE_DOMAIN_URL=https://cdn.example.com
|
||||
FILE_MAX_SIZE=10
|
||||
FILE_IMAGE_EXT=gif,jpg,jpeg,png,bmp,webp
|
||||
FILE_EXT=gif,jpg,jpeg,png,bmp,webp,doc,docx,xls,xlsx,pdf,zip,rar
|
||||
```
|
||||
|
||||
## 目录结构
|
||||
|
||||
```text
|
||||
{upload_dir}/ # upload_dir(上传根目录)
|
||||
├── temp/ # 临时目录(temp_dir)
|
||||
│ └── 20260920/ # 按日期分目录
|
||||
│ ├── a1b2c3d4e5f6.jpg # 随机文件名(防止冲突)
|
||||
│ └── f6e5d4c3b2a1.png
|
||||
├── article/ # 正式目录(由 fileSaveDir 配置)
|
||||
│ └── 20260920/
|
||||
│ └── 143052_xK7pMn3q.jpg
|
||||
├── example/
|
||||
│ └── 20260920/
|
||||
├── user/
|
||||
│ └── avatar/
|
||||
│ └── 20260920/
|
||||
└── file_template/
|
||||
└── 20260920/
|
||||
public/
|
||||
└── {upload_dir}/ # upload_dir(默认 uploads)
|
||||
├── temp/ # 临时目录(UploadController 上传落盘)
|
||||
│ └── 20261002/
|
||||
│ └── 123456_a1b2c3d4e5f6.jpg
|
||||
├── article/ # 正式目录(由 Service 的 fileSaveDir 配置)
|
||||
│ └── 20261002/
|
||||
│ └── 153052_9f8e7d6c5b4a.pdf
|
||||
├── example/
|
||||
├── user/
|
||||
│ └── avatar/
|
||||
└── file_template/
|
||||
```
|
||||
|
||||
### 目录命名规则
|
||||
|
||||
| 目录 | 说明 | 示例 |
|
||||
| 目录 | 说明 | 来源 |
|
||||
|------|------|------|
|
||||
| `temp/` | 临时文件目录 | 上传后暂存于此 |
|
||||
| `{module}/` | 正式目录(按模块) | 由 Logic 的 `fileSaveDir` 配置 |
|
||||
| `{date}/` | 日期子目录 | `20260920`(自动创建) |
|
||||
| `{random}.{ext}` | 随机文件名 | `a1b2c3d4e5f6.jpg`(防止冲突) |
|
||||
| `temp/` | 临时文件目录(上传接口落盘) | `config/file.php → temp_dir` |
|
||||
| `{module}/` | 按模块的正式目录 | Service 的 `fileSaveDir`(未配置按模型名推导) |
|
||||
| `{Ymd}/` | 日期子目录 | 自动创建 |
|
||||
| `{His}_{random}.{ext}` | 时间+随机文件名 | 防冲突与可预测性 |
|
||||
|
||||
## 文件生命周期
|
||||
|
||||
```text
|
||||
1. 前端上传 → upload_file()
|
||||
保存到: {upload_dir}/temp/20260920/a1b2c3d4e5f6.jpg
|
||||
返回: https://cdn.example.com/temp/20260920/a1b2c3d4e5f6.jpg
|
||||
1. 前端上传 → POST /api/upload/uploadFile
|
||||
保存到: public/uploads/temp/20261002/123456_a1b2c3d4e5f6.jpg
|
||||
返回: filePath + fileUrl
|
||||
|
||||
2. 前端提交表单 → 携带 fileUrl
|
||||
POST /api/example/add { name: "测试", avatar: "https://..." }
|
||||
2. 前端提交表单 → 携带 filePath
|
||||
POST /api/example/add { name: "测试", avatar: "temp/20261002/..." }
|
||||
|
||||
3. BaseLogic::add() → save_file()
|
||||
检测到 temp/ → 移动到正式目录
|
||||
{upload_dir}/temp/20260920/a1b2c3d4e5f6.jpg
|
||||
→ {upload_dir}/example/20260920/a1b2c3d4e5f6.jpg
|
||||
返回相对路径入库: /uploads/example/20260920/a1b2c3d4e5f6.jpg
|
||||
3. ExampleService::add() → processFileFieldsOnSave → save_file()
|
||||
temp/ → 迁移到 fileSaveDir(example/)后,正式目录相对路径入库
|
||||
(其它分支:去掉域名直接用;外部 URL → 下载保存)
|
||||
|
||||
4. BaseLogic::detail() → get_file_url()
|
||||
相对路径 → 拼接域名
|
||||
/uploads/example/20260920/a1b2c3d4e5f6.jpg
|
||||
→ https://cdn.example.com/uploads/example/20260920/a1b2c3d4e5f6.jpg
|
||||
4. ExampleService::detail() → processFileFieldsOnRead → get_file_url()
|
||||
相对路径 → 拼接 FILE_DOMAIN_URL
|
||||
example/20261002/...
|
||||
→ https://cdn.example.com/example/20261002/...
|
||||
```
|
||||
|
||||
## 与 Logic 层的配合
|
||||
## 与 Service 层的配合
|
||||
|
||||
```php
|
||||
class ArticleLogic extends BaseTenantLogic
|
||||
class ArticleService extends BaseTenantService
|
||||
{
|
||||
/**
|
||||
* 需要自动处理的文件上传字段
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $fileFields = ['cover'];
|
||||
use HasFileProcessing, /* 其他 Trait */;
|
||||
|
||||
/**
|
||||
* 文件保存的子目录
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected array $fileFields = ['cover'];
|
||||
protected string $fileSaveDir = 'article';
|
||||
}
|
||||
```
|
||||
@@ -235,14 +212,14 @@ class ArticleLogic extends BaseTenantLogic
|
||||
|
||||
```text
|
||||
配置:
|
||||
upload_dir = /data/uploads/rxthinkcmf
|
||||
fileSaveDir = article
|
||||
FILE_UPLOAD_DIR = uploads
|
||||
FILE_DOMAIN_URL = https://cdn.example.com
|
||||
fileSaveDir = article
|
||||
|
||||
结果:
|
||||
临时文件: /data/uploads/rxthinkcmf/temp/20260920/abc.jpg
|
||||
正式文件: /data/uploads/rxthinkcmf/article/20260920/abc.jpg
|
||||
数据库存: /uploads/article/20260920/abc.jpg
|
||||
前端显示: https://cdn.example.com/uploads/article/20260920/abc.jpg
|
||||
上传文件: public/uploads/temp/20261002/xxx.jpg
|
||||
Service 归一化后入库: article/20261002/xxx.jpg
|
||||
前端显示: https://cdn.example.com/article/20261002/xxx.jpg
|
||||
```
|
||||
|
||||
## Nginx 配置
|
||||
@@ -250,20 +227,18 @@ class ArticleLogic extends BaseTenantLogic
|
||||
### 静态文件直接由 Nginx 返回
|
||||
|
||||
```nginx
|
||||
# 配置 Nginx 直接处理文件请求,不经过 PHP
|
||||
location /uploads/ {
|
||||
alias /data/uploads/rxthinkcmf/;
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
# 项目方案:public/uploads 位于站点根内,location / 由 try_files 直接返回静态文件
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
```
|
||||
|
||||
### 禁止上传目录执行 PHP
|
||||
|
||||
```nginx
|
||||
# 安全:禁止上传目录执行 PHP 文件
|
||||
location ~* /uploads/.*\.php$ {
|
||||
deny all;
|
||||
# docker/nginx.conf 已内置:仅入口 index.php 可执行,其余 .php 一律 404
|
||||
location ~ \.php$ {
|
||||
return 404;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -279,57 +254,60 @@ location ~ /\. {
|
||||
|
||||
### 问题 1:上传提示"目录不可写"
|
||||
|
||||
**原因:** `upload_dir` 目录没有写入权限。
|
||||
**原因:** `public/uploads` 没有写入权限。
|
||||
|
||||
**解决:**
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
chmod -R 755 /data/uploads/rxthinkcmf
|
||||
chown -R www:www /data/uploads/rxthinkcmf
|
||||
chmod -R 755 public/uploads
|
||||
chown -R www-data:www-data public/uploads
|
||||
|
||||
# Docker:镜像内已 chown(storage / bootstrap/cache / public/uploads)
|
||||
```
|
||||
|
||||
### 问题 2:上传后图片不显示
|
||||
|
||||
**原因:** `domain_url` 配置错误或 Nginx 未配置静态文件处理。
|
||||
**原因:** `FILE_DOMAIN_URL` 配置错误或与前端不同源。
|
||||
|
||||
**解决:**
|
||||
1. 检查 `.env` 中 `DOMAIN_URL` 是否正确
|
||||
2. 检查 Nginx 是否配置了 `/uploads/` 的 alias
|
||||
3. 浏览器打开图片 URL 看是否能直接访问
|
||||
|
||||
1. 检查 `.env` 中 `FILE_DOMAIN_URL` 是否为前端可访问的地址(改后 `php artisan config:clear`)
|
||||
2. 留空时用相对路径——确认前端与后端同源或经代理
|
||||
3. 浏览器直接打开图片 URL 验证
|
||||
|
||||
### 问题 3:文件大小限制不生效
|
||||
|
||||
**原因:** PHP 配置限制了上传大小。
|
||||
**原因:** PHP 层限制小于业务层。
|
||||
|
||||
**解决:**
|
||||
|
||||
```ini
|
||||
; php.ini
|
||||
upload_max_filesize = 20M
|
||||
post_max_size = 25M
|
||||
; php.ini(修改后重启服务)
|
||||
upload_max_filesize = 50M
|
||||
post_max_size = 50M
|
||||
max_execution_time = 300
|
||||
```
|
||||
|
||||
### 问题 4:临时文件未清理
|
||||
|
||||
**原因:** `temp/` 目录中的文件在表单提交后未被 `save_file()` 迁移。
|
||||
**原因:** 上传后未提交表单(或表单未引用)的文件停留在 `temp/`,不会被迁移。
|
||||
|
||||
**解决:** 定期清理 `temp/` 目录中超过 1 天的文件:
|
||||
**解决:** 定期清理 `temp/` 中超过 1 天的文件:
|
||||
|
||||
```bash
|
||||
# 定时任务:每天凌晨清理 1 天前的临时文件
|
||||
find /data/uploads/rxthinkcmf/temp/ -type f -mtime +1 -delete
|
||||
find public/uploads/temp/ -type f -mtime +1 -delete
|
||||
```
|
||||
|
||||
## 安全建议
|
||||
|
||||
| 建议 | 说明 |
|
||||
|------|------|
|
||||
| 上传目录放在项目外 | 防止被 Web 直接访问源码 |
|
||||
| Nginx 禁止执行 PHP | 防止上传恶意 PHP 文件并执行 |
|
||||
| 扩展名白名单 | 只允许已知安全的文件类型 |
|
||||
| MIME 类型检查 | `finfo` 检测真实 MIME,防止伪造扩展名 |
|
||||
| 随机文件名 | 防止路径遍历和文件名注入 |
|
||||
| 文件大小限制 | 防止大文件 DoS 攻击 |
|
||||
| 定期清理临时文件 | 避免磁盘空间被占满 |
|
||||
| 扩展名白名单 | 只允许已知安全的文件类型(`FILE_IMAGE_EXT`/`FILE_EXT`) |
|
||||
| 移除高危后缀 | svg 已移除;生产白名单去掉 `sql/js/css` 等可执行类 |
|
||||
| MIME 类型检查 | 导入等场景配合 `finfo` 检测真实 MIME(见 [7.4 数据导入导出](/zh/tools/excel.html)) |
|
||||
| 随机文件名 | 服务端生成(时间+随机串),防止路径遍历和文件名注入 |
|
||||
| 文件大小限制 | `FILE_MAX_SIZE` 防止大文件 DoS |
|
||||
| Nginx 禁止执行 PHP | 仅入口 `index.php` 可执行(Docker 配置已内置) |
|
||||
| 定期清理临时文件 | `temp/` 内未被引用的文件按周期清理,避免磁盘空间被占满 |
|
||||
|
||||
Reference in New Issue
Block a user