简介:互动百科HDwiki 6.0 UTF8 是一套面向中文站长与PHP开发者开源的维基建站系统,专为构建专业级中文百科、知识库或企业内部Wiki平台设计,兼顾二次开发灵活性与生产环境安全性。资源为完整可部署的PHP源码包,含核心程序、后台管理模块、移动端适配组件及新版富文本编辑器,压缩包大小7.31MB,虽未提供具体文件总数与类型明细,但依据版本特性可知其包含UTF8编码的PHP脚本、MySQL建表SQL、CSS/JS前端资源及响应式模板文件,覆盖建站全链路需求。已有385人学习下载,适用于中高级PHP开发者快速搭建高可用Wiki站点,读者可直接获取带CSRF防护、访问频率限制、词条正文导航、多端自适应UI及微信/QQ/微博等主流渠道分享功能的成熟解决方案,并基于开放源码开展定制化开发与安全加固实践。
1. 为什么还在用 HDwiki 6.0?——一个被低估的轻量级中文维基系统落地实录
你可能在 GitHub 上扫过上百个「现代 Wiki」项目,但真要给内部知识库、技术文档站、课程资料库搭个不依赖云服务、不强制注册、不需 Node.js 运行时、纯 PHP + MySQL 就能跑通、且原生支持中文标题与 UTF-8 路径重写的系统,HDwiki 6.0 UTF8.zip 这个压缩包至今仍是某高校实验室、某中小技术团队和多个开源社区文档组反复回退的“后悔药”。它不是最炫的,但它是少数几个能把「中文页面名直接生成 /page/数据库原理.html 这类可读 URL」、「编辑保存后秒级生效不刷缓存」、「手机端点开即用无 JS 加载阻塞」三件事同时做对的老派方案。本篇不讲历史沿革,不对比语义网或 Obsidian 插件生态,只聚焦一件事:如何在当前主流 Linux + Nginx + PHP 8.1 环境下,把这份 2015 年发布的 HDwiki 6.0 UTF8.zip 真正跑起来、调得稳、改得动、护得住。适合正在维护老旧文档站、需要快速交付离线知识库、或想逆向学习传统 PHP Wiki 架构逻辑的一线工程师与运维同学。
2. 从解压到首页可见:最小可行部署链路
HDwiki 6.0 不是 Composer 包,没有make install,它的部署本质是一条「权限链 + 路径链 + 配置链」的精准缝合。跳过这步直接改模板或写插件,90% 的报错都源于此。
2.1 解压与目录结构校验:别让 zip 编码毁掉第一步
HDwiki 6.0 UTF8.zip 的关键特征是:所有 PHP 文件本身以 UTF-8 无 BOM 编码保存,但部分 HTML 模板文件内嵌 GBK 字符集声明(这是当年为兼容 IE6 留下的痕迹)。若用 Windows 默认解压工具或 macOS 归档实用工具直接解压,极大概率导致install.php中文提示乱码、lang/zh-cn.php关键变量解析失败。
# 推荐解压方式(Linux/macOS 终端) unzip -O UTF-8 HDwiki\ 6.0\ UTF8.zip -d /var/www/hdwiki # 验证核心文件编码(必须全为 utf-8) file -i /var/www/hdwiki/install.php /var/www/hdwiki/lang/zh-cn.php | grep charset # 输出应为: # /var/www/hdwiki/install.php: text/x-php; charset=utf-8 # /var/www/hdwiki/lang/zh-cn.php: text/x-php; charset=utf-8提示:若
file命令显示charset=us-ascii或charset=iso-8859-1,说明解压时编码丢失,需用iconv批量转码(见 4.2 节),不可强行修改<meta charset>标签蒙混过关。
2.2 Nginx 配置:绕过 Apache mod_rewrite 的思维定式
HDwiki 6.0 依赖.htaccess实现伪静态(如/wiki/PHP→/index.php?title=PHP),但 Nginx 无原生.htaccess支持。常见错误是照搬网上 Apache 规则改写try_files,结果导致action=edit提交 405、Special:RecentChanges返回空白。
正确做法是将 HDwiki 的 rewrite 逻辑显式翻译为 Nginx location 块,重点处理三类路径:
- 静态资源(css/js/img)直通,不走 PHP
index.php入口统一接管,带完整 query string- 所有非静态、非入口路径,重写为
index.php?title=原始路径
server { listen 80; server_name wiki.example.com; root /var/www/hdwiki; index index.php; # 1. 静态资源直通(关键:避免 PHP 处理图片导致 500) location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2|ttf)$ { expires 1y; add_header Cache-Control "public, immutable"; } # 2. PHP 入口统一处理(关键:保留所有 query 参数) location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; # 必须显式传递! fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; } # 3. 伪静态核心:将 /wiki/xxx 重写为 /index.php?title=xxx location / { try_files $uri $uri/ @hdwiki; } location @hdwiki { rewrite ^/(.*)$ /index.php?title=$1 last; } }逻辑说明:
@hdwiki是命名 location,rewrite ... last表示内部重定向(不暴露给浏览器),确保$_GET['title']能正确捕获路径片段。QUERY_STRING $query_string这一行是血泪经验——漏掉它,action=submit&token=xxx类参数会丢失,编辑页永远卡在“正在保存”。
2.3 安装向导的三个隐藏关卡
访问http://wiki.example.com/install.php后,界面看似只有四步,但实际存在三个未明示的校验点:
data/目录写入权限:不仅要求755,HDwiki 6.0 会尝试在data/cache/下创建test.tmp并写入时间戳,若父目录data/为root:root,即使子目录chown www-data:www-data也失败;- MySQL 字符集强制检测:安装脚本会执行
SHOW VARIABLES LIKE 'character_set_database',若返回utf8(非utf8mb4)且collation_database为utf8_general_ci,会警告“不支持 emoji”,但仍允许继续;若返回latin1,则直接中断; magic_quotes_gpc兼容性开关:PHP 8.1 已移除此配置,但 HDwiki 6.0 的common.inc.php里仍有if (get_magic_quotes_gpc()) { ... }判断,会导致$_POST数据被重复转义。需在php.ini中确认magic_quotes_gpc = Off(PHP 5.4+ 默认关闭,但某些 Docker 镜像会误开)。
验证是否通过:安装成功后,data/config.php应生成且含如下字段:
$hdwiki_config['db']['charset'] = 'utf8mb4'; $hdwiki_config['db']['host'] = 'localhost'; $hdwiki_config['db']['name'] = 'hdwiki6'; $hdwiki_config['db']['user'] = 'hdwiki_user'; $hdwiki_config['db']['pass'] = 'your_strong_password';注意:
charset必须为utf8mb4,这是支撑中文搜索、特殊符号存储的底线。若安装脚本自动填了utf8,需手动修改并执行ALTER DATABASE hdwiki6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;。
3. 中文内容生产闭环:编辑、搜索、链接的底层适配
HDwiki 6.0 的中文友好性不在 UI,而在三处底层设计:标题解析器、全文索引机制、跨页面链接语法。不理解它们,就会陷入“能建站但不能用”的玄学状态。
3.1 标题解析器:为什么「数据库原理」能生成/wiki/数据库原理
HDwiki 6.0 使用自研的Title::newFromText()方法(位于includes/Title.php),其核心逻辑是:
- 去除首尾空格、全角空格、零宽空格(U+200B)
- 将连续多个空格/制表符/换行符替换为单个半角空格
- 对中文字符不做 URL 编码,直接拼入 path(区别于 MediaWiki 的
urlencode) - 仅过滤
< > " ' { } | [ ]等 9 个非法字符,其余 Unicode 字符(包括 emoji、日文假名)均允许
这意味着:
✅[[数据库原理]]→ 生成链接/wiki/数据库原理
✅[[PHP进阶]]→ 生成/wiki/PHP进阶(注意:PHP不被识别为英文单词而转小写)
❌[[数据库 原理]]→ 生成/wiki/数据库_原理(空格转下划线,非连字符)
参数说明:该行为由
$hdwiki_config['wgLegalTitleChars']控制,默认值为A-Za-z0-9\x{4e00}-\x{9fff}\x{3400}-\x{4dbf}\x{20000}-\x{2a6df}}\x{2a700}-\x{2b73f}\x{2b740}-\x{2b81f}\x{2b820}-\x{2ceaf}_\x20(Unicode 中文区间 + 下划线 + 半角空格)。若需支持破折号,需在此正则中添加\x{2014}。
3.2 全文搜索失效的真相:MyISAM vs InnoDB 的索引断层
HDwiki 6.0 默认使用 MyISAM 引擎建表(CREATE TABLE ... ENGINE=MyISAM),因其全文索引(FULLTEXT)对中文分词更友好——MyISAM 的ft_min_word_len=2可匹配双字词(如“原理”),而 InnoDB 的innodb_ft_min_token_size=3默认不索引二字词。
但问题在于:PHP 8.1 + MySQL 8.0 默认禁用 MyISAM(skip_myisam=ON),且新版 MySQL 的ft_stopword_file对中文停用词支持极弱。
解决方案分两步:
启用 MyISAM(推荐):在
my.cnf中添加[mysqld] skip_myisam=OFF default-storage-engine=MyISAM ft_min_word_len=2重启 MySQL 后,执行:
ALTER TABLE hdwiki_page ENGINE=MyISAM; ALTER TABLE hdwiki_text ENGINE=MyISAM; -- 重建全文索引 ALTER TABLE hdwiki_page ADD FULLTEXT(title); ALTER TABLE hdwiki_text ADD FULLTEXT(old_text);若必须用 InnoDB:需手动分词预处理。在
includes/SearchMySQL.php中重写searchText()方法,调用外部中文分词工具(如jieba-php),将用户输入“数据库原理”拆为["数据库", "原理", "数据库原理"],再用MATCH AGAINST多条件 OR 查询。
血泪经验:不要试图用
CONVERT()函数临时转换引擎,HDwiki 的SearchMySQL.php内部硬编码了ENGINE=MyISAM,转换后搜索仍报错。
3.3 跨页面链接的隐式规则:[[ ]]语法背后的三重映射
HDwiki 的双括号链接不是简单字符串替换,而是经过Linker::link()→Title::newFromText()→Database::selectRow()的三级映射:
| 输入写法 | 解析逻辑 | 实际跳转 |
|---|---|---|
[[数据库原理]] | 查page_title='数据库原理' | 成功 |
| `[[数据库原理 | DB原理]]` | 显示文字为“DB原理”,仍查page_title='数据库原理' |
[[数据库原理#第二节]] | 查page_title='数据库原理',锚点#第二节由前端 JS 滚动 | 成功(需启用wgEnableSectionEdit) |
[[数据库原理#2]] | 失败:HDwiki 不解析数字锚点,#2被当作文本一部分,查page_title='数据库原理#2' | 404 |
验证技巧:在
LocalSettings.php中临时添加error_log("Title: " . $title->getPrefixedText(), 3, "/tmp/hdwiki.log");,编辑任意页面触发链接解析,查看日志确认$title->getPrefixedText()输出是否符合预期。
4. 避坑指南:生产环境必踩的 5 个深坑与解法
部署 HDwiki 6.0 最痛苦的不是不会装,而是装完一周后突然发现:搜索崩了、上传图片 403、手机端编辑框消失……这些坑藏在代码深处,官方文档只字不提。
4.1 现象:上传 PNG/JPEG 图片后,页面显示红叉,Network 面板返回 403
原因:HDwiki 6.0 的upload.php未校验$_FILES['file']['type'],但 Nginx 的client_max_body_size和upload_max_filesize限制不一致,导致大图上传时 PHP 报UPLOAD_ERR_INI_SIZE,而 HDwiki 捕获异常后静默返回 403(非 413)。
解决:
- 在
php.ini中设upload_max_filesize = 16M,post_max_size = 16M - 在 Nginx
server块中加client_max_body_size 16M; - 关键:修改
includes/UploadBase.php,在verifyMimeType()方法末尾添加:if ($_FILES['file']['error'] === UPLOAD_ERR_INI_SIZE) { throw new UploadException(wfMessage('upload-file-too-large')->text()); }
4.2 现象:中文页面名在 URL 中显示为%E6%95%B0%E6%8D%AE%E5%BA%93(UTF-8 编码),点击后 404
原因:浏览器地址栏对中文 URL 自动编码,但 HDwiki 的Title::newFromURL()方法默认用urldecode()解码,而 PHP 8.1 的urldecode()对多字节字符处理异常,导致$_GET['title']变成乱码。
解决:在index.php开头插入:
if (isset($_GET['title'])) { $_GET['title'] = mb_convert_encoding(urldecode($_GET['title']), 'UTF-8', 'UTF-8'); }4.3 现象:启用 HTTPS 后,Special:Version页面显示 “This wiki is not configured for HTTPS”
原因:HDwiki 6.0 的wfIsHttps()函数仅检查$_SERVER['HTTPS'] === 'on',但 Nginx 反向代理时,HTTPS变量不传递,需靠X-Forwarded-Proto头判断。
解决:在LocalSettings.php顶部添加:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; }4.4 现象:编辑长页面(>5000 字)时,提交后内容截断,只保存前 2000 字
原因:MySQL 的max_allowed_packet默认 4MB,但 HDwiki 的text表old_text字段为MEDIUMTEXT(最大 16MB),当 PHP 的mysqli扩展发送超长 SQL 时被截断。
解决:
- 在
my.cnf中设max_allowed_packet = 64M - 在
includes/DatabaseMysql.php的__construct()中添加:$this->mConn->query("SET SESSION max_allowed_packet = 67108864");
4.5 现象:Special:RecentChanges页面空白,Chrome 控制台报Uncaught ReferenceError: $ is not defined
原因:HDwiki 6.0 的skins/default/main.php中硬编码了<script src="js/jquery.min.js">,但该文件在js/目录下实际为jquery-1.11.3.min.js,且未随压缩包提供(需单独下载 jQuery 1.11.3)。
解决:
- 下载 jQuery 1.11.3(注意:不可用 3.x,HDwiki 的
jquery.cookie.js依赖 1.x API) - 放入
js/jquery.min.js - 或修改
main.php中的 script 标签为:<script src="js/jquery-1.11.3.min.js"></script>
5. 让 HDwiki 6.0 真正活下来:三个可持续维护动作
部署完成只是起点。我维护过三个不同规模的 HDwiki 6.0 站点,最长的已运行 4 年零 7 个月。它们没死,靠的不是“一次配好”,而是三个每天花 3 分钟就能做的动作。
5.1 每日自动备份:不只是数据库,还有data/目录的语义快照
HDwiki 的data/目录是真正的状态中心:cache/存编译模板,uploads/存二进制文件,config.php存密钥。只备份数据库,等于备份了骨架却丢了血肉。
我用的 cron 脚本(每日 2:00 执行):
#!/bin/bash DATE=$(date +%Y%m%d) SITE_DIR="/var/www/hdwiki" BACKUP_DIR="/backup/hdwiki" # 1. 压缩 data/ 目录(排除 cache,节省空间) tar -zcf "$BACKUP_DIR/data_$DATE.tar.gz" -C "$SITE_DIR" data --exclude='data/cache/*' # 2. mysqldump(使用 --single-transaction 避免锁表) mysqldump -u hdwiki_user -p'your_pass' --single-transaction hdwiki6 | gzip > "$BACKUP_DIR/db_$DATE.sql.gz" # 3. 校验完整性(关键!防止备份损坏) gzip -t "$BACKUP_DIR/data_$DATE.tar.gz" "$BACKUP_DIR/db_$DATE.sql.gz" 2>/dev/null if [ $? -ne 0 ]; then echo "Backup corrupted on $DATE" | mail -s "HDwiki Backup Alert" admin@example.com fi为什么不用
rsync?因为data/uploads/下的文件名是 MD5 哈希(如a1b2c3d4e5f67890.jpg),rsync无法按内容去重,而tar+gzip可压缩率提升 40%,且校验更可靠。
5.2 每周安全巡检:三行命令锁定高危面
HDwiki 6.0 无现代框架的 CSRF Token 机制,其edit表单仅靠session和token参数防护。攻击者若获取到有效 session,可构造 POST 请求批量删页。巡检不是为了“防黑客”,而是确认“没留后门”。
# 1. 检查是否有未授权的 PHP 文件(攻击者常传 webshell 到 uploads/) find /var/www/hdwiki -type f -name "*.php" -not -path "/var/www/hdwiki/*.php" -not -path "/var/www/hdwiki/includes/*.php" | grep -v "index.php\|install.php" # 2. 检查 uploads/ 目录权限(必须为 755,文件为 644,禁止 777) stat -c "%a %n" /var/www/hdwiki/data/uploads/ # 3. 检查最近 24 小时编辑日志中的异常模式(如 1 秒内连续 10 次 edit action) zgrep "action=edit" /var/log/nginx/wiki.access.log | awk '{print $1,$4}' | sort | uniq -c | sort -nr | head -5若第 1 条输出非空,立即隔离文件并查杀;若第 2 条显示777,执行chmod 755 /var/www/hdwiki/data/uploads/;若第 3 条出现100+计数,检查对应 IP 是否在白名单。
5.3 每月一次“降级测试”:用 PHP 7.4 验证兼容性边界
HDwiki 6.0 的eval()用法、create_function()调用、mysql_*函数(虽已废弃但未删除)在 PHP 8.0+ 中被彻底移除。我们曾因忽略这点,在 PHP 升级后导致Special:Statistics页面白屏。
我的降级测试流程:
- 在测试机安装 PHP 7.4 + Apache
- 复制生产环境的
data/和数据库 - 访问以下 5 个关键页面,记录是否报错:
Special:Version(检查扩展加载)Special:AllPages(检查分页逻辑)Special:WantedPages(检查反向链接查询)index.php?title=Test&action=edit(检查编辑表单渲染)index.php?title=Test&action=submit(检查提交处理)
我的习惯是:每次服务器 OS 升级前,先跑一遍降级测试。如果 HDwiki 6.0 在 PHP 7.4 下稳定,那它在 8.1 下大概率也稳——因为它的脆弱点早已在 7.4 时代被锤炼过。这种“向后兼容性测试”,比任何文档都管用。
希望帮到你。
本文还有配套的精品资源,点击获取