# 7.2 上传配置详解 :::tip 概述 文件上传配置定义在 `config/file.php` 和 `.env` 中,控制上传目录、域名、大小限制、允许的文件类型等。所有值通过 `env()` 函数从 `.env` 文件读取,支持多环境切换。 ::: ## 配置文件 ```php // config/file.php — 文件上传配置 // 所有值通过 env() 函数从 .env 文件读取,支持多环境切换 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 → 字节) ]; ``` ## 配置项详解 | 配置项 | .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 — 上传根目录 ```ini ; .env [FILE] UPLOAD_DIR = D:\xampp8.2\htdocs\RXThinkCMF_ThinkPhp8_EleVue\uploads ``` **要求:** - 必须是绝对路径 - 目录必须存在且有写入权限 - 生产环境建议放在项目目录外(防止被 Web 直接访问) **各环境示例:** | 环境 | 路径示例 | |------|---------| | Windows 开发 | `D:\xampp8.2\htdocs\RXThinkCMF_ThinkPhp8_EleVue\uploads` | | Linux 开发 | `/home/www/uploads` | | Linux 生产 | `/opt/data/uploads` | | Docker | `/data/apps/uploads`(挂载卷) | ### domain_url — 文件访问域名 ```ini ; .env [FILE] DOMAIN_URL = https://cdn.example.com ``` **要求:** - 不要以 `/` 结尾 - 必须是前端可访问的域名 - 本地开发可留空(使用相对路径) **各环境示例:** | 环境 | 域名示例 | |------|---------| | 本地开发 | (留空,使用相对路径) | | 测试环境 | `http://file.thinkphp8.elevue` | | 生产环境 | `https://cdn.example.com` | | 对象存储 | `https://bucket-name.oss-cn-hangzhou.aliyuncs.com` | ### max_size — 文件大小限制 ```ini ; .env [FILE] MAX_SIZE = 10 ``` **单位:** MB(配置文件中会自动转换为字节:`10 * 1024 * 1024`) **建议值:** | 场景 | 建议值 | 说明 | |------|--------|------| | 头像上传 | 2 MB | 图片通常不会太大 | | 文章封面 | 5 MB | 压缩后的图片 | | 通用文件上传 | 10 MB | 默认值 | | 文档上传 | 20 MB | PDF/Word 等 | | 视频上传 | 100 MB | 需配合分片上传 | ### image_ext — 图片允许后缀 ```ini ; .env [FILE] IMAGE_EXT = gif,jpg,jpeg,png,bmp,webp,svg ``` **默认值:** `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` 接口,允许所有合法文件格式。 ## .env 配置示例 ### 开发环境 ```ini [FILE] UPLOAD_DIR = D:\xampp8.2\htdocs\RXThinkCMF_ThinkPhp8_EleVue\uploads DOMAIN_URL = MAX_SIZE = 10 ``` ### 测试环境 ```ini [FILE] UPLOAD_DIR = /home/www/uploads DOMAIN_URL = http://file.thinkphp8.elevue MAX_SIZE = 10 ``` ### 生产环境 ```ini [FILE] UPLOAD_DIR = /opt/data/uploads 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 = /opt/data/uploads DOMAIN_URL = https://your-bucket.oss-cn-hangzhou.aliyuncs.com MAX_SIZE = 50 ``` ## 目录结构 ```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/ ``` ### 目录命名规则 | 目录 | 说明 | 示例 | |------|------|------| | `temp/` | 临时文件目录 | 上传后暂存于此 | | `{module}/` | 正式目录(按模块) | 由 Logic 的 `fileSaveDir` 配置 | | `{date}/` | 日期子目录 | `20260920`(自动创建) | | `{random}.{ext}` | 随机文件名 | `a1b2c3d4e5f6.jpg`(防止冲突) | ## 文件生命周期 ```text 1. 前端上传 → upload_file() 保存到: {upload_dir}/temp/20260920/a1b2c3d4e5f6.jpg 返回: https://cdn.example.com/temp/20260920/a1b2c3d4e5f6.jpg 2. 前端提交表单 → 携带 fileUrl POST /api/example/add { name: "测试", avatar: "https://..." } 3. BaseLogic::add() → save_file() 检测到 temp/ → 移动到正式目录 {upload_dir}/temp/20260920/a1b2c3d4e5f6.jpg → {upload_dir}/example/20260920/a1b2c3d4e5f6.jpg 返回相对路径入库: /uploads/example/20260920/a1b2c3d4e5f6.jpg 4. BaseLogic::detail() → get_file_url() 相对路径 → 拼接域名 /uploads/example/20260920/a1b2c3d4e5f6.jpg → https://cdn.example.com/uploads/example/20260920/a1b2c3d4e5f6.jpg ``` ## 与 Logic 层的配合 ```php class ArticleLogic extends BaseTenantLogic { /** * 需要自动处理的文件上传字段 * * @var array */ protected array $fileFields = ['cover']; /** * 文件保存的子目录 * * @var string */ protected string $fileSaveDir = 'article'; } ``` **实际路径映射:** ```text 配置: upload_dir = /opt/data/uploads fileSaveDir = article 结果: 临时文件: /opt/data/uploads/temp/20260920/abc.jpg 正式文件: /opt/data/uploads/article/20260920/abc.jpg 数据库存: /uploads/article/20260920/abc.jpg 前端显示: https://cdn.example.com/uploads/article/20260920/abc.jpg ``` ## Nginx 配置 ### 静态文件直接由 Nginx 返回 ```nginx # 配置 Nginx 直接处理文件请求,不经过 PHP location /uploads/ { alias /opt/data/uploads/; expires 30d; add_header Cache-Control "public, immutable"; } ``` ### 禁止上传目录执行 PHP ```nginx # 安全:禁止上传目录执行 PHP 文件 location ~* /uploads/.*\.php$ { deny all; } ``` ### 禁止访问隐藏文件 ```nginx location ~ /\. { deny all; } ``` ## 常见问题 ### 问题 1:上传提示"目录不可写" **原因:** `upload_dir` 目录没有写入权限。 **解决:** ```bash # Linux chmod -R 755 /opt/data/uploads chown -R www:www /opt/data/uploads ``` ### 问题 2:上传后图片不显示 **原因:** `domain_url` 配置错误或 Nginx 未配置静态文件处理。 **解决:** 1. 检查 `.env` 中 `DOMAIN_URL` 是否正确 2. 检查 Nginx 是否配置了 `/uploads/` 的 alias 3. 浏览器打开图片 URL 看是否能直接访问 ### 问题 3:文件大小限制不生效 **原因:** PHP 配置限制了上传大小。 **解决:** ```ini ; php.ini upload_max_filesize = 20M post_max_size = 25M max_execution_time = 300 ``` ### 问题 4:临时文件未清理 **原因:** `temp/` 目录中的文件在表单提交后未被 `save_file()` 迁移。 **解决:** 定期清理 `temp/` 目录中超过 1 天的文件: ```bash # 定时任务:每天凌晨清理 1 天前的临时文件 find /opt/data/uploads/temp/ -type f -mtime +1 -delete ``` ## 安全建议 | 建议 | 说明 | |------|------| | 上传目录放在项目外 | 防止被 Web 直接访问源码 | | Nginx 禁止执行 PHP | 防止上传恶意 PHP 文件并执行 | | 扩展名白名单 | 只允许已知安全的文件类型 | | MIME 类型检查 | `finfo` 检测真实 MIME,防止伪造扩展名 | | 随机文件名 | 防止路径遍历和文件名注入 | | 文件大小限制 | 防止大文件 DoS 攻击 | | 定期清理临时文件 | 避免磁盘空间被占满 |