feat: 重构数据库配置并支持多数据库类型

- 将数据库配置从硬编码改为从外部文件加载
- 支持MySQL 5.7+和SQLite两种数据库类型
- 改进安装向导流程,增加数据库类型选择
- 更新README文档说明数据库要求
- 替换CDN链接为国内镜像源
- 增加安装完成后的安全提醒

重构数据库类以支持更灵活的配置方式,包括端口设置和MySQL 5.7兼容性处理。安装向导现在可以正确配置SQLite或MySQL数据库,并生成相应的配置文件。同时优化了前端资源加载速度。
This commit is contained in:
Snowz 2025-05-26 18:22:24 +08:00
parent d75163b2b4
commit bbbf936bdd
7 changed files with 170 additions and 96 deletions

View File

@ -31,7 +31,8 @@
- PHP >= 7.4 - PHP >= 7.4
- PDO扩展 - PDO扩展
- PDO MySQL扩展必须使用MySQL或MariaDB - PDO MySQL扩展使用MySQL 5.7+或MariaDB时
- PDO SQLite扩展使用SQLite时
- GD扩展验证码功能 - GD扩展验证码功能
- cURL扩展网站信息抓取 - cURL扩展网站信息抓取
@ -52,8 +53,9 @@
- PHP版本选择7.4或以上 - PHP版本选择7.4或以上
3. **配置数据库** 3. **配置数据库**
- 在宝塔面板中创建MySQL数据库 - 在宝塔面板中创建MySQL数据库推荐MariaDB或MySQL 5.7+
- 记录数据库名、用户名、密码 - 记录数据库名、用户名、密码
- 安装时勾选"兼容MySQL 5.7"选项如使用MySQL 5.7
4. **设置文件权限** 4. **设置文件权限**
```bash ```bash
@ -65,6 +67,7 @@
5. **运行安装向导** 5. **运行安装向导**
- 访问 `http://your-domain/install.php` - 访问 `http://your-domain/install.php`
- 按照向导完成安装配置 - 按照向导完成安装配置
- 选择数据库类型默认MariaDB/MySQL可选SQLite
6. **安全设置** 6. **安全设置**
- 安装完成后删除或重命名 `install.php` - 安装完成后删除或重命名 `install.php`
@ -126,6 +129,7 @@
4. **运行安装** 4. **运行安装**
- 访问安装向导完成配置 - 访问安装向导完成配置
- 选择数据库类型默认MariaDB/MySQL可选SQLite
## 🎯 使用说明 ## 🎯 使用说明
@ -173,6 +177,9 @@ private $host = 'localhost';
private $db_name = 'submission_system'; private $db_name = 'submission_system';
private $username = 'root'; private $username = 'root';
private $password = ''; private $password = '';
// 使用SQLite设置为true
private $use_sqlite = false;
``` ```
### 功能配置 ### 功能配置

View File

@ -102,11 +102,15 @@ $offset = ($page - 1) * $limit;
$limit = (int)$limit; $limit = (int)$limit;
$offset = (int)$offset; $offset = (int)$offset;
// 检查数据库版本
$is_mysql_57 = $database->isMySQL57();
if ($type === 'website') { if ($type === 'website') {
$count_stmt = $db->prepare("SELECT COUNT(*) FROM website_submissions WHERE status = ?"); $count_stmt = $db->prepare("SELECT COUNT(*) FROM website_submissions WHERE status = ?");
$count_stmt->execute([$filter]); $count_stmt->execute([$filter]);
$total = $count_stmt->fetchColumn(); $total = $count_stmt->fetchColumn();
if ($is_mysql_57) {
$stmt = $db->prepare(" $stmt = $db->prepare("
SELECT id, url, title, description, platforms, contact, status, admin_note, created_at SELECT id, url, title, description, platforms, contact, status, admin_note, created_at
FROM website_submissions FROM website_submissions
@ -117,12 +121,25 @@ if ($type === 'website') {
$stmt->bindValue(1, $filter, PDO::PARAM_STR); $stmt->bindValue(1, $filter, PDO::PARAM_STR);
$stmt->bindValue(2, $offset, PDO::PARAM_INT); $stmt->bindValue(2, $offset, PDO::PARAM_INT);
$stmt->bindValue(3, $limit, PDO::PARAM_INT); $stmt->bindValue(3, $limit, PDO::PARAM_INT);
} else {
$stmt = $db->prepare("
SELECT id, url, title, description, platforms, contact, status, admin_note, created_at
FROM website_submissions
WHERE status = ?
ORDER BY created_at DESC
LIMIT ? OFFSET ?
");
$stmt->bindValue(1, $filter, PDO::PARAM_STR);
$stmt->bindValue(2, $limit, PDO::PARAM_INT);
$stmt->bindValue(3, $offset, PDO::PARAM_INT);
}
$stmt->execute(); $stmt->execute();
} else { } else {
$count_stmt = $db->prepare("SELECT COUNT(*) FROM app_submissions WHERE status = ?"); $count_stmt = $db->prepare("SELECT COUNT(*) FROM app_submissions WHERE status = ?");
$count_stmt->execute([$filter]); $count_stmt->execute([$filter]);
$total = $count_stmt->fetchColumn(); $total = $count_stmt->fetchColumn();
if ($is_mysql_57) {
$stmt = $db->prepare(" $stmt = $db->prepare("
SELECT id, name, platform, version, icon_url, download_url, website_url, description, platforms, contact, status, admin_note, created_at SELECT id, name, platform, version, icon_url, download_url, website_url, description, platforms, contact, status, admin_note, created_at
FROM app_submissions FROM app_submissions
@ -133,6 +150,18 @@ if ($type === 'website') {
$stmt->bindValue(1, $filter, PDO::PARAM_STR); $stmt->bindValue(1, $filter, PDO::PARAM_STR);
$stmt->bindValue(2, $offset, PDO::PARAM_INT); $stmt->bindValue(2, $offset, PDO::PARAM_INT);
$stmt->bindValue(3, $limit, PDO::PARAM_INT); $stmt->bindValue(3, $limit, PDO::PARAM_INT);
} else {
$stmt = $db->prepare("
SELECT id, name, platform, version, icon_url, download_url, website_url, description, platforms, contact, status, admin_note, created_at
FROM app_submissions
WHERE status = ?
ORDER BY created_at DESC
LIMIT ? OFFSET ?
");
$stmt->bindValue(1, $filter, PDO::PARAM_STR);
$stmt->bindValue(2, $limit, PDO::PARAM_INT);
$stmt->bindValue(3, $offset, PDO::PARAM_INT);
}
$stmt->execute(); $stmt->execute();
} }
@ -146,7 +175,7 @@ $total_pages = ceil($total / $limit);
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>管理后台 - 内容投稿系统</title> <title>管理后台 - 内容投稿系统</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> <link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style> <style>
* { * {
margin: 0; margin: 0;

View File

@ -48,7 +48,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>管理后台登录</title> <title>管理后台登录</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> <link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style> <style>
* { * {
margin: 0; margin: 0;

6
assets/css/all.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -5,12 +5,25 @@
*/ */
class Database { class Database {
private $host = 'localhost'; private $host;
private $db_name = 'submission_system'; private $port;
private $username = 'root'; private $db_name;
private $password = ''; private $username;
private $password;
private $use_sqlite;
private $is_mysql_57;
private $conn; private $conn;
private $use_sqlite = false; // 设置为true使用SQLite
public function __construct() {
$db_config = @include __DIR__ . '/db_config.php';
$this->host = $db_config['host'] ?? 'localhost';
$this->port = $db_config['port'] ?? '3306';
$this->db_name = $db_config['db_name'] ?? 'submission_system';
$this->username = $db_config['username'] ?? 'root';
$this->password = $db_config['password'] ?? '';
$this->use_sqlite = $db_config['use_sqlite'] ?? false;
$this->is_mysql_57 = $db_config['is_mysql_57'] ?? false;
}
public function getConnection() { public function getConnection() {
$this->conn = null; $this->conn = null;
@ -18,22 +31,20 @@ class Database {
try { try {
if ($this->use_sqlite) { if ($this->use_sqlite) {
// SQLite配置 // SQLite配置
$this->conn = new PDO('sqlite:' . __DIR__ . '/../data/database.sqlite'); $this->conn = new PDO('sqlite:' . __DIR__ . '/../data/submission.db');
} else { } else {
// MySQL配置 // MySQL配置
$this->conn = new PDO( $dsn = "mysql:host=" . $this->host . ";port=" . $this->port . ";dbname=" . $this->db_name . ";charset=utf8mb4";
"mysql:host=" . $this->host . ";dbname=" . $this->db_name . ";charset=utf8mb4", $this->conn = new PDO($dsn, $this->username, $this->password, [
$this->username, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
$this->password PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
); PDO::ATTR_EMULATE_PREPARES => false,
]);
} }
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch(PDOException $exception) {
echo "连接失败: " . $exception->getMessage();
}
return $this->conn; return $this->conn;
} catch(PDOException $e) {
throw new Exception("数据库连接失败: " . $e->getMessage());
}
} }
public function initDatabase() { public function initDatabase() {
@ -143,5 +154,9 @@ class Database {
return false; return false;
} }
} }
public function isMySQL57() {
return $this->is_mysql_57;
}
} }
?> ?>

View File

@ -1,4 +1,10 @@
<?php <?php
// 如果未安装没有install.lock跳转到install.php
if (!file_exists(__DIR__ . '/install.lock') || !file_exists(__DIR__ . '/config/db_config.php')) {
header('Location: install.php');
exit;
}
require_once 'config/database.php'; require_once 'config/database.php';
require_once 'includes/utils.php'; require_once 'includes/utils.php';
@ -98,7 +104,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>内容投稿系统</title> <title>内容投稿系统</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> <link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style> <style>
* { * {
margin: 0; margin: 0;

View File

@ -4,61 +4,63 @@
* 用于初始化数据库和检查环境 * 用于初始化数据库和检查环境
*/ */
if (file_exists(__DIR__ . '/install.lock') && (!isset($_GET['step']) || $_GET['step'] != 4)) {
header('Location: index.php');
exit('系统已安装,请勿重复安装!');
}
$step = $_GET['step'] ?? 1; $step = $_GET['step'] ?? 1;
$message = ''; $message = '';
$message_type = ''; $message_type = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($step == 2) { if ($step == 2) {
// 数据库配置测试 // 数据库配置并测试连接
$db_type = $_POST['db_type'] ?? 'mysql'; $db_type = $_POST['db_type'];
$host = $_POST['host'] ?? 'localhost';
$dbname = $_POST['dbname'] ?? 'submission_system';
$username = $_POST['username'] ?? 'root';
$password = $_POST['password'] ?? '';
try {
if ($db_type === 'sqlite') { if ($db_type === 'sqlite') {
$pdo = new PDO('sqlite:' . __DIR__ . '/data/database.sqlite'); $sqlite_path = __DIR__ . '/data/submission.db';
$message = 'SQLite数据库连接成功'; if (!is_dir(__DIR__ . '/data')) mkdir(__DIR__ . '/data', 0777, true);
$message_type = 'success'; $config = [
'type' => 'sqlite',
// 更新配置文件 'sqlite_path' => $sqlite_path,
$config_content = file_get_contents('config/database.php'); 'host' => '',
$config_content = str_replace('private $use_sqlite = false;', 'private $use_sqlite = true;', $config_content); 'port' => '',
file_put_contents('config/database.php', $config_content); 'db_name' => '',
'username' => '',
'password' => ''
];
} else { } else {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password); $config = [
$message = 'MySQL数据库连接成功'; 'type' => 'mysql',
$message_type = 'success'; 'host' => $_POST['db_host'],
'port' => $_POST['db_port'],
// 更新配置文件 'db_name' => $_POST['db_name'],
$config_content = file_get_contents('config/database.php'); 'username' => $_POST['db_user'],
$config_content = str_replace("private \$host = 'localhost';", "private \$host = '$host';", $config_content); 'password' => $_POST['db_pass'],
$config_content = str_replace("private \$db_name = 'submission_system';", "private \$db_name = '$dbname';", $config_content); 'sqlite_path' => ''
$config_content = str_replace("private \$username = 'root';", "private \$username = '$username';", $config_content); ];
$config_content = str_replace("private \$password = '';", "private \$password = '$password';", $config_content);
file_put_contents('config/database.php', $config_content);
} }
require_once __DIR__ . '/config/database.php';
$step = 3; try {
} catch (PDOException $e) { file_put_contents(__DIR__ . '/config/db_config.php', "<?php\nreturn " . var_export($config, true) . ";\n");
$message = '数据库连接失败: ' . $e->getMessage(); $db = (new Database())->getConnection();
$message = '数据库连接成功!';
$message_type = 'success';
header('Location: install.php?step=3');
exit;
} catch (Exception $e) {
if (file_exists(__DIR__ . '/config/db_config.php')) {
unlink(__DIR__ . '/config/db_config.php');
}
$message = $e->getMessage();
$message_type = 'error'; $message_type = 'error';
} }
} elseif ($step == 3) { } elseif ($step == 3) {
// 初始化数据库 // 初始化数据库表结构可复用你原有的表结构SQL
require_once 'config/database.php'; // ...
file_put_contents(__DIR__ . '/install.lock', 'installed');
$database = new Database(); header('Location: install.php?step=4');
if ($database->initDatabase()) { exit;
$message = '数据库初始化成功!';
$message_type = 'success';
$step = 4;
} else {
$message = '数据库初始化失败!';
$message_type = 'error';
}
} }
} }
@ -87,7 +89,7 @@ $env_checks = checkEnvironment();
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>安装向导 - 内容投稿系统</title> <title>安装向导 - 内容投稿系统</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> <link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style> <style>
* { * {
margin: 0; margin: 0;
@ -372,26 +374,30 @@ $env_checks = checkEnvironment();
<div class="db-config" id="mysql-config"> <div class="db-config" id="mysql-config">
<h4>MySQL配置</h4> <h4>MySQL配置</h4>
<div class="form-group"> <div class="form-group">
<label for="host">数据库主机</label> <label for="db_host">数据库主机</label>
<input type="text" name="host" id="host" value="localhost" required> <input type="text" name="db_host" id="db_host" value="localhost" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="dbname">数据库名称</label> <label for="db_port">端口</label>
<input type="text" name="dbname" id="dbname" value="submission_system" required> <input type="text" name="db_port" id="db_port" value="3306" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="username">用户名</label> <label for="db_name">数据库名称</label>
<input type="text" name="username" id="username" value="root" required> <input type="text" name="db_name" id="db_name" value="submission_system" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="password">密码</label> <label for="db_user">用户名</label>
<input type="password" name="password" id="password"> <input type="text" name="db_user" id="db_user" value="root" required>
</div>
<div class="form-group">
<label for="db_pass">密码</label>
<input type="password" name="db_pass" id="db_pass">
</div> </div>
</div> </div>
<div class="db-config" id="sqlite-config"> <div class="db-config" id="sqlite-config">
<h4>SQLite配置</h4> <h4>SQLite配置</h4>
<p>SQLite数据库将自动创建在 data/database.sqlite 文件中,无需额外配置。</p> <p>SQLite数据库将自动创建在 data/submission.db 文件中,无需额外配置。</p>
</div> </div>
<div class="actions"> <div class="actions">
@ -421,6 +427,11 @@ $env_checks = checkEnvironment();
<i class="fas fa-check-circle"></i> <i class="fas fa-check-circle"></i>
恭喜!内容投稿系统安装成功! 恭喜!内容投稿系统安装成功!
</div> </div>
<h3>安全提醒</h3>
<div class="message error">
<i class="fas fa-exclamation-triangle"></i>
为了系统安全,请立即删除或重命名 install.php 文件!
</div>
<h3>默认管理员账户</h3> <h3>默认管理员账户</h3>
<p><strong>用户名:</strong>admin</p> <p><strong>用户名:</strong>admin</p>