TBlog v1.2.1 — Bug 修复版

This commit is contained in:
zhang-pu 2026-06-03 11:18:12 +08:00
parent 2a5bdcbc4e
commit 3fc988e951
16 changed files with 192 additions and 98 deletions

View file

@ -4,7 +4,31 @@
---
## [v1.2.0] - 2024-05-31
## [v1.2.1] - 2026-06-03
### 🐛 Bug 修复
- ✅ 修复发布/编辑文章时 `mysqli_stmt::bind_param(): Argument #3 cannot be passed by reference` 致命错误
- 原因:`bind_param()` 第三个参数传入了表达式 `$existing['id'] ?? 0`,PHP 7.4+ 不允许以引用方式传递表达式
- 修复:先赋值到变量 `$exclude_id`,再传给 `bind_param()`
- ✅ 修复 `get_post_by_id()` 在 ID 不存在时返回 `null`,后续 `$post['xxx']` 触发 PHP 8 warning
- 修复:找不到记录时返回空数组 `[]`
- ✅ 修复 `get_category_by_id()` 同上问题
- ✅ 修复 `admin/post.php` 编辑文章时 `$edit_post` 未做 null 防御
- ✅ 修复 `admin/category.php` 编辑分类时 `$edit_category` 未做 null 防御
### ✨ 新增
- ✅ 新增 `TBLOG_VERSION` 常量(`include/db.php`),统一版本号管理
- ✅ 管理后台「系统信息」页面新增 TBlog 版本显示
### 🔧 改进
- 防御性编程:`fetch_assoc()` 返回 null 时统一改为返回 `[]`,避免上层调用链产生 warning
---
## [v1.2.0] - 2026-05-31
### 定时任务 + 远程备份
@ -34,13 +58,25 @@
---
## 待办
## 升级说明
- [ ] 多 PHP 版本切换
- [ ] Node.js 支持
- [ ] nginx 日志查看器
- [ ] 插件系统
### 从 v1.2.0 升级到 v1.2.1
无破坏性改动,直接覆盖 PHP 文件即可:
```bash
# 备份
cp -r /www/wwwroot/your-blog /path/to/backup/your-blog.v1.2.0
# 上传新文件覆盖(保留 config.php)
unzip -o TBlog_v1.2.1.zip -d /www/wwwroot/your-blog/
# 修复权限
chown -R www:www /www/wwwroot/your-blog
```
无需执行 SQL 迁移。
---
> 关注 GitHub 仓库获取最新更新:https://github.com/tblog-cn/tblog
> 关注 GitHub 仓库获取最新更新:https://github.com/zhang-pu/tblog

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 TBlog
Copyright (c) 2024-2026 Zhang Pu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.

108
README.md
View file

@ -2,11 +2,14 @@
一个简洁、优雅的开源博客系统,基于 PHP + MySQL 开发。
🌐 网址:https://tblog.cn
🌐 官网:https://tblog.cn
💻 源码:https://github.com/zhang-pu/tblog
📦 Releases:https://github.com/zhang-pu/tblog/releases
📝 更新日志:[CHANGELOG.md](./CHANGELOG.md)
---
## 特性
## ✨ 特性
- ✏️ 富文本编辑器,写作体验流畅
- 🎨 两套主题可选(Flow 浅色 / Magine 深色)
@ -18,18 +21,18 @@
---
## 环境要求
## 📋 环境要求
- PHP >= 7.0
- MySQL >= 5.6
- PHP >= 7.0(推荐 7.4 / 8.0+)
- MySQL >= 5.6(推荐 5.7 / 8.0)
- mysqli 扩展
- PDO 扩展(可选)
---
## 安装
## 🚀 快速安装
### 方式一:向导安装
### 方式一:向导安装(推荐)
1. 解压源码,上传至网站目录
2. 访问 `http://你的域名/install.php`
@ -52,7 +55,7 @@ INSERT INTO settings (`key`, value) VALUES ('admin_hash', '$2y$10$YOUR_HASH_HERE
---
## 目录结构
## 📁 目录结构
```
tblog/
@ -66,7 +69,7 @@ tblog/
│ ├── post.php 文章管理
│ └── settings.php 系统设置
├── include/ 核心类库
│ ├── db.php 数据库连接
│ ├── db.php 数据库连接 + 版本常量
│ ├── router.php URL 路由
│ ├── function.common.php
│ ├── function.post.php
@ -80,39 +83,106 @@ tblog/
├── index.php 入口文件
├── config.php.new 配置文件模板
├── install.php 安装向导
└── install.sql 数据库建表脚本
├── install.sql 数据库建表脚本
├── CHANGELOG.md 更新日志
├── README.md 本文件
└── LICENSE MIT 协议
```
---
## 管理后台
## 🔐 管理后台
访问 `http://你的域名/admin/`,使用安装时设置的管理员账号登录。
> 忘记密码?使用 [reset.zip](https://tblog.cn/reset.zip) 工具一键重置。
---
## 主题切换
## 🎨 主题切换
文章可独立选择模板(Flow / Magine),全站默认模板可在后台「设置」中修改。
---
## 开源协议
## 🔧 系统设置
MIT License
登录后台 → 「设置」可配置:
- 站点名称 / 站点描述
- 默认主题(flow / magine)
- 每页文章数
---
## 更新日志
## 🐛 常见问题
详见 [CHANGELOG.md](./CHANGELOG.md)
### 500 Internal Server Error
- 检查 `config.php` 数据库配置
- 确认 `config.php` 可写(安装时)
- 查看 PHP 错误日志:`/var/log/php*-fpm.log`
### 主题不生效
- 硬刷新浏览器:`Ctrl+Shift+R` / `Cmd+Shift+R`
- 清除 CDN/浏览器缓存
### 性能优化
- 启用 PHP OPcache
- 用 CDN 缓存静态资源
- 文章数 > 1000 时考虑分页
详见 [FAQ 文档](https://tblog.cn/docs/faq.html)。
---
## 问题反馈
## 📦 升级
如有 Bug 或建议,欢迎提交 Issue。
```bash
# 1. 备份
cp -r /www/wwwroot/your-blog /path/to/backup/
# 2. 覆盖新文件(保留 config.php 和 uploads/)
rsync -av --exclude='config.php' --exclude='uploads/' \
TBlog_v1.2.1/ /www/wwwroot/your-blog/
# 3. 修复权限
chown -R www:www /www/wwwroot/your-blog
```
完整更新日志:[CHANGELOG.md](./CHANGELOG.md)
---
**TBlog** — 简洁而不简单。
## 🛡 安全建议
- 安装后立即删除 `install.php` 和 `install.sql`
- 修改默认管理员密码为强密码(12 位以上)
- 不要将 `config.php` 设为 777 权限(推荐 644)
- 定期升级到最新版本
- 启用 HTTPS(Let's Encrypt 免费)
---
## 🤝 贡献
欢迎提交 Issue 和 Pull Request!
- Bug 报告:https://github.com/zhang-pu/tblog/issues
- 功能建议:https://github.com/zhang-pu/tblog/issues
- 代码贡献:Fork → 修改 → Pull Request
---
## 📄 开源协议
MIT License - 详见 [LICENSE](./LICENSE)
---
## 👨‍💻 作者
**Zhang Pu** - [https://zhangpu.dev](https://zhangpu.dev)
---
**TBlog** — 简洁而不简单。

View file

@ -36,7 +36,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Load category for editing
if (!empty($_GET['edit'])) {
$edit_category = get_category_by_id(intval($_GET['edit']));
$edit_category = get_category_by_id(intval($_GET['edit'])) ?? [];
}
// Handle delete

View file

@ -39,14 +39,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$message = '<div class="error">标题和内容不能为空</div>';
} else {
// Check slug uniqueness (only if slug changed or new post)
$existing = null;
$existing = [];
if (!empty($_POST['id'])) {
$existing = get_post_by_id(intval($_POST['id']));
$existing = get_post_by_id(intval($_POST['id'])) ?? [];
}
$slug_check = $data['slug'];
$db = get_db();
$exclude_id = $existing['id'] ?? 0;
$stmt = $db->prepare("SELECT id FROM posts WHERE slug = ? AND deleted_at IS NULL AND id != ?");
$stmt->bind_param('si', $slug_check, $existing['id'] ?? 0);
$stmt->bind_param('si', $slug_check, $exclude_id);
$stmt->execute();
$res = $stmt->get_result();
if ($res->num_rows > 0) {
@ -64,7 +65,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
}
if (!empty($_GET['edit'])) {
$edit_post = get_post_by_id(intval($_GET['edit']));
$edit_post = get_post_by_id(intval($_GET['edit'])) ?? [];
}
if (!empty($_GET['delete'])) {

View file

@ -130,6 +130,10 @@ $admin_user = get_admin_user();
<h2 style="margin-top: 40px;">系统信息</h2>
<table class="table">
<tr>
<td>TBlog 版本</td>
<td><?php echo TBLOG_VERSION; ?></td>
</tr>
<tr>
<td>PHP 版本</td>
<td><?php echo PHP_VERSION; ?></td>

22
config.php Normal file
View file

@ -0,0 +1,22 @@
<?php
/**
* ZhangPu Blog - Configuration
*/
define('DB_HOST', 'localhost');
define('DB_PORT', 3306);
define('DB_USER', 'zhangpu_blog');
define('DB_PASS', 'rHzj9EWStT6xCcMD');
define('DB_NAME', 'zhangpu_blog');
define('DB_PREFIX', '');
// Site settings
define('SITE_NAME', 'ZhangPu Blog');
// Path constants
define('ROOT_PATH', __DIR__ . '/');
define('INCLUDE_PATH', ROOT_PATH . 'include/');
define('TEMPLATE_PATH', ROOT_PATH . 'templates/');
// Admin credentials stored hashed in DB; fall back to env/local config if needed
// To set initial password: go to /admin/settings and change it there
session_start();

View file

@ -1,18 +0,0 @@
<?php
/**
* TBlog - Configuration Template
* 复制此文件为 config.php 并填写数据库信息
*/
define('DB_HOST', 'localhost');
define('DB_PORT', 3306);
define('DB_USER', 'your_db_user');
define('DB_PASS', 'your_db_password');
define('DB_NAME', 'tblog');
define('DB_PREFIX', '');
// Path constants
define('ROOT_PATH', __DIR__ . '/');
define('INCLUDE_PATH', ROOT_PATH . 'include/');
define('TEMPLATE_PATH', ROOT_PATH . 'templates/');
session_start();

View file

@ -3,6 +3,9 @@
* Database Connection
*/
// TBlog 版本常量
define('TBLOG_VERSION', '1.2.1');
function get_db() {
static $db = null;
if ($db === null) {

View file

@ -22,7 +22,8 @@ function get_category_by_id($id) {
$stmt = $db->prepare("SELECT * FROM categories WHERE id = ?");
$stmt->bind_param('i', $id);
$stmt->execute();
return $stmt->get_result()->fetch_assoc();
$row = $stmt->get_result()->fetch_assoc();
return $row ?? [];
}
function create_category($data) {

View file

@ -81,7 +81,8 @@ function get_post_by_id($id) {
$stmt = $db->prepare("SELECT * FROM posts WHERE id = ?");
$stmt->bind_param('i', $id);
$stmt->execute();
return $stmt->get_result()->fetch_assoc();
$row = $stmt->get_result()->fetch_assoc();
return $row ?? [];
}
function create_post($data) {

View file

@ -1,6 +1,6 @@
<?php
/**
* TBlog - Installation Wizard
* ZhangPu Blog - Installation Wizard
*/
session_start();
@ -54,7 +54,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && $step === 2) {
if ($step === 3) {
$config_content = "<?php
/**
* TBlog - Configuration
* ZhangPu Blog - Configuration
*/
define('DB_HOST', '{$_SESSION['db_host']}');
define('DB_PORT', {$_SESSION['db_port']});
@ -100,7 +100,7 @@ if ($step === 5) {
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>安装向导 - TBlog</title>
<title>安装向导 - ZhangPu Blog</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@ -293,7 +293,7 @@ if ($step === 5) {
<body>
<div class="installer">
<div class="installer-header">
<h1>🌿 TBlog 安装向导</h1>
<h1>🌿 ZhangPu Blog 安装向导</h1>
<p>一个简洁优雅的博客系统</p>
<div class="progress-bar">
<div class="progress-step <?php echo $step >= 1 ? 'completed' : ''; ?>" data-step="1"></div>
@ -370,7 +370,7 @@ if ($step === 5) {
<div class="form-group">
<label for="db_name">数据库名称</label>
<input type="text" name="db_name" id="db_name" value="<?php echo e($_SESSION['db_name'] ?? 'tblog'); ?>" required>
<input type="text" name="db_name" id="db_name" value="<?php echo e($_SESSION['db_name'] ?? 'zhangpu_blog'); ?>" required>
</div>
<div class="buttons">
@ -396,7 +396,7 @@ if ($step === 5) {
<?php elseif ($step === 4): ?>
<h2>第四步:安装完成</h2>
<div class="success">🎉 恭喜!TBlog 已安装成功!</div>
<div class="success">🎉 恭喜!ZhangPu Blog 已安装成功!</div>
<div class="features">
<strong>默认管理员信息:</strong>
@ -418,7 +418,7 @@ if ($step === 5) {
<?php elseif ($step === 5): ?>
<div class="text-center">
<h2>🎉 安装完成!</h2>
<p class="mt-4">感谢使用 TBlog</p>
<p class="mt-4">感谢使用 ZhangPu Blog</p>
</div>
<div class="buttons" style="justify-content: center; margin-top: 30px;">

View file

@ -2,27 +2,14 @@
/**
* Flow Template - Footer
*/
$site_name = get_setting('site_name', 'TBlog');
$github_url = 'https://github.com/tblog-cn/tblog';
$site_name = get_setting('site_name', '张璞博客');
?>
</div>
</div>
</main>
<footer class="site-footer">
<div class="container">
<div class="footer-links">
<a href="https://tblog.cn" target="_blank">TBlog</a>
<span class="sep">·</span>
<a href="<?php echo $github_url; ?>" target="_blank" title="GitHub">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" style="vertical-align:middle">
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/>
</svg>
开源
</a>
<span class="sep">·</span>
<a href="https://github.com/tblog-cn/tblog/releases" target="_blank">更新日志</a>
</div>
<p>© <?php echo date('Y'); ?> <?php echo e($site_name); ?> · MIT License</p>
<p>© <?php echo date('Y'); ?> <?php echo e($site_name); ?> · Apache 2.0</p>
</div>
</footer>
<script>
@ -32,4 +19,4 @@ $github_url = 'https://github.com/tblog-cn/tblog';
}
</script>
</body>
</html>
</html>

View file

@ -7,8 +7,8 @@ require_once __DIR__ . '/../../config.php';
require_once INCLUDE_PATH . 'function.common.php';
require_once INCLUDE_PATH . 'function.category.php';
$site_name = get_setting('site_name', 'TBlog');
$site_description = get_setting('site_description', '一个简洁优雅的开源博客系统');
$site_name = get_setting('site_name', '张璞博客');
$site_description = get_setting('site_description', '一个简洁优雅的博客');
$categories = get_categories();
?>
<!DOCTYPE html>
@ -39,4 +39,4 @@ $categories = get_categories();
</header>
<main class="main-content">
<div class="container">
<div class="content-wrapper">
<div class="content-wrapper">

View file

@ -2,27 +2,14 @@
/**
* Magine Template - Footer (Dark Theme)
*/
$site_name = get_setting('site_name', 'TBlog');
$github_url = 'https://github.com/tblog-cn/tblog';
$site_name = get_setting('site_name', '张璞博客');
?>
</div>
</div>
</main>
<footer class="site-footer">
<div class="container">
<div class="footer-links">
<a href="https://tblog.cn" target="_blank">TBlog</a>
<span class="sep">·</span>
<a href="<?php echo $github_url; ?>" target="_blank" title="GitHub">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" style="vertical-align:middle">
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/>
</svg>
开源
</a>
<span class="sep">·</span>
<a href="https://github.com/tblog-cn/tblog/releases" target="_blank">更新日志</a>
</div>
<p>© <?php echo date('Y'); ?> <?php echo e($site_name); ?> · MIT License</p>
<p>© <?php echo date('Y'); ?> <?php echo e($site_name); ?> · Apache 2.0</p>
</div>
</footer>
<script>
@ -32,4 +19,4 @@ $github_url = 'https://github.com/tblog-cn/tblog';
}
</script>
</body>
</html>
</html>

View file

@ -6,8 +6,8 @@ require_once __DIR__ . '/../../config.php';
require_once INCLUDE_PATH . 'function.common.php';
require_once INCLUDE_PATH . 'function.category.php';
$site_name = get_setting('site_name', 'TBlog');
$site_description = get_setting('site_description', '一个简洁优雅的开源博客系统');
$site_name = get_setting('site_name', '张璞博客');
$site_description = get_setting('site_description', '一个简洁优雅的博客');
$categories = get_categories();
?>
<!DOCTYPE html>
@ -37,4 +37,4 @@ $categories = get_categories();
</header>
<main class="main-content">
<div class="container">
<div class="content-wrapper">
<div class="content-wrapper">