CKEditor 5 在 PHP 项目中的完整使用教程

CKEditor 5 是一个功能强大、现代化的富文本编辑器,它不再是传统的全局变量模式,而是基于 ES6 模块构建的,这使得集成方式与旧版 CKEditor 4 有所不同。

ckeditor使用教程 php
(图片来源网络,侵删)

本教程将涵盖以下核心内容:

  1. 环境准备:搭建 PHP 开发环境。
  2. 下载与集成:获取 CKEditor 5 并将其集成到你的 PHP 页面中。
  3. 基本配置:自定义工具栏、语言等。
  4. 核心功能:文件上传:配置 CKEditor 5 上传图片到服务器。
  5. 后端处理:编写 PHP 脚本接收并保存上传的文件。
  6. 数据保存与显示:如何将编辑器内容安全地存入数据库并安全地显示在页面上。
  7. 进阶配置:自定义内容过滤等。

第一步:环境准备

你需要一个支持 PHP 的 Web 服务器环境,最简单的方式是使用集成环境包:

  • XAMPP (Windows, macOS, Linux)
  • WAMP (Windows)
  • MAMP (macOS)

确保你的环境已经启动,Apache 和 MySQL 服务都在运行。


第二步:下载与集成 CKEditor 5

我们将使用 CKEditor 5 的 "经典编辑器" 版本,因为它最接近传统编辑器的体验。

ckeditor使用教程 php
(图片来源网络,侵删)

下载 CKEditor 5

访问 CKEditor 5 下载页面,选择 "Classic editor",然后点击 "Download",你会得到一个 ZIP 压缩包。

解压并放置文件

将下载的 ZIP 包解压,你会得到一个名为 ckeditor 的文件夹,我们将这个文件夹复制到你的 PHP 项目根目录下。

你的项目结构现在看起来应该像这样:

/my-php-project/
├── ckeditor/          <-- 从官网下载的 CKEditor 5 文件夹
│   ├── build/
│   ├── lang/
│   ├── samples/
│   └── ...
├── uploads/           <-- 我们稍后会创建这个文件夹,用于存放上传的图片
├── save_data.php      <-- 用于接收和处理编辑器数据的 PHP 文件
└── index.php          <-- 包含编辑器的页面

在 PHP 页面中引入 CKEditor 5

打开你的 index.php 文件,我们需要引入 CKEditor 5 的 JavaScript 和 CSS 文件。

ckeditor使用教程 php
(图片来源网络,侵删)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">CKEditor 5 PHP 教程</title>
    <!-- 1. 引入 CKEditor 5 的 CSS 文件 -->
    <link rel="stylesheet" href="ckeditor/contents.css">
    <!-- 2. 引入 CKEditor 5 的核心 JavaScript 文件 -->
    <!-- 注意:这里我们使用 build/ckeditor.js -->
    <script src="ckeditor/build/ckeditor.js"></script>
</head>
<body>
    <h1>CKEditor 5 PHP 集成示例</h1>
    <!-- 3. 创建一个 textarea 元素,作为编辑器的容器 -->
    <!-- CKEditor 5 会将这个 textarea 替换成一个功能完整的编辑器 -->
    <form action="save_data.php" method="post">
        <textarea name="editor_content" id="editor"></textarea>
        <br><br>
        <button type="submit">保存内容</button>
    </form>
    <!-- 4. 在页面底部编写初始化脚本 -->
    <script>
        // 使用 ClassicEditor 初始化编辑器
        // 'editor' 是上面 textarea 的 id
        ClassicEditor
            .create(document.querySelector('#editor'), {
                // 配置选项将在这里添加
            })
            .then(editor => {
                console.log('编辑器已初始化', editor);
            })
            .catch(error => {
                console.error('初始化编辑器时出错', error);
            });
    </script>
</body>
</html>

在浏览器中打开 index.php,你应该能看到一个功能齐全的富文本编辑器了!


第三步:基本配置

让我们对编辑器做一些简单的自定义,比如设置语言和工具栏。

index.phpClassicEditor.create() 中添加配置对象:

<script>
    ClassicEditor
        .create(document.querySelector('#editor'), {
            // 语言配置
            language: 'zh-cn', // 或者 'zh'
            // 工具栏配置
            toolbar: {
                items: [
                    'heading', '|',
                    'bold', 'italic', 'link', 'bulletedList', 'numberedList', '|',
                    'outdent', 'indent', '|',
                    'blockQuote', 'insertTable', 'undo', 'redo'
                ]
            }
        })
        .then(editor => { /* ... */ })
        .catch(error => { /* ... */ });
</script>

刷新页面,你会看到工具栏和界面都变成了中文,并且只显示了你配置的那些按钮,你可以根据需要从 官方文档 中查找更多配置项。


第四步:核心功能 - 配置文件上传

这是整个教程中最关键的一步,我们需要让 CKEditor 5 能够将图片上传到我们服务器的 uploads 目录。

创建上传目录

在你的项目根目录下创建一个名为 uploads 的文件夹,并确保 Web 服务器(如 Apache 的 www-data 用户)对该目录有写入权限。

在 Linux/macOS 上,你可以执行:

sudo chown -R www-data:www-data /path/to/your/my-php-project/uploads
sudo chmod -R 755 /path/to/your/my-php-project/uploads

在编辑器配置中添加上传适配器

修改 index.php 中的 ClassicEditor.create() 配置,添加一个 simpleUpload 适配器。

<script>
    ClassicEditor
        .create(document.querySelector('#editor'), {
            // ... 其他配置 ...
            language: 'zh-cn',
            toolbar: { /* ... */ },
            // 新增的文件上传配置
            simpleUpload: {
                // 上传服务器的 URL
                uploadUrl: 'upload.php', 
                // 可选:携带到请求头中的信息,CSRF Token
                // headers: {
                //     'X-CSRF-Token': 'CSRF_TOKEN_VALUE'
                // }
            }
        })
        .then(editor => { /* ... */ })
        .catch(error => { /* ... */ });
</script>

配置说明:

  • uploadUrl: 指向一个处理文件上传的 PHP 脚本的 URL,我们接下来会创建这个脚本。

处理上传请求:创建 upload.php

在项目根目录下创建 upload.php 文件,这个脚本将接收文件、验证它、保存它,并返回一个 JSON 响应给 CKEditor 5。

<?php
// upload.php
// 设置响应头为 JSON
header('Content-Type: application/json');
// --- 1. 配置 ---
$uploadDir = __DIR__ . '/uploads/'; // 上传目录
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif']; // 允许的文件类型
$maxSize = 5 * 1024 * 1024; // 最大文件大小 (5MB)
// --- 2. 创建上传目录(如果不存在) ---
if (!file_exists($uploadDir)) {
    mkdir($uploadDir, 0777, true);
}
// --- 3. 处理上传 ---
$response = [
    'default' => $uploadDir // 给 CKEditor 一个默认路径
];
if (isset($_FILES['upload']) && $_FILES['upload']['error'] === UPLOAD_ERR_OK) {
    $file = $_FILES['upload'];
    $fileName = $file['name'];
    $fileTmpName = $file['tmp_name'];
    $fileSize = $file['size'];
    $fileType = $file['type'];
    // --- 4. 验证 ---
    // 验证文件类型
    if (!in_array($fileType, $allowedTypes)) {
        http_response_code(415); // Unsupported Media Type
        echo json_encode(['error' => '不支持的文件类型。']);
        exit;
    }
    // 验证文件大小
    if ($fileSize > $maxSize) {
        http_response_code(413); // Payload Too Large
        echo json_encode(['error' => '文件太大。']);
        exit;
    }
    // --- 5. 生成安全的文件名并移动文件 ---
    // 获取文件扩展名
    $fileExtension = pathinfo($fileName, PATHINFO_EXTENSION);
    // 生成唯一文件名
    $newFileName = uniqid('img_', true) . '.' . $fileExtension;
    $destination = $uploadDir . $newFileName;
    if (move_uploaded_file($fileTmpName, $destination)) {
        // --- 6. 返回成功响应 ---
        // CKEditor 5 期望的响应格式
        echo json_encode([
            'url' => 'uploads/' . $newFileName // 返回文件的相对 URL
        ]);
        exit;
    } else {
        http_response_code(500); // Internal Server Error
        echo json_encode(['error' => '文件移动失败。']);
        exit;
    }
} else {
    // --- 7. 处理错误 ---
    $error = '上传失败。';
    if (isset($_FILES['upload']['error'])) {
        switch ($_FILES['upload']['error']) {
            case UPLOAD_ERR_INI_SIZE:
                $error = '上传的文件超过了 php.ini 中 upload_max_filesize 指令限制的值。';
                break;
            case UPLOAD_ERR_FORM_SIZE:
                $error = '上传文件的大小超过了 HTML 表单中指定的 MAX_FILE_SIZE。';
                break;
            case UPLOAD_ERR_PARTIAL:
                $error = '文件只有部分被上传。';
                break;
            case UPLOAD_ERR_NO_FILE:
                $error = '没有文件被上传。';
                break;
        }
    }
    http_response_code(400); // Bad Request
    echo json_encode(['error' => $error]);
    exit;
}
?>

upload.php 的工作流程:

  1. 设置响应头为 application/json
  2. 定义上传目录、允许的文件类型和最大大小。
  3. 检查 $_FILES 数组中是否有名为 upload 的文件(CKEditor 5 默认使用这个字段名)。
  4. 验证文件类型和大小,确保安全性。
  5. 生成一个唯一的文件名(避免文件名冲突和覆盖),然后将文件从临时目录移动到 uploads 目录。
  6. 如果成功,返回一个包含 url 字段的 JSON 对象,CKEditor 5 会用这个 URL 来显示图片。
  7. 如果失败,返回一个包含 error 字段的 JSON 对象,并设置相应的 HTTP 状态码。

回到 index.php,尝试点击编辑器中的图片上传按钮,你应该可以选择一张图片并成功上传到 uploads 目录。


第五步:数据保存与显示

现在编辑器可以用了,我们来处理用户编辑后的内容。

创建 save_data.php

这个脚本会接收 index.php 表单提交的数据,并将其保存到数据库或文件中。

假设我们使用 MySQL 数据库:

创建一个数据库和一张表:

CREATE DATABASE ckeditor_db;
USE ckeditor_db;
CREATE TABLE `posts` (
  `id` INT AUTO_INCREMENT PRIMARY KEY, VARCHAR(255) NOT NULL,
  `content` TEXT NOT NULL,
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

创建 save_data.php

<?php
// save_data.php
// 数据库连接信息 (请替换成你自己的)
$host = 'localhost';
$dbname = 'ckeditor_db';
$user = 'root'; // 你的数据库用户名
$pass = '';     // 你的数据库密码
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];
try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
    throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
// 获取表单提交的数据
$title = $_POST['title'] ?? '无标题'; // 假设你有一个 title 输入框
$content = $_POST['editor_content'] ?? '';
// 准备 SQL 语句
$sql = "INSERT INTO posts (title, content) VALUES (:title, :content)";
$stmt = $pdo->prepare($sql);
// 绑定参数并执行
$stmt->execute([
    ':title' => $title,
    ':content' => $content
]);
echo "内容已成功保存!<br>";
echo "<a href='view_post.php?id=" . $pdo->lastInsertId() . "'>查看文章</a>";
?>

注意:这个例子假设你的表单中还有一个 title 字段,如果没有,你可以去掉它。

安全地显示内容:创建 view_post.php

直接从数据库输出 HTML 内容是极其危险的,因为它可能导致 Cross-Site Scripting (XSS) 攻击,CKEditor 5 的内容可能包含 <script> 标签等恶意代码。

为了安全地显示内容,我们应该使用 PHP 的 strip_tags() 函数来移除所有 HTML 标签,或者使用更复杂的 HTML Purifier 库来净化内容。

简单移除所有 HTML (不推荐,会丢失格式)

<?php
// view_post.php (不安全示例)
$id = $_GET['id'] ?? 1;
$pdo = new PDO("mysql:host=localhost;dbname=ckeditor_db;charset=utf8mb4", "root", "");
$stmt = $pdo->prepare("SELECT * FROM posts WHERE id = ?");
$stmt->execute([$id]);
$post = $stmt->fetch();
// !!! 危险 !!! 直接输出未经处理的 HTML
echo "<h1>" . htmlspecialchars($post['title']) . "</h1>";
echo "<div>" . $post['content'] . "</div>"; // 这行代码是 XSS 漏洞
?>

安全地显示内容 (推荐)

最佳实践是使用一个专门的库来净化 HTML,HTML Purifier

  1. 安装 HTML Purifier: 最简单的方式是通过 Composer:

    composer require ezyang/htmlpurifier
  2. 创建 view_post.php (安全版本):

    <?php
    // view_post.php (安全示例)
    require_once 'vendor/autoload.php'; // 引入 Composer 的自动加载器
    use HTMLPurifier_Config;
    use HTMLPurifier;
    // 数据库连接 (同上)
    $id = $_GET['id'] ?? 1;
    $pdo = new PDO("mysql:host=localhost;dbname=ckeditor_db;charset=utf8mb4", "root", "");
    $stmt = $pdo->prepare("SELECT * FROM posts WHERE id = ?");
    $stmt->execute([$id]);
    $post = $stmt->fetch();
    if (!$post) {
        die("文章未找到。");
    }
    // 配置并创建 HTML Purifier 实例
    $config = HTMLPurifier_Config::createDefault();
    // 允许的 HTML 标签和属性
    $config->set('HTML.Allowed', 'p,b,i,u,a[href|title],ul,ol,li,br,strong,em,div,span[style],img[src|alt|style],table,thead,tbody,tr,th,td');
    // 允许的 CSS 样式 (为了安全,只允许特定样式)
    $config->set('CSS.AllowedProperties', 'text-align, float');
    $config->set('URI.AllowedSchemes', [
        'http' => true,
        'https' => true,
        // 'data' => true, // 不允许内嵌的 base64 图片
    ]);
    $purifier = new HTMLPurifier($config);
    // 净化从数据库获取的内容
    $clean_html = $purifier->purify($post['content']);
    // 安全地输出
    ?>
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title><?php echo htmlspecialchars($post['title']); ?></title>
    </head>
    <body>
        <h1><?php echo htmlspecialchars($post['title']); ?></h1>
        <div>
            <?php echo $clean_html; // 输出净化后的 HTML ?>
        </div>
    </body>
    </html>

当你保存内容后,点击“查看文章”,你就能看到格式良好的、安全的 HTML 内容了。


总结与进阶

恭喜!你已经成功地在 PHP 项目中集成了 CKEditor 5,并实现了完整的内容编辑、上传、保存和显示流程。

回顾关键点:

  1. 引入方式:通过 <script src="ckeditor/build/ckeditor.js"> 引入,并在页面底部用 ClassicEditor.create() 初始化。
  2. 配置:在 create() 函数的第二个参数中传入配置对象。
  3. 文件上传:通过 simpleUpload.uploadUrl 指向一个自定义的 PHP 处理脚本 (upload.php)。
  4. upload.php:负责接收文件、验证、保存,并返回 JSON 响应。
  5. 数据安全永远不要直接输出用户提交的 HTML,使用 strip_tags() 或更强大的 HTML Purifier 来净化内容,防止 XSS 攻击。

进阶学习方向:

  • 自定义插件:学习如何创建自己的 CKEditor 5 插件,添加特殊功能。
  • 内容过滤:深入研究 editor.config 中的 ckboxcontentSecurityPolicy 等高级配置,以实现更精细的内容控制。
  • API 集成:CKEditor 5 支持通过 API 与后端服务交互,可以实现更复杂的业务逻辑。

希望这份详细的教程能帮助你顺利地在项目中使用 CKEditor 5!