478 lines
16 KiB
PHP
478 lines
16 KiB
PHP
|
<?php
|
|||
|
/**
|
|||
|
* 安装脚本
|
|||
|
* 用于初始化数据库和检查环境
|
|||
|
*/
|
|||
|
|
|||
|
$step = $_GET['step'] ?? 1;
|
|||
|
$message = '';
|
|||
|
$message_type = '';
|
|||
|
|
|||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||
|
if ($step == 2) {
|
|||
|
// 数据库配置测试
|
|||
|
$db_type = $_POST['db_type'] ?? 'mysql';
|
|||
|
$host = $_POST['host'] ?? 'localhost';
|
|||
|
$dbname = $_POST['dbname'] ?? 'submission_system';
|
|||
|
$username = $_POST['username'] ?? 'root';
|
|||
|
$password = $_POST['password'] ?? '';
|
|||
|
|
|||
|
try {
|
|||
|
if ($db_type === 'sqlite') {
|
|||
|
$pdo = new PDO('sqlite:' . __DIR__ . '/data/database.sqlite');
|
|||
|
$message = 'SQLite数据库连接成功!';
|
|||
|
$message_type = 'success';
|
|||
|
|
|||
|
// 更新配置文件
|
|||
|
$config_content = file_get_contents('config/database.php');
|
|||
|
$config_content = str_replace('private $use_sqlite = false;', 'private $use_sqlite = true;', $config_content);
|
|||
|
file_put_contents('config/database.php', $config_content);
|
|||
|
} else {
|
|||
|
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
|
|||
|
$message = 'MySQL数据库连接成功!';
|
|||
|
$message_type = 'success';
|
|||
|
|
|||
|
// 更新配置文件
|
|||
|
$config_content = file_get_contents('config/database.php');
|
|||
|
$config_content = str_replace("private \$host = 'localhost';", "private \$host = '$host';", $config_content);
|
|||
|
$config_content = str_replace("private \$db_name = 'submission_system';", "private \$db_name = '$dbname';", $config_content);
|
|||
|
$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);
|
|||
|
}
|
|||
|
|
|||
|
$step = 3;
|
|||
|
} catch (PDOException $e) {
|
|||
|
$message = '数据库连接失败: ' . $e->getMessage();
|
|||
|
$message_type = 'error';
|
|||
|
}
|
|||
|
} elseif ($step == 3) {
|
|||
|
// 初始化数据库
|
|||
|
require_once 'config/database.php';
|
|||
|
|
|||
|
$database = new Database();
|
|||
|
if ($database->initDatabase()) {
|
|||
|
$message = '数据库初始化成功!';
|
|||
|
$message_type = 'success';
|
|||
|
$step = 4;
|
|||
|
} else {
|
|||
|
$message = '数据库初始化失败!';
|
|||
|
$message_type = 'error';
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 环境检查
|
|||
|
function checkEnvironment() {
|
|||
|
$checks = [
|
|||
|
'PHP版本 >= 7.4' => version_compare(PHP_VERSION, '7.4.0', '>='),
|
|||
|
'PDO扩展' => extension_loaded('pdo'),
|
|||
|
'PDO MySQL扩展' => extension_loaded('pdo_mysql'),
|
|||
|
'PDO SQLite扩展' => extension_loaded('pdo_sqlite'),
|
|||
|
'GD扩展' => extension_loaded('gd'),
|
|||
|
'cURL扩展' => extension_loaded('curl'),
|
|||
|
'config目录可写' => is_writable(__DIR__ . '/config'),
|
|||
|
'data目录可写' => is_writable(__DIR__ . '/data') || mkdir(__DIR__ . '/data', 0755, true)
|
|||
|
];
|
|||
|
|
|||
|
return $checks;
|
|||
|
}
|
|||
|
|
|||
|
$env_checks = checkEnvironment();
|
|||
|
?>
|
|||
|
|
|||
|
<!DOCTYPE html>
|
|||
|
<html lang="zh-CN">
|
|||
|
<head>
|
|||
|
<meta charset="UTF-8">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
<title>安装向导 - 内容投稿系统</title>
|
|||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
|||
|
<style>
|
|||
|
* {
|
|||
|
margin: 0;
|
|||
|
padding: 0;
|
|||
|
box-sizing: border-box;
|
|||
|
}
|
|||
|
|
|||
|
body {
|
|||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|||
|
min-height: 100vh;
|
|||
|
padding: 20px;
|
|||
|
}
|
|||
|
|
|||
|
.container {
|
|||
|
max-width: 600px;
|
|||
|
margin: 0 auto;
|
|||
|
background: rgba(255, 255, 255, 0.95);
|
|||
|
border-radius: 20px;
|
|||
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
|||
|
overflow: hidden;
|
|||
|
backdrop-filter: blur(10px);
|
|||
|
}
|
|||
|
|
|||
|
.header {
|
|||
|
background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
|
|||
|
color: white;
|
|||
|
padding: 40px;
|
|||
|
text-align: center;
|
|||
|
}
|
|||
|
|
|||
|
.header h1 {
|
|||
|
font-size: 2rem;
|
|||
|
font-weight: 700;
|
|||
|
margin-bottom: 10px;
|
|||
|
}
|
|||
|
|
|||
|
.step-indicator {
|
|||
|
display: flex;
|
|||
|
justify-content: center;
|
|||
|
gap: 10px;
|
|||
|
margin-top: 20px;
|
|||
|
}
|
|||
|
|
|||
|
.step {
|
|||
|
width: 30px;
|
|||
|
height: 30px;
|
|||
|
border-radius: 50%;
|
|||
|
background: rgba(255, 255, 255, 0.3);
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
justify-content: center;
|
|||
|
font-weight: 600;
|
|||
|
}
|
|||
|
|
|||
|
.step.active {
|
|||
|
background: white;
|
|||
|
color: #4f46e5;
|
|||
|
}
|
|||
|
|
|||
|
.step.completed {
|
|||
|
background: #10b981;
|
|||
|
color: white;
|
|||
|
}
|
|||
|
|
|||
|
.content {
|
|||
|
padding: 40px;
|
|||
|
}
|
|||
|
|
|||
|
.message {
|
|||
|
padding: 15px;
|
|||
|
border-radius: 8px;
|
|||
|
margin-bottom: 20px;
|
|||
|
font-weight: 500;
|
|||
|
}
|
|||
|
|
|||
|
.message.success {
|
|||
|
background: #d1fae5;
|
|||
|
color: #065f46;
|
|||
|
border: 1px solid #10b981;
|
|||
|
}
|
|||
|
|
|||
|
.message.error {
|
|||
|
background: #fee2e2;
|
|||
|
color: #991b1b;
|
|||
|
border: 1px solid #ef4444;
|
|||
|
}
|
|||
|
|
|||
|
.check-list {
|
|||
|
list-style: none;
|
|||
|
margin-bottom: 20px;
|
|||
|
}
|
|||
|
|
|||
|
.check-item {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
gap: 10px;
|
|||
|
padding: 10px 0;
|
|||
|
border-bottom: 1px solid #e5e7eb;
|
|||
|
}
|
|||
|
|
|||
|
.check-item:last-child {
|
|||
|
border-bottom: none;
|
|||
|
}
|
|||
|
|
|||
|
.check-icon {
|
|||
|
width: 20px;
|
|||
|
text-align: center;
|
|||
|
}
|
|||
|
|
|||
|
.check-icon.success {
|
|||
|
color: #10b981;
|
|||
|
}
|
|||
|
|
|||
|
.check-icon.error {
|
|||
|
color: #ef4444;
|
|||
|
}
|
|||
|
|
|||
|
.form-group {
|
|||
|
margin-bottom: 20px;
|
|||
|
}
|
|||
|
|
|||
|
.form-group label {
|
|||
|
display: block;
|
|||
|
margin-bottom: 8px;
|
|||
|
font-weight: 600;
|
|||
|
color: #374151;
|
|||
|
}
|
|||
|
|
|||
|
.form-group input,
|
|||
|
.form-group select {
|
|||
|
width: 100%;
|
|||
|
padding: 12px 16px;
|
|||
|
border: 2px solid #e5e7eb;
|
|||
|
border-radius: 8px;
|
|||
|
font-size: 16px;
|
|||
|
}
|
|||
|
|
|||
|
.form-group input:focus,
|
|||
|
.form-group select:focus {
|
|||
|
outline: none;
|
|||
|
border-color: #4f46e5;
|
|||
|
}
|
|||
|
|
|||
|
.btn {
|
|||
|
padding: 12px 24px;
|
|||
|
border: none;
|
|||
|
border-radius: 8px;
|
|||
|
font-size: 16px;
|
|||
|
font-weight: 600;
|
|||
|
cursor: pointer;
|
|||
|
transition: all 0.3s ease;
|
|||
|
display: inline-flex;
|
|||
|
align-items: center;
|
|||
|
gap: 8px;
|
|||
|
}
|
|||
|
|
|||
|
.btn-primary {
|
|||
|
background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
|
|||
|
color: white;
|
|||
|
}
|
|||
|
|
|||
|
.btn-primary:hover {
|
|||
|
transform: translateY(-2px);
|
|||
|
box-shadow: 0 10px 20px rgba(79, 70, 229, 0.3);
|
|||
|
}
|
|||
|
|
|||
|
.btn-success {
|
|||
|
background: #10b981;
|
|||
|
color: white;
|
|||
|
}
|
|||
|
|
|||
|
.btn-success:hover {
|
|||
|
background: #059669;
|
|||
|
}
|
|||
|
|
|||
|
.actions {
|
|||
|
display: flex;
|
|||
|
gap: 15px;
|
|||
|
justify-content: center;
|
|||
|
margin-top: 30px;
|
|||
|
}
|
|||
|
|
|||
|
.db-option {
|
|||
|
padding: 20px;
|
|||
|
border: 2px solid #e5e7eb;
|
|||
|
border-radius: 8px;
|
|||
|
margin-bottom: 15px;
|
|||
|
cursor: pointer;
|
|||
|
transition: all 0.3s ease;
|
|||
|
}
|
|||
|
|
|||
|
.db-option:hover {
|
|||
|
border-color: #4f46e5;
|
|||
|
}
|
|||
|
|
|||
|
.db-option.selected {
|
|||
|
border-color: #4f46e5;
|
|||
|
background: #f0f9ff;
|
|||
|
}
|
|||
|
|
|||
|
.db-config {
|
|||
|
display: none;
|
|||
|
margin-top: 20px;
|
|||
|
padding: 20px;
|
|||
|
background: #f8fafc;
|
|||
|
border-radius: 8px;
|
|||
|
}
|
|||
|
|
|||
|
.db-config.active {
|
|||
|
display: block;
|
|||
|
}
|
|||
|
</style>
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
<div class="container">
|
|||
|
<div class="header">
|
|||
|
<h1><i class="fas fa-cogs"></i> 安装向导</h1>
|
|||
|
<p>内容投稿系统安装配置</p>
|
|||
|
<div class="step-indicator">
|
|||
|
<div class="step <?php echo $step >= 1 ? ($step > 1 ? 'completed' : 'active') : ''; ?>">1</div>
|
|||
|
<div class="step <?php echo $step >= 2 ? ($step > 2 ? 'completed' : 'active') : ''; ?>">2</div>
|
|||
|
<div class="step <?php echo $step >= 3 ? ($step > 3 ? 'completed' : 'active') : ''; ?>">3</div>
|
|||
|
<div class="step <?php echo $step >= 4 ? 'active' : ''; ?>">4</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="content">
|
|||
|
<?php if ($message): ?>
|
|||
|
<div class="message <?php echo $message_type; ?>">
|
|||
|
<?php echo htmlspecialchars($message); ?>
|
|||
|
</div>
|
|||
|
<?php endif; ?>
|
|||
|
|
|||
|
<?php if ($step == 1): ?>
|
|||
|
<!-- 步骤1: 环境检查 -->
|
|||
|
<h2>环境检查</h2>
|
|||
|
<p>正在检查服务器环境是否满足运行要求...</p>
|
|||
|
|
|||
|
<ul class="check-list">
|
|||
|
<?php foreach ($env_checks as $name => $status): ?>
|
|||
|
<li class="check-item">
|
|||
|
<div class="check-icon <?php echo $status ? 'success' : 'error'; ?>">
|
|||
|
<i class="fas <?php echo $status ? 'fa-check' : 'fa-times'; ?>"></i>
|
|||
|
</div>
|
|||
|
<span><?php echo $name; ?></span>
|
|||
|
</li>
|
|||
|
<?php endforeach; ?>
|
|||
|
</ul>
|
|||
|
|
|||
|
<?php if (array_product($env_checks)): ?>
|
|||
|
<div class="actions">
|
|||
|
<a href="?step=2" class="btn btn-primary">
|
|||
|
<i class="fas fa-arrow-right"></i> 下一步
|
|||
|
</a>
|
|||
|
</div>
|
|||
|
<?php else: ?>
|
|||
|
<div class="message error">
|
|||
|
<i class="fas fa-exclamation-triangle"></i>
|
|||
|
环境检查未通过,请先解决上述问题后再继续安装。
|
|||
|
</div>
|
|||
|
<?php endif; ?>
|
|||
|
|
|||
|
<?php elseif ($step == 2): ?>
|
|||
|
<!-- 步骤2: 数据库配置 -->
|
|||
|
<h2>数据库配置</h2>
|
|||
|
<p>请选择数据库类型并配置连接信息。</p>
|
|||
|
|
|||
|
<form method="POST">
|
|||
|
<div class="db-option" onclick="selectDatabase('mysql')">
|
|||
|
<h3><i class="fas fa-database"></i> MySQL数据库</h3>
|
|||
|
<p>适合生产环境,性能更好,支持并发访问</p>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="db-option" onclick="selectDatabase('sqlite')">
|
|||
|
<h3><i class="fas fa-file-alt"></i> SQLite数据库</h3>
|
|||
|
<p>适合小型站点,无需额外配置,开箱即用</p>
|
|||
|
</div>
|
|||
|
|
|||
|
<input type="hidden" name="db_type" id="db_type" value="mysql">
|
|||
|
|
|||
|
<div class="db-config" id="mysql-config">
|
|||
|
<h4>MySQL配置</h4>
|
|||
|
<div class="form-group">
|
|||
|
<label for="host">数据库主机</label>
|
|||
|
<input type="text" name="host" id="host" value="localhost" required>
|
|||
|
</div>
|
|||
|
<div class="form-group">
|
|||
|
<label for="dbname">数据库名称</label>
|
|||
|
<input type="text" name="dbname" id="dbname" value="submission_system" required>
|
|||
|
</div>
|
|||
|
<div class="form-group">
|
|||
|
<label for="username">用户名</label>
|
|||
|
<input type="text" name="username" id="username" value="root" required>
|
|||
|
</div>
|
|||
|
<div class="form-group">
|
|||
|
<label for="password">密码</label>
|
|||
|
<input type="password" name="password" id="password">
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="db-config" id="sqlite-config">
|
|||
|
<h4>SQLite配置</h4>
|
|||
|
<p>SQLite数据库将自动创建在 data/database.sqlite 文件中,无需额外配置。</p>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="actions">
|
|||
|
<button type="submit" class="btn btn-primary">
|
|||
|
<i class="fas fa-check"></i> 测试连接
|
|||
|
</button>
|
|||
|
</div>
|
|||
|
</form>
|
|||
|
|
|||
|
<?php elseif ($step == 3): ?>
|
|||
|
<!-- 步骤3: 初始化数据库 -->
|
|||
|
<h2>初始化数据库</h2>
|
|||
|
<p>数据库连接成功!现在将创建必要的数据表。</p>
|
|||
|
|
|||
|
<form method="POST">
|
|||
|
<div class="actions">
|
|||
|
<button type="submit" class="btn btn-primary">
|
|||
|
<i class="fas fa-database"></i> 初始化数据库
|
|||
|
</button>
|
|||
|
</div>
|
|||
|
</form>
|
|||
|
|
|||
|
<?php elseif ($step == 4): ?>
|
|||
|
<!-- 步骤4: 安装完成 -->
|
|||
|
<h2>安装完成</h2>
|
|||
|
<div class="message success">
|
|||
|
<i class="fas fa-check-circle"></i>
|
|||
|
恭喜!内容投稿系统安装成功!
|
|||
|
</div>
|
|||
|
|
|||
|
<h3>默认管理员账户</h3>
|
|||
|
<p><strong>用户名:</strong>admin</p>
|
|||
|
<p><strong>密码:</strong>admin</p>
|
|||
|
<p style="color: #ef4444; margin-top: 10px;">⚠️ 请登录后台后立即修改默认密码!</p>
|
|||
|
|
|||
|
<h3>下一步操作</h3>
|
|||
|
<ul style="margin: 20px 0; padding-left: 20px;">
|
|||
|
<li>删除或重命名 install.php 文件以确保安全</li>
|
|||
|
<li>配置Web服务器(如Apache、Nginx)</li>
|
|||
|
<li>设置适当的文件权限</li>
|
|||
|
<li>登录管理后台修改默认密码</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<div class="actions">
|
|||
|
<a href="index.php" class="btn btn-primary">
|
|||
|
<i class="fas fa-home"></i> 访问前台
|
|||
|
</a>
|
|||
|
<a href="admin/login.php" class="btn btn-success">
|
|||
|
<i class="fas fa-shield-alt"></i> 管理后台
|
|||
|
</a>
|
|||
|
</div>
|
|||
|
<?php endif; ?>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<script>
|
|||
|
function selectDatabase(type) {
|
|||
|
// 移除所有选中状态
|
|||
|
document.querySelectorAll('.db-option').forEach(option => {
|
|||
|
option.classList.remove('selected');
|
|||
|
});
|
|||
|
|
|||
|
// 隐藏所有配置
|
|||
|
document.querySelectorAll('.db-config').forEach(config => {
|
|||
|
config.classList.remove('active');
|
|||
|
});
|
|||
|
|
|||
|
// 选中当前选项
|
|||
|
event.currentTarget.classList.add('selected');
|
|||
|
|
|||
|
// 显示对应配置
|
|||
|
document.getElementById(type + '-config').classList.add('active');
|
|||
|
|
|||
|
// 设置表单值
|
|||
|
document.getElementById('db_type').value = type;
|
|||
|
}
|
|||
|
|
|||
|
// 默认选择MySQL
|
|||
|
document.addEventListener('DOMContentLoaded', function() {
|
|||
|
document.querySelector('.db-option').click();
|
|||
|
});
|
|||
|
</script>
|
|||
|
</body>
|
|||
|
</html>
|