一、项目背景与环境概述

1.1 项目信息

  • 项目名称: Cleanl.de (新视点/ThinkCMF 6.0)
  • 框架版本: ThinkPHP 6.0.14 LTS + ThinkCMF 6.0.8
  • PHP 版本要求: ≥ 7.4.0 (推荐 8.0+)
  • 数据库: MySQL 5.7+ (备份来自 5.7.40-log)

1.2 服务器环境

  • 控制面板: Plesk Obsidian (Webhosting.netcup)
  • Web 服务器: Apache + mod_fcgid (FastCGI)
  • PHP 版本: 8.5.4 (NTS)
  • 数据库服务器: MySQL 8.0.44 (外部服务器 10.35.232.191:3306)
  • 操作系统: Linux (Debian/Ubuntu 系列)

1.3 项目结构特点

ThinkCMF 采用安全目录结构

1
2
3
4
5
6
7
8
9
10
cleanl.de/                 # 项目根目录
├── app/ # 应用代码 (不可Web访问)
├── data/ # 数据配置 (不可Web访问)
├── vendor/ # Composer依赖 (不可Web访问)
├── public/ # Web根目录 (唯一可访问)
│ ├── index.php # 入口文件
│ ├── static/ # 静态资源
│ ├── themes/ # 模板文件
│ └── upload/ # 上传目录
└── ...

关键要求: Web服务器必须将 public/ 作为文档根目录(DocRoot)。


二、部署过程中遇到的核心问题

2.1 问题一:Plesk 文档根目录锁定

现象: Plesk 强制使用 httpdocs/ 作为 Web 根目录,且面板中无法修改。

影响:

  • 无法直接将 public/ 设置为 Web 根目录
  • 导致项目核心文件暴露在 Web 可访问范围外或内,要么不安全要么无法运行

错误表现:

1
2
500 Internal Server Error
AH01276: Cannot serve directory ... No matching DirectoryIndex

2.2 问题二:open_basedir 安全限制

现象: PHP 的 open_basedir 被 Plesk 锁定,只允许访问:

1
/var/www/vhosts/hosting238905.ae8be.netcup.net/httpdocs/:/tmp/:...

影响:

  • 即使创建软链接 httpdocs -> public,PHP 也无法加载 vendor/autoload.php
  • 因为 vendor/ 在项目根目录,不在 httpdocs/

错误表现:

1
2
PHP 警告:require():open_basedir 限制生效。
文件(/var/www/.../vendor/autoload.php)不在允许的路径内

2.3 问题三:MySQL 8.0 行格式兼容性问题

现象: 原始 SQL 备份使用 ROW_FORMAT=COMPACT (MySQL 5.7 默认)。

影响:

  • MySQL 8.0 对行大小限制更严格 (最大 8126 字节)
  • 表中有大量 varchar(255) 字段,在 utf8mb4 下超出限制

错误表现:

1
2
3
Error 1118 (42000): Row size too large (> 8126)
Changing some columns to TEXT or BLOB may help.
In current row format, BLOB prefix of 768 bytes is stored inline.

2.4 问题四:字符编码混乱

现象: 原始 SQL 文件为 GBK/GB2312 编码,包含中文注释。

影响:

  • Plesk phpMyAdmin 默认使用 UTF-8 解析
  • GBK 中文字符被错误解析,导致引号不匹配、SQL 语法错误
  • COMMENT 字段内容截断,破坏 SQL 结构

错误表现:

1
2
3
#1064 - You have an error in your SQL syntax
near '' at line X
静态分析:不应出现的开始声明。无法识别的声明形式。

2.5 问题五:.htaccess 配置冲突

现象: ThinkCMF 默认 .htaccess 使用 Options +FollowSymlinks

影响:

  • Plesk/Apache 配置不允许 .htaccess 中使用 FollowSymlinks 选项
  • 导致 500 错误

错误表现:

1
[core:alert] .htaccess:此处不允许使用 FollowSymlinks 选项

2.6 问题六:数据库表缺失

现象: 成功启动后报错 Table 'cmf_portal_visits' doesn't exist

原因: SQL 导入过程中断或失败,部分表未创建。


三、解决方案详解

3.1 方案一:重构目录结构(核心解决方案)

由于 Plesk 锁定 httpdocsopen_basedir 限制,唯一可行方案是将项目核心文件移入 httpdocs

操作步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 进入域名根目录
cd ~/hosting238905.ae8be.netcup.net/

# 2. 删除旧的 httpdocs(如果是软链接或空目录)
rm -rf httpdocs

# 3. 将项目移到域名目录下(如果尚未移动)
mv ~/kkkkk/cleanl.de .

# 4. 将 public 重命名为 httpdocs
mv cleanl.de/public httpdocs

# 5. 将核心文件复制到 httpdocs 内(突破 open_basedir 限制)
cp -r cleanl.de/vendor httpdocs/
cp -r cleanl.de/data httpdocs/
cp -r cleanl.de/app httpdocs/
cp -r cleanl.de/extend httpdocs/ 2>/dev/null || true

# 6. 修改入口文件 index.php
cd httpdocs
nano index.php

index.php 修改内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
namespace think;

// 修改为当前目录 (httpdocs)
define('CMF_ROOT', __DIR__ . '/');
define('CMF_DATA', CMF_ROOT . 'data/');
define('APP_PATH', CMF_ROOT . 'app/');
define('WEB_ROOT', __DIR__ . '/');

require CMF_ROOT . 'vendor/autoload.php';

$http = (new App())->http;
$response = $http->run();
$response->send();
$http->end($response);

优势:

  • ✅ 所有 PHP 需要加载的文件都在 httpdocs 内,符合 open_basedir
  • ✅ Web 服务器直接访问 httpdocs (原 public),符合 ThinkCMF 设计
  • ✅ 无需修改 Plesk 配置

3.2 方案二:数据库 SQL 文件修复

由于原始 SQL 文件存在 编码问题行格式问题,需要修复。

修复内容:

  1. 字符编码转换: GBK → UTF-8
  2. 删除损坏的 COMMENT 字段: 避免引号不匹配导致的语法错误
  3. 替换 ROW_FORMAT: COMPACTDYNAMIC

修复后的 SQL 特征:

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 修复前(有问题)
CREATE TABLE `cmf_admin_menu` (
`id` int(10) UNSIGNED NOT NULL,
`status` tinyint(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT '状态;1:显示,0:不显示',
...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台菜单表' ROW_FORMAT=COMPACT;

-- 修复后(可用)
CREATE TABLE `cmf_admin_menu` (
`id` int(10) UNSIGNED NOT NULL,
`status` tinyint(3) UNSIGNED NOT NULL DEFAULT '0',
...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

导入方法:

方法 A - SSH 命令行(推荐):

1
2
3
cd ~/kkkkk/
mysql -h 10.35.232.191 -u k358602_cleanl.de1 -p k358602_cleanlde < www_kelin_de_final.sql
# 密码: CleanAMT2022

方法 B - phpMyAdmin:

  1. Plesk → 数据库 → phpMyAdmin
  2. 选择数据库 k358602_cleanlde
  3. 导入 → 选择文件 www_kelin_de_final.sql
  4. 字符集: utf8mb4
  5. 点击执行

3.3 方案三:.htaccess 修复

修改 httpdocs/.htaccess,移除不被允许的指令:

1
2
3
4
5
6
7
<IfModule mod_rewrite.c>
Options -Indexes -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1]
</IfModule>

关键修改:

  • ❌ 删除: Options +FollowSymlinks
  • ✅ 保留: Options -Indexes -Multiviews

3.4 方案四:PHP 配置调整

在 Plesk 面板中:

  1. PHP 版本: 选择 8.0+ (实际使用 8.5.4)
  2. 运行模式: FastCGI 应用程序
  3. 必需扩展(确保已启用):
    • pdo_mysql
    • mysqli
    • curl
    • mbstring
    • gd
    • fileinfo
    • openssl
    • zip

3.5 方案五:数据库连接配置

创建/编辑 .env 文件:

1
2
cd ~/hosting238905.ae8be.netcup.net/httpdocs
nano .env

内容:

1
2
3
4
5
6
7
8
9
APP_DEBUG = false
APP_DEFAULT_TIMEZONE = Asia/Shanghai

DATABASE_HOSTNAME = 10.35.232.191
DATABASE_DATABASE = k358602_cleanlde
DATABASE_USERNAME = k358602_cleanl.de1
DATABASE_PASSWORD = CleanAMT2022
DATABASE_HOSTPORT = 3306
DATABASE_PREFIX = cmf_

3.6 方案六:目录权限设置

1
2
3
cd ~/hosting238905.ae8be.netcup.net/httpdocs
chmod -R 755 data/runtime/
chmod -R 755 upload/

四、完整的部署流程(按顺序执行)

步骤 1: 上传项目文件

1
# 通过 FTP/SSH 将 cleanl.de 上传到 ~/hosting238905.ae8be.netcup.net/

步骤 2: 重构目录结构

1
2
3
4
5
6
cd ~/hosting238905.ae8be.netcup.net/
rm -rf httpdocs
mv cleanl.de/public httpdocs
cp -r cleanl.de/vendor httpdocs/
cp -r cleanl.de/data httpdocs/
cp -r cleanl.de/app httpdocs/

步骤 3: 修改 index.php

CMF_ROOTdirname(__DIR__) 改为 __DIR__

步骤 4: 配置 .env

设置数据库连接信息。

步骤 5: 修复并导入数据库

使用 www_kelin_de_final.sql(已修复编码和行格式)。

步骤 6: 修复 .htaccess

移除 FollowSymlinks

步骤 7: 设置权限

1
2
chmod -R 755 data/runtime/
chmod -R 755 upload/

步骤 8: 访问测试

  • 前台: https://hosting238905.ae8be.netcup.net/
  • 后台: https://hosting238905.ae8be.netcup.net/admin

五、关键经验总结

5.1 关于 Plesk 共享主机

  • 文档根目录锁定是常见限制,无法像 VPS 那样自由配置
  • open_basedir 严格限制 PHP 文件访问范围,必须在 httpdocs 内完成所有操作
  • 符号链接在 open_basedir 环境下无效,因为 PHP 会解析真实路径

5.2 关于 MySQL 8.0 迁移

  • 从 MySQL 5.7 迁移到 8.0 时,ROW_FORMAT=COMPACT 是常见坑点
  • 大量 varchar(255) + utf8mb4 的组合容易触发行大小限制
  • 解决方案: 统一使用 ROW_FORMAT=DYNAMIC

5.3 关于字符编码

  • 旧项目常为 GBK/GB2312,新环境应为 UTF-8
  • SQL 导入时,字符集选择必须与文件实际编码匹配
  • 建议: 在源头修复编码问题,不要依赖导入工具的自动转换

5.4 安全建议

  • 当前方案将 vendor/ 等敏感目录放入 httpdocs,理论上存在安全风险
  • 缓解措施: 确保 .htaccess 正确配置,禁止直接访问 PHP 文件
  • 理想方案: 升级至 VPS 以获得完整的 Web 服务器配置权限

六、故障排查速查表

错误现象 可能原因 解决方案
500 Error + FollowSymlinks .htaccess 配置不被允许 移除 Options +FollowSymlinks
open_basedir restriction PHP 访问了 httpdocs 外文件 将 vendor/data/app 移入 httpdocs
Row size too large MySQL 8.0 行格式限制 SQL 中 ROW_FORMAT=COMPACTDYNAMIC
SQL syntax error near COMMENT 字符编码问题导致引号不匹配 删除 SQL 中的 COMMENT 字段或修复编码
Table doesn’t exist 数据库导入不完整 重新导入修复后的 SQL 文件
No matching DirectoryIndex httpdocs 下缺少 index.php 确保 public 内容已正确移动到 httpdocs

七、相关文件清单

文件名 说明 位置
www_kelin_de_final.sql 修复后的数据库备份(UTF-8 + DYNAMIC) ~/kkkkk/
.env 环境配置文件(数据库连接) ~/httpdocs/
index.php 修改后的入口文件 ~/httpdocs/
.htaccess 修改后的重写规则 ~/httpdocs/
data/config/database.php 数据库配置(备选) ~/httpdocs/data/config/

文档生成日期: 2026-04-01
适用项目: cleanl.de (ThinkCMF 6.0)
服务器环境: Plesk + Apache + PHP 8.5 + MySQL 8.0