Skip to content

Commit ee13b4a

Browse files
author
雾都
committed
a
1 parent 1c04575 commit ee13b4a

File tree

2 files changed

+421
-191
lines changed

2 files changed

+421
-191
lines changed

install.php

Lines changed: 153 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<?php
2+
//define('ABSPATH', dirname(__DIR__));
3+
// install.php
24
require 'vendor/autoload.php';
35

46
use BaconQrCode\Renderer\GDLibRenderer;
@@ -7,16 +9,17 @@
79

810
if (file_exists('install.lock')) {
911
echo "install.lock 系统已安装,请勿重复安装。如发生错误/需要重新安装,请删除 install.lock \n";
10-
exit;
12+
exit; // 退出脚本
1113
}
1214
if (file_exists('redis.lock')) {
1315
unlink('redis.lock');
1416
}
1517
if (file_exists('qrcode.png')) {
1618
unlink('qrcode.png');
1719
}
18-
20+
// 检查是否已经提交了表单
1921
if ($_SERVER["REQUEST_METHOD"] == "POST") {
22+
// 获取用户输入的数据库连接信息
2023
$dbHost = trim(filter_var($_POST['dbHost'] ?? '127.0.0.1', FILTER_VALIDATE_IP) ?: '127.0.0.1');
2124
$dbName = trim(htmlspecialchars($_POST['dbName']));
2225
$dbUser = trim(htmlspecialchars($_POST['dbUser']));
@@ -25,9 +28,9 @@
2528
$password = trim(htmlspecialchars($_POST['password']));
2629
$adminEmail = trim(filter_var($_POST['admin_email'], FILTER_VALIDATE_EMAIL) ?: '[email protected]');
2730
$inputPassword = trim(htmlspecialchars($_POST['customPassword']));
28-
$productId = '1';
31+
$productId = '1'; // 默认产品ID为1,不显示在表单中
2932
$authMethod = $_POST['authMethod'];
30-
33+
// 处理不同认证方法
3134
switch ($authMethod) {
3235
case 'password':
3336
if (empty($inputPassword)) {
@@ -61,120 +64,191 @@
6164
echo "redis.lock 文件已创建。\n";
6265
}
6366

67+
// 尝试连接到数据库
6468
$mysqli = new mysqli($dbHost, $dbUser, $dbPass, $dbName);
69+
70+
// 检查连接是否成功
6571
if ($mysqli->connect_error) {
6672
die('数据库连接失败: ' . $mysqli->connect_error);
6773
}
6874

75+
// 读取 SQL 文件内容
6976
$sqlContent = file_get_contents('install.sql');
77+
78+
// 执行 SQL 语句
7079
if ($mysqli->multi_query($sqlContent)) {
71-
do {} while ($mysqli->next_result());
72-
73-
$configFile = "<?php\nreturn [\n 'db' => [\n 'host' => '{$dbHost}',\n 'dbname' => '{$dbName}',\n 'user' => '{$dbUser}',\n 'pass' => '{$dbPass}'\n ],\n 'auth' => [\n 'account' => '{$account}',\n 'password' => '{$password}',\n 'product_id' => '{$productId}'\n ],\n 'mail' => [\n 'host' => '',\n 'port' => 465,\n 'username' => '',\n 'password' => '',\n 'from' => '{$adminEmail}',\n 'encryption' => 'ssl'\n ]\n];";
80+
// 等待所有查询执行完成
81+
do {
82+
// 无需进一步处理结果
83+
} while ($mysqli->next_result());
84+
echo "创建config.php文件...\n";
85+
// 创建 config.php 文件
86+
$configFile = "<?php\n// config.php\nreturn [\n 'db' => [\n 'host' => '{$dbHost}',\n 'dbname' => '{$dbName}',\n 'user' => '{$dbUser}',\n 'pass' => '{$dbPass}'\n ],\n 'auth' => [\n 'account' => '{$account}',\n 'password' => '{$password}',\n 'product_id' => '{$productId}'\n ]\n];";
7487
file_put_contents('config.php', $configFile);
75-
88+
echo "config.php 文件已创建。\n";
7689
$config = require 'config.php';
7790
if (file_exists('qrcode.png')) {
7891
unlink('qrcode.png');
7992
}
93+
// Database connection
94+
$host = $config['db']['host'];
95+
$dbname = $config['db']['dbname'];
96+
$user = $config['db']['user'];
97+
$pass = $config['db']['pass'];
8098

8199
try {
82-
$pdo = new PDO("mysql:host={$config['db']['host']};dbname={$config['db']['dbname']};charset=utf8",
83-
$config['db']['user'], $config['db']['pass']);
100+
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass);
84101
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
85102
} catch (PDOException $e) {
86-
die("数据库连接失败: " . $e->getMessage());
103+
die("Could not connect to the database: " . $e->getMessage());
87104
}
88105

89-
if ($useTotp) {
106+
if ($useTotp && !$usePassword) { // 生成一个新的TOTP密钥
90107
$totp = TOTP::create();
91108
$totp->setLabel($adminEmail);
92-
$totp->setIssuer('TuanICP');
109+
$totp->setIssuer('TuanICP');// 获取密钥和二维码URL
93110
$secret = $totp->getSecret();
94-
$qrCodeUrl = $totp->getProvisioningUri();
95-
96-
$renderer = new GDLibRenderer(400);
97-
$writer = new Writer($renderer);
98-
file_put_contents('qrcode.png', $writer->writeString($qrCodeUrl));
111+
$qrCodeUrl = $totp->getProvisioningUri();// 将TOTP密钥和用户信息存储到数据库
112+
$query = "INSERT INTO admin (email, totp_secret ,totp_enabled) VALUES (?, ?, ?)";
113+
$stmt = $pdo->prepare($query);
114+
$stmt->execute([$adminEmail, $secret, '1']);// 创建 GDLibRenderer 实例,设置二维码大小
115+
$renderer = new GDLibRenderer(400);// 创建 Writer 实例
116+
$writer = new Writer($renderer);// 生成并保存二维码图片
117+
$qrcode_image = $writer->writeString($qrCodeUrl);// 将 QRCode URL 转换为图像
118+
file_put_contents('qrcode.png', $qrcode_image);// 保存为 qrcode.png 文件
99119
}
100-
101120
if ($usePassword && !$useTotp) {
102-
$stmt = $pdo->prepare("INSERT INTO admin (email, password, password_enabled) VALUES (?, ?, ?)");
121+
$query = "INSERT INTO admin (email, password, password_enabled) VALUES (?, ?, ?)";
122+
$stmt = $pdo->prepare($query);
103123
$stmt->execute([$adminEmail, $customPassword, '1']);
104-
} elseif ($useTotp && !$usePassword) {
105-
$stmt = $pdo->prepare("INSERT INTO admin (email, totp_secret, totp_enabled) VALUES (?, ?, ?)");
106-
$stmt->execute([$adminEmail, $secret, '1']);
107-
} elseif ($usePassword && $useTotp) {
108-
$stmt = $pdo->prepare("INSERT INTO admin (email, password, totp_secret, totp_enabled, password_enabled) VALUES (?, ?, ?, ?, ?)");
124+
}
125+
if ($usePassword && $useTotp) {
126+
$totp = TOTP::create();
127+
$totp->setLabel($adminEmail);
128+
$totp->setIssuer('TuanICP');// 获取密钥和二维码URL
129+
$secret = $totp->getSecret();
130+
$qrCodeUrl = $totp->getProvisioningUri();// 将TOTP密钥和用户信息存储到数据库
131+
$query = "INSERT INTO admin (email, password, totp_secret, totp_enabled, password_enabled) VALUES (?, ?, ?, ?, ?)";
132+
$stmt = $pdo->prepare($query);
109133
$stmt->execute([$adminEmail, $customPassword, $secret, '1', '1']);
134+
$renderer = new GDLibRenderer(400);// 创建 Writer 实例
135+
$writer = new Writer($renderer);// 生成并保存二维码图片
136+
$qrcode_image = $writer->writeString($qrCodeUrl);// 将 QRCode URL 转换为图像
137+
file_put_contents('qrcode.png', $qrcode_image);// 保存为 qrcode.png 文件
110138
}
111139

112-
file_put_contents('install.lock', 'installed');
113-
echo "安装成功!请删除安装文件!\n";
140+
echo "安装成功,请删除安装文件!请前往phpMyAdmin进入数据库或网站后台修改网站配置信息!\n";
141+
if ($useTotp === true) {
142+
// 设置HTTP缓存控制头,确保在发送任何输出之前设置
143+
header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1.
144+
header("Pragma: no-cache"); // HTTP 1.0.
145+
header("Expires: 0"); // Proxies.
114146

115-
if ($useTotp && file_exists('qrcode.png')) {
116-
echo '<div><img src="qrcode.png"></div>';
117-
echo "<h2>请使用TOTP应用扫描二维码</h2>";
147+
if (file_exists('qrcode.png')) {
148+
echo '<div><img src="qrcode.png"></div>';
149+
echo "<h2>二维码已生成,请使用TOTP应用扫描二维码绑定。如果没有TOTP应用,请自行寻找并下载安装“Free OTP”。</h2><br>
150+
<h3>此应用是免费且开源的,并且Android(安卓)和IOS(苹果)平台都支持。</h3>\n";
151+
} else {
152+
if (isset($qrCodeUrl) && isset($secret)) {
153+
echo "<h2>二维码生成失败,请手动将TOTP的URL生成为二维码导入到设备,或使用TOTP密钥手动输入:</h2><br>";
154+
echo "<h3>TOTP的URL为:<a href='$qrCodeUrl'>$qrCodeUrl</a></h3><br>";
155+
echo "<h3>TOTP密钥为:</h3><br>";
156+
echo "<textarea>$secret</textarea>";
157+
} else {
158+
echo "TOTP密钥为空。环境可能未被正确设置,请检查!";
159+
phpinfo();
160+
exit;
161+
}
162+
}
118163
}
164+
165+
// 逻辑代码执行完毕后,创建 install.lock 文件
166+
file_put_contents('install.lock', 'installed');
167+
echo "install.lock 文件已创建。\n";
119168
exit;
120169
} else {
121-
die("数据库安装失败: " . $mysqli->error);
170+
// 输出错误信息
171+
$errorInfo = $mysqli->error;
172+
173+
// 检查错误信息中是否包含“Access denied”来确定是否是用户名或密码错误
174+
if (strpos($errorInfo, "Access denied") !== false) {
175+
echo "数据库安装失败。错误信息:用户名或密码错误。";
176+
} else {
177+
// 如果不是用户名或密码错误,显示其他错误信息
178+
echo "数据库安装失败。错误信息:" . $errorInfo;
179+
}
180+
122181
}
182+
183+
// 关闭数据库连接
184+
$mysqli->close();
123185
}
124186
?>
125187

126188
<!DOCTYPE html>
127-
<html lang="zh-CN">
189+
<html lang="en">
128190
<head>
129191
<meta charset="UTF-8">
130-
<title>系统安装向导</title>
131-
<style>
132-
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
133-
label { display: inline-block; width: 150px; margin-bottom: 10px; }
134-
input, select { padding: 8px; width: 300px; }
135-
#passwordDiv { margin-top: 15px; }
136-
</style>
192+
<title>数据库安装</title>
193+
<link rel="stylesheet" href="css/install.css">
137194
</head>
138195
<body>
139-
<h1>系统安装向导</h1>
140-
<form method="post">
141-
<label for="dbHost">数据库地址:</label>
142-
<input type="text" id="dbHost" name="dbHost" value="127.0.0.1" required><br>
143-
144-
<label for="dbName">数据库名:</label>
145-
<input type="text" id="dbName" name="dbName" required><br>
146-
147-
<label for="dbUser">数据库用户名:</label>
148-
<input type="text" id="dbUser" name="dbUser" required><br>
149-
150-
<label for="dbPass">数据库密码:</label>
151-
<input type="password" id="dbPass" name="dbPass" required><br>
152-
153-
<label for="admin_email">管理员邮箱:</label>
154-
<input type="email" id="admin_email" name="admin_email" value="[email protected]" required><br>
155-
156-
<label for="authMethod">认证方式:</label>
157-
<select id="authMethod" name="authMethod" required>
158-
<option value="password">密码认证</option>
159-
<option value="totp">TOTP认证</option>
160-
<option value="both">双重认证</option>
161-
</select><br>
162-
163-
<div id="passwordDiv">
164-
<label for="customPassword">设置密码:</label>
165-
<input type="password" id="customPassword" name="customPassword">
166-
</div>
167-
168-
<label><input type="checkbox" name="redis" value="1"> 启用Redis</label><br><br>
169-
170-
<input type="submit" value="开始安装" style="padding: 10px 20px;">
171-
</form>
172-
173-
<script>
174-
document.getElementById('authMethod').addEventListener('change', function() {
175-
document.getElementById('passwordDiv').style.display =
176-
(this.value === 'totp') ? 'none' : 'block';
196+
<h1>数据库安装</h1>
197+
<form action="install.php" method="post">
198+
<label for="dbHost">数据库地址:</label>
199+
<input type="text" id="dbHost" name="dbHost" value="127.0.0.1"><br><br>
200+
<label for="dbName">数据库名:</label>
201+
<input type="text" id="dbName" name="dbName" required><br><br>
202+
<label for="dbUser">数据库用户名:</label>
203+
<input type="text" id="dbUser" name="dbUser" required><br><br>
204+
<label for="dbPass">数据库密码:</label>
205+
<input type="password" id="dbPass" name="dbPass" required><br><br>
206+
<label for="account">授权账号:</label>
207+
<input type="text" id="account" name="account" required><br><br>
208+
<label for="password">授权密码:</label>
209+
<input type="password" id="password" name="password" required><br><br>
210+
<label for="redis">是否启用Redis:</label>
211+
<input type="checkbox" id="redis" name="redis" value="1"><br><br>
212+
<label for="admin_email">管理员邮箱:</label>
213+
<input type="text" name="admin_email" value="[email protected]" required><br><br>
214+
<label for="authMethod">密码类型:</label>
215+
<p>不懂或不清楚什么意思,请选择“传统密码”</p>
216+
<select id="authMethod" name="authMethod" required>
217+
<option value="password">传统密码</option>
218+
<option value="totp">TOTP</option>
219+
<option value="both">同时支持</option>
220+
</select><br><br>
221+
<div id="passwordDiv" style="display:block;">
222+
<label for="customPassword">自定义密码:</label>
223+
<input type="password" id="customPassword" name="customPassword">
224+
</div>
225+
<div style="display:block;">
226+
<label for="testData">测试数据:</label>
227+
<p>测试数据用于快速测试网站功能。完整数据是直接将开发环境的数据库dump下来。</p>
228+
<p>精简数据是从开发环境导出的数据,仅包含部分必要数据。</p>
229+
<p>不导入测试数据将仅创建数据库结构,不导入任何数据。</p>
230+
<p>此选项目前没用。</p>
231+
<select id="testData" name="testData" required>
232+
<option value="full">完整测试数据</option>
233+
<option value="must">精简测试数据</option>
234+
<option value="none">不导入测试数据</option>
235+
</select>
236+
</div>
237+
<input type="submit" value="安装">
238+
</form>
239+
240+
<script>
241+
document.addEventListener('DOMContentLoaded', function () {
242+
document.getElementById('authMethod').addEventListener('input', function () {
243+
var authMethod = this.value;
244+
var passwordDiv = document.getElementById('passwordDiv');
245+
if (authMethod === 'password' || authMethod === 'both') {
246+
passwordDiv.style.display = 'block';
247+
} else {
248+
passwordDiv.style.display = 'none';
249+
}
177250
});
178-
</script>
251+
});
252+
</script>
179253
</body>
180-
</html>
254+
</html>

0 commit comments

Comments
 (0)