使用文档

YeCha 1.0.0 · 从安装到二次开发的一份完整手册。当前版本 1.0.0,本站现装 34 套主题、20 个插件(均可在 /theme 与 /plugin 在线浏览)。命令均可在生产直接执行;任何改动前先备份(库 + 文件 + 配置)。

本页导航

安装

环境要求

项目要求
PHP8.1+(推荐 8.3),扩展:pdo_mysql、mbstring、curl、simplexml、fileinfo、zip、openssl
数据库MySQL 5.7+ / MariaDB 10.3+,字符集 utf8mb4
Web 服务器Nginx 1.20+ 或 Apache 2.4+,需要能配置伪静态
目录站点根目录可写(uploads、var/cache、var/home-static)
可选HTTPS 证书、CDN(Cloudflare 等)

安装步骤

  1. 下载发布包,解压到站点根目录(docroot),确认 index.php、core/、themes/、plugins/ 在同一层。
  2. 建库:CREATE DATABASE yecha DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  3. 复制 config.inc.php.example 为 config.inc.php,填写数据库与 SECRET(见配置项)。
  4. 浏览器打开站点根目录,进入一次性安装向导;若已手动建表,访问 /install/ 会提示「已安装」。
  5. 配置伪静态(Nginx 最小可用):
location / { try_files $uri $uri/ /index.php?$query_string; }
location ~ ^/(var|data|install|tools|tests|core|config\.inc\.php) { deny all; }
location ~* \.(bak|orig|old|save|swp|tmp|sql|gz|log)$ { deny all; }
  1. 安装完成立即:改管理员口令、删除或锁死 install/ 目录、确认 core/ 不可直出。

目录权限

chown -R www:www /www/wwwroot/yecha.org
find /www/wwwroot/yecha.org -type d -exec chmod 755 {} \;
find /www/wwwroot/yecha.org -type f -exec chmod 644 {} \;
chmod -R 775 /www/wwwroot/yecha.org/uploads /www/wwwroot/yecha.org/var

常见安装错误

现象原因处理
打开 /install/ 得 403伪静态拒绝规则把安装目录也拦了把 install 从拒绝规则中拆出单独一条,不要加 ^~
整站 500,日志报 Unknown column 'c.words'1.0.0 内核列表按 ye_contents.words 取字数,旧库无该列ALTER TABLE ye_contents ADD COLUMN words INT UNSIGNED NOT NULL DEFAULT 0; 再回填 CHAR_LENGTH(content)
首页空白 / 模板不存在主题缺 views/landing.php 或 views/layout.php后台切回默认主题 yecha,或补齐模板
页面 404,后台正常伪静态未生效按上面 Nginx 规则配置并 nginx -t && nginx -s reload
上传图片失败uploads 不可写按「目录权限」修正属主

升级

升级前备份

B=/root/backup/$(date -u +%Y%m%dT%H%M%SZ); mkdir -p "$B"
mysqldump --single-transaction --routines yecha | gzip > "$B/yecha.sql.gz"
tar czf "$B/site.tar.gz" -C /www/wwwroot yecha.org --exclude='uploads/*' --exclude='var/cache/*'
cp -a /www/wwwroot/yecha.org/config.inc.php "$B/config.inc.php.orig"

升级步骤

  1. 覆盖内核文件(index.php、core/、admin/、lang/),保留 config.inc.php、uploads/、var/。
  2. 覆盖或新增主题/插件目录;同名主题建议先备份再覆盖。
  3. 插件迁移在插件启用时自动执行(内核 Upgrade::apply(),幂等,重复执行无副作用)。
  4. 清缓存并重建首页静态件(见缓存与静态件)。

升级后自检

  • 抽样 10 页是否 200,5xx 是否为 0;
  • 后台能登录、能保存设置;
  • 主题/插件列表条数与目录数一致;
  • /sitemap.xml、/feed 正常;
  • 多语站抽查 /en/ 与 /en/category/…/。

回滚

# 库
gunzip -c /root/backup/<时间>/yecha.sql.gz | mysql yecha
# 文件
tar xzf /root/backup/<时间>/site.tar.gz -C /www/wwwroot

主题开发

目录结构

themes/<id>/
  theme.json          # 元数据与后台可调设置
  style.css           # 主题样式
  views/
    layout.php        # 整页外壳(必须)
    landing.php       # 首页门户版式(可选,home.landing=1 时启用)
    landing-en.php    # 分语言首页(可选,/en/ 时优先)
    404.php
    partials/         # list / post / page / search / archives …
  logo.png / favicon.png

theme.json

字段说明
name / version / description显示名、版本、简介(后台与在线主题页读取)
requires_core依赖的内核版本
author / license作者与许可
settings后台可调项数组:key / type(select、color、number、checkbox) / label / def / opts
home设为 landing 时首页走门户版式

最小可用主题

themes/hello/theme.json:

{ "name": "Hello", "version": "0.1.0", "requires_core": "1.0.0", "description": "最小示例主题" }

themes/hello/views/layout.php:

<!DOCTYPE html><html lang="<?= e($htmlLang ?? 'zh-CN') ?>"><head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title><?= e($title) ?></title>
<link rel="stylesheet" href="<?= e(View::asset('style.css')) ?>">
</head><body>
<header><?php foreach (Nav::list('top', Lang::short()) as $n): ?>
<a href="<?= e($n['href']) ?>"<?= $n['active'] ? ' class="active"' : '' ?>><?= e($n['label']) ?></a>
<?php endforeach; ?></header>
<main><?= $main ?></main>
<aside><?= $side ?></aside>
</body></html>

模板与变量

  • $title 页面标题、$main 正文 HTML、$side 侧栏 HTML、$htmlLang 语言;
  • 常用函数:e() 转义、__() 语言包、site_label() 站点名、theme_opt('key','默认') 主题设置、Nav::list('top'|'foot') 导航、Poly::termUrl()/termName() 多语术语;
  • 资源用 View::asset('style.css') 输出带版本号的 URL(?v=mtime),改样式不用手工改版本。

调试与发布

  1. 目录放进 themes/,后台「主题」即可见并切换;
  2. 切换后清页面缓存、重建首页静态件(见缓存与静态件);
  3. 缺模板时内核会回落到默认主题 yecha 并在 var/log/php-error.log 留记录,不静默;
  4. 发布前逐套 php -l,并在 390 窄屏检查导航折叠。

插件开发

目录结构

plugins/<id>/
  plugin.php      # 清单(返回数组)
  boot.php        # 启用时注册钩子(register_file)
  admin.php       # 后台页(admin_file/admin_fn)
  page.php        # 前台独立页(page_file/page_fn)
  migrations/     # 幂等迁移 *.php 或 *.sql

plugin.php 清单

字段说明
id / name / ver / desc / author / license基本信息,在线插件页直接读取
requires.core依赖内核版本
toggle是否允许停用
tables自有表名(安装/卸载据此建表与清理)
pages前台页:[['slug'=>'hello','title'=>'示例']],路由 /<slug>
blocks侧栏块:[['id'=>'hello','label'=>'示例块']]
register_file启用时 include 的文件(通常 boot.php)
admin_file / admin_fn后台页文件与渲染函数
page_file / page_fn前台页文件与渲染函数,函数返回 ['html'=>…, 'title'=>…]
uninstall['tables'=>[], 'options'=>[], 'like'=>[]]

最小插件

plugins/hello/plugin.php:

<?php
return [
  'id' => 'hello', 'name' => '示例插件', 'ver' => '0.1.0',
  'desc' => '最小插件示例', 'author' => 'YeCha', 'license' => 'MIT',
  'requires' => ['core' => '1.0.0'], 'toggle' => true,
  'pages' => [['slug' => 'hello', 'title' => '示例页']],
  'register_file' => 'boot.php',
  'page_file' => 'page.php', 'page_fn' => 'hello_page',
];

plugins/hello/boot.php:

<?php
Hooks::on('front.head', function (array $p): array { return $p; }, 10);

plugins/hello/page.php:

<?php
function hello_page(string $slug): array {
  return ['html' => '<h1>Hello</h1><p>来自示例插件。</p>', 'title' => '示例页 · ' . site_label()];
}

放置后在后台「插件」启用即生效;前台访问 /hello。

路由、权限与迁移

  • 多级路径:内核把 /<slug>/… 交给插件页,子路径在 $GLOBALS['YC_PLUGIN_PATH'] 中;
  • 后台页需管理员会话;表单必须带 Csrf::field() 并 Csrf::check();
  • 迁移写在 migrations/,用 CREATE TABLE IF NOT EXISTS / 先查后建,保证幂等;
  • 停用只停止注册,数据保留;卸载按 uninstall 清理。

配置项

config.inc.php

常量说明
DB_HOST / DB_PORT / DB_NAME / DB_USER / DB_PASS数据库连接
DB_PREFIX表前缀,默认 ye_
SECRET站点密钥:会话、加密(AI Key 等)都用它;换掉会让已加密的密钥失效
TZ时区,默认 Asia/Shanghai
SITE_LANG默认界面语言,如 zh_CN
DEBUG生产必须 false;true 会把错误显示到页面

站点选项(options 表)

选项说明
site.name / site.name_en站点中文名 / 英文名(/en/ 下显示英文名)
site.subtitle / site.subtitle_en副标题 / 英文副标题
site.languages / site.default_lang启用语言与默认语言,如 ["zh","en"]
theme.default / theme.options当前主题与主题设置
home.landing1 = 首页使用主题的门户版式
nav.hide_top / nav.hide_foot / nav.custom顶部/页脚隐藏项与自定义导航
stats.head / stats.foot统计代码位(留空即零外发)
market.source云市场清单地址,留空 = 本站 var/market/manifest.json

密钥与敏感信息

  • 不要把任何密钥写进主题/插件源码或仓库;AI、短信、支付等密钥一律在后台填写,入库前用 SECRET 加密,界面不回显明文;
  • SECRET 只存在 config.inc.php(权限 640、属主 root:www),不进版本库;
  • 轮换 SECRET 前先导出并重新录入受影响的密钥,否则旧密文无法解密;
  • 日志、报错页、导出文件都不得包含密钥;DEBUG=true 只允许在本机临时使用。

缓存与静态件

位置作用何时清理
var/cache/pages全页缓存改内容/主题/菜单后
var/cache/blocks侧栏与区块缓存改侧栏/插件后
var/home-static/首页烘焙件(含 /en/)改首页/主题/统计代码后
# 清缓存(也可后台「工具 → 清缓存」)
php -r 'chdir("/www/wwwroot/yecha.org"); require "config.inc.php"; require "core/bootstrap.php"; Cache::flush("pages"); Cache::flush("blocks");'
# 重建首页静态件
curl -s -H 'Host: yecha.org' https://127.0.0.1/ >/dev/null   # 或后台「首页生成静态 → 立即生成」

常见问题

/en/category/xxx/ 返回 500?

旧库缺 ye_contents.words 列。按常见安装错误加列并回填,然后清页面缓存。

换了主题,首页看起来没变?

首页有烘焙静态件(var/home-static/index.html 与 en/index.html)。删除或重新生成后才会按新主题渲染。

后台登录后马上跳回登录页?

多为 HTTPS 判定与会话 Cookie 不一致:确认源站 fastcgi_param HTTPS on、site.url 与访问域名一致,并清一次浏览器 Cookie。

多语内容不显示?

确认 poly 插件已启用、site.languages 含该语言、且译文状态为 publish;术语名/别名在后台「多语言」维护。

云市场安装失败?

只接受 https 且强制 SHA-256 校验;检查包结构与 plugin.php/theme.json 是否齐全,PHP 是否全部 php -l 通过。

如何只保留官网、关闭博客?

启用 site 插件并在后台切到官网模式;博客文章改走 301,插件详情与文档页不受影响。需要恢复时一键切回博客模式。

如何迁移站点?

导出库 + 打包站点文件(含 uploads/),在新机按安装配好环境、导入库、改 config.inc.php,最后清缓存并重建静态件。