签入版本
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
# 7.3 富文本处理
|
||||
|
||||
:::tip 概述
|
||||
富文本(如文章内容)中的图片/视频也需要处理。使用 `[IMG_URL]` 占位符机制,支持域名变更场景。
|
||||
富文本(如文章内容)中的图片/视频链接同样需要处理。项目采用 `[IMG_URL]` 占位符机制:入库时迁移临时文件并把域名替换为占位符,读取时再还原为当前配置的域名——支持域名变更场景。
|
||||
:::
|
||||
|
||||
## 处理流程图
|
||||
|
||||
```html
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 写入流程(add/update) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
@@ -14,20 +14,24 @@
|
||||
│ 前端编辑器插入图片 │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ 上传到临时目录 temp/日期/ │
|
||||
│ 上传到临时目录(uploadFile 接口) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ 提交 HTML 内容到后端 │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ BaseLogic::processContentFieldsOnSave() │
|
||||
│ Service(use HasFileProcessing) │
|
||||
│ processContentFieldsOnSave() │
|
||||
│ │ │
|
||||
│ ├─ 解析 <img> 标签的 src │
|
||||
│ ├─ 解析 <video>/<source>/<embed> 标签的 src │
|
||||
│ ├─ 解析 <a> 标签的文件 href │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ save_file() 迁移临时文件 → 正式目录 │
|
||||
│ save_content(&$content, $saveDir) ← 引用传递,原地修改 │
|
||||
│ │ │
|
||||
│ ├─ 站内临时文件 → save_file() 迁移至正式目录 │
|
||||
│ ├─ 正式文件 → 去掉域名 │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ 替换为 [IMG_URL]/相对路径 占位符 │
|
||||
@@ -44,9 +48,9 @@
|
||||
│ 数据库读取含占位符的 HTML │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ BaseLogic::processContentFieldsOnRead() │
|
||||
│ Service.processContentFieldsOnRead() │
|
||||
│ │ │
|
||||
│ ├─ 替换 [IMG_URL] 为实际域名 │
|
||||
│ ├─ 替换 [IMG_URL] 为 config/file.php 的 domain_url │
|
||||
│ │ 如 https://cdn.example.com │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
@@ -55,11 +59,14 @@
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 在 Logic 中配置
|
||||
## 在 Service 中配置
|
||||
|
||||
```php
|
||||
class ArticleLogic extends BaseLogic
|
||||
class ArticleService extends BaseTenantService
|
||||
{
|
||||
// 必须 use HasFileProcessing(否则占位实现直接透传,不处理)
|
||||
use HasFileProcessing, /* 其他 Trait */;
|
||||
|
||||
/**
|
||||
* 富文本字段
|
||||
*
|
||||
@@ -69,19 +76,31 @@ class ArticleLogic extends BaseLogic
|
||||
}
|
||||
```
|
||||
|
||||
配置后 BaseLogic 自动处理:
|
||||
- **add/update**:调用 `save_content()` 处理临时文件
|
||||
- **detail/pageList/allList**:调用 `processContentFieldsOnRead()` 替换占位符
|
||||
配置后自动处理:
|
||||
|
||||
- **add/update**:`processContentFieldsOnSave()` → `save_content()` 处理临时文件与占位符
|
||||
- **detail/pageList/allList**:`processContentFieldsOnRead()` / `...ReadList()` 还原占位符
|
||||
|
||||
:::warning 未启用 Trait 不生效
|
||||
`BaseService` 中的 `processContentFieldsOnSave` 是**占位实现**(直接返回原数据)。子类必须 `use HasFileProcessing` 真实实现才会处理——声明了 `contentFields` 却不 `use`,富文本将原样入库。
|
||||
:::
|
||||
|
||||
## 为什么使用占位符?
|
||||
|
||||
:::tip 域名变更场景
|
||||
假设初始配置 `FILE.DOMAIN_URL = https://cdn.example.com`,文章内容中图片 URL 为:
|
||||
`https://cdn.example.com/article/20260920/abc.jpg`
|
||||
假设初始配置 `FILE_DOMAIN_URL=https://cdn.example.com`,文章内容中图片 URL 为:
|
||||
|
||||
存储时替换为:`[IMG_URL]/article/20260920/abc.jpg`
|
||||
```text
|
||||
https://cdn.example.com/uploads/article/20261002/abc.jpg
|
||||
```
|
||||
|
||||
如果后续域名变更为 `https://cdn2.example.com`,只需修改 `.env` 中的 `FILE.DOMAIN_URL`,已存储的内容无需逐条更新,读取时自动替换为新域名。
|
||||
存储时替换为:
|
||||
|
||||
```text
|
||||
[IMG_URL]/uploads/article/20261002/abc.jpg
|
||||
```
|
||||
|
||||
如果后续域名变更为 `https://cdn2.example.com`,只需修改 `.env` 中的 `FILE_DOMAIN_URL`,**已存储的内容无需逐条更新**,读取时自动替换为新域名。
|
||||
:::
|
||||
|
||||
## 处理范围
|
||||
@@ -99,8 +118,15 @@ class ArticleLogic extends BaseLogic
|
||||
## 代码示例
|
||||
|
||||
```php
|
||||
// app/common.php 中的 save_content 函数
|
||||
// app/Helpers/helpers.php 中的 save_content(来自项目实际代码的函数签名)
|
||||
|
||||
/**
|
||||
* 处理富文本内容:站内临时文件转正、正式文件去掉域名,最终替换为 [IMG_URL] 占位。
|
||||
*
|
||||
* @param string $content 富文本 HTML(引用传递,原地修改)
|
||||
* @param string $saveDir 正式保存子目录
|
||||
* @return bool 是否发生替换
|
||||
*/
|
||||
function save_content(string &$content, string $saveDir = 'article'): bool
|
||||
{
|
||||
$config = config('file');
|
||||
@@ -110,7 +136,6 @@ function save_content(string &$content, string $saveDir = 'article'): bool
|
||||
return false;
|
||||
}
|
||||
|
||||
// 收集所有需要处理的 URL
|
||||
$urlMap = [];
|
||||
|
||||
// 1. 匹配 <img> 标签的 src
|
||||
@@ -123,7 +148,7 @@ function save_content(string &$content, string $saveDir = 'article'): bool
|
||||
save_content_match($content, '/<a[^>]+href=["\']?([^"\'>\s]+\.\w{2,5})["\']?/i', $domainUrl, $saveDir, $urlMap);
|
||||
|
||||
// 批量替换
|
||||
if (!empty($urlMap)) {
|
||||
if (! empty($urlMap)) {
|
||||
$content = str_replace(array_keys($urlMap), array_values($urlMap), $content);
|
||||
}
|
||||
|
||||
@@ -131,10 +156,25 @@ function save_content(string &$content, string $saveDir = 'article'): bool
|
||||
}
|
||||
```
|
||||
|
||||
**处理规则(来自 `save_content` 实现注释):**
|
||||
|
||||
- 站内临时文件 → 迁移到正式目录后记为 `[IMG_URL]` 占位
|
||||
- 正式文件 → 去掉域名后记录为 `[IMG_URL]` 占位
|
||||
- 外部 URL → 不处理(保持原样)
|
||||
|
||||
## 注意事项
|
||||
|
||||
:::warning 富文本安全
|
||||
- 富文本内容可能包含 XSS 攻击代码,建议在前端使用编辑器的安全模式
|
||||
- 富文本内容可能包含 XSS 攻击代码,建议在前端使用编辑器的安全模式(粘贴过滤)
|
||||
- `save_content` 只处理本站域名下的 URL,外部 URL 不做处理
|
||||
- 图片标签的 `src` 必须是完整 URL(包含域名),否则无法识别
|
||||
:::
|
||||
- 响应统一 `Content-Type: application/json`(ForceJsonResponse 中间件),内容不会被浏览器按 HTML 渲染
|
||||
:::
|
||||
|
||||
:::tip 与文件字段的分工
|
||||
- **单文件/多文件字段**(`fileFields`/`multiFileFields`)→ 结构化字段,见 [7.1 文件上传全流程](/zh/tools/upload.html)
|
||||
- **富文本字段**(`contentFields`)→ HTML 内嵌资源,本页说明
|
||||
- **配置项的 value**(按 `type` 分派,富文本类型为 `ueditor`)→ `HasConfigValueProcessing` Trait,见 [5.12 系统配置管理](/zh/core/config.html)
|
||||
|
||||
前两者由 `HasFileProcessing` Trait 提供,按属性声明分别启用;配置项不声明字段列表,而是由记录自身的 `type` 决定处理方式。
|
||||
:::
|
||||
|
||||
Reference in New Issue
Block a user