Compare commits

..

1 commit
v1.2.1 ... main

Author SHA1 Message Date
zhang-pu
a82fe4ac21 TBlog v1.2.1 — Bug 修复版 2026-06-03 11:18:12 +08:00
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

106
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,38 +83,105 @@ 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)
---
## 🛡 安全建议
- 安装后立即删除 `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)
---

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>

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>

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>

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>