本文目录导读:

在 PHP 项目中对接富文本编辑器后端,核心逻辑其实不复杂:(正文、图片、文件)发给后端,后端接收、处理、存储,然后返回给前端。
这里有几个关键点需要特别注意:图片/文件上传、XSS 安全防护、HTML 内容存储与回显。
下面我以最流行的编辑器之一 TinyMCE 为例(其他如 CKEditor、Quill、wangEditor 逻辑相似),给你一个完整的对接流程。
整体流程
用户在前端编辑器里输入文字、插入图片。 2. 点击"保存"(或编辑器自动触发的"提交")。 3. 前端将 HTML 内容(包含`<img>`标签等)通过 AJAX 或表单提交给 PHP 后端。 4. PHP 后端: - 接收 HTML 字符串。 - 进行安全检查(过滤 XSS 脚本)。 - 将内容存入数据库(通常是`TEXT`或`LONGTEXT`字段)。 5. 当需要显示文章时,PHP 从数据库取出 HTML,直接输出到前端页面。
核心步骤详解
HTML 内容的提交与接收
前端(假设使用 jQuery + TinyMCE):
// 获取编辑器内容(包含所有 HTML 标签)
var content = tinyMCE.get('editor_id').getContent();
// 提交给后端(建议使用 POST + JSON)
$.ajax({
type: 'POST',
url: '/api/save_article.php',
contentType: 'application/json',
data: JSON.stringify({
title: '文章标题',
content: content // 这里是完整的 HTML
}),
success: function(response) {
console.log('保存成功', response);
}
});
后端(PHP):
<?php
// save_article.php
header('Content-Type: application/json; charset=utf-8');
// 接收 JSON 请求
$input = json_decode(file_get_contents('php://input'), true);
$title = $input['title'] ?? '';
$content = $input['content'] ?? '';
// --- 关键:XSS 安全过滤 ---
// 使用 HTMLPurifier 或 strip_tags 白名单过滤
// 绝对不要直接存用户输入的 HTML,危险!
$cleanContent = purify_html($content); // 自定义函数,见下文
// --- 存入数据库(假设用 PDO)---
$stmt = $pdo->prepare("INSERT INTO articles (title, content) VALUES (?, ?)");
$stmt->execute([$title, $cleanContent]);
// 返回成功
echo json_encode(['status' => 'ok', 'id' => $pdo->lastInsertId()]);
⚠️ 重要提醒:
- 不要使用
strip_tags($content)直接过滤,因为它会去除所有 HTML,导致富文本变成纯文本。 - 推荐使用 HTMLPurifier 或 DOMDocument 进行白名单过滤。
图片/文件上传(最常遇到的问题)
大多数编辑器支持拖拽或粘贴上传图片,你需要提供一个“图片上传接口”。
前端 TinyMCE 配置:
tinymce.init({
selector: '#editor',
// 图片上传处理 URL
images_upload_url: '/api/upload_image.php',
// 自定义图片上传处理(可选,更灵活)
images_upload_handler: function (blobInfo, success, failure) {
var formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
$.ajax({
url: '/api/upload_image.php',
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function (response) {
// 后端返回图片的 URL
success(response.location);
},
error: function () {
failure('上传失败');
}
});
}
});
后端 PHP 处理图片上传:
<?php
// upload_image.php
header('Content-Type: application/json; charset=utf-8');
// 1. 验证上传
if ($_FILES['file']['error'] !== UPLOAD_ERR_OK) {
http_response_code(400);
echo json_encode(['error' => '上传失败']);
exit;
}
$file = $_FILES['file'];
// 2. 安全限制(类型、大小)
$allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($file['type'], $allowed_types)) {
http_response_code(400);
echo json_encode(['error' => '仅支持 JPG/PNG/GIF/WEBP']);
exit;
}
$max_size = 10 * 1024 * 1024; // 10MB
if ($file['size'] > $max_size) {
http_response_code(400);
echo json_encode(['error' => '文件大小不能超过10MB']);
exit;
}
// 3. 存储到服务器(建议使用日期目录,避免同名覆盖)
$upload_dir = '/uploads/images/' . date('Y/m/d/');
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$new_name = uniqid() . '.' . $ext;
$dest_path = $upload_dir . $new_name;
if (!move_uploaded_file($file['tmp_name'], $dest_path)) {
http_response_code(500);
echo json_encode(['error' => '存储失败']);
exit;
}
// 4. 返回图片的完整 URL(注意是 URL 不是路径)
$base_url = 'https://yourdomain.com'; // 建议从配置读取
$image_url = $base_url . $dest_path;
echo json_encode([
'location' => $image_url // TinyMCE 期待 "location" 字段
]);
内容回显(如何在前端显示)
当你从数据库取出文章内容,直接输出到 HTML 页面的对应容器即可。
PHP 输出到视图层:
<?php
// 假设从数据库取出
$article = $pdo->query("SELECT content FROM articles WHERE id = 1")->fetch();
?>
<html>
<body>
<article>
<?= $article['content'] ?> <!-- 直接输出 HTML -->
</article>
</body>
</html>
安全提示:
- 在输出时不需要再做转义,因为入库时已经进行了过滤。
- 如果你使用的模板引擎(如 Twig),需要输出原始HTML(
| raw过滤器),否则会被转义。 - 不要在
unknown环境中输出用户可控的内容,确保只输出已经安全过滤的 HTML。
关键点总结
| 环节 | 要点 |
|------|------|提交 | 前端提交完整 HTML,后端接收并存储 |
| XSS 防护 | 使用 HTMLPurifier 或 DOMDocument 白名单过滤,不要直接存用户 HTML图片上传 | 单独提供接口,限制文件类型/大小,返回可访问的 URL |
| 存储格式 | 数据库用 TEXT / LONGTEXT,或存储为静态 HTML 文件 |
| 回显输出** | 直接输出 HTML,但要确保已过滤,不要在输出前做 htmlspecialchars |
进阶建议
-
使用 HTMLPurifier 库
composer require ezyang/htmlpurifier
require_once 'HTMLPurifier/HTMLPurifier.auto.php'; $config = HTMLPurifier_Config::createDefault(); $purifier = new HTMLPurifier($config); $clean_content = $purifier->purify($content);
-
图片存储建议:
- 不要存在数据库(影响性能),存路径 URL 即可。
- 生产环境建议上传到
OSS(阿里云/腾讯云)或S3,返回 CDN URL。
-
防止 CSRF:
- 在 AJAX 请求中携带 CSRF Token,后端验证。 长度限制:**
- 数据库字段够用(LONGTEXT 可存 4GB)。
- 前端和后端都做长度校验,避免超大内容导致问题。