|
|
<?php
|
|
|
require_once __DIR__ . '/../config/database.php';
|
|
|
require_once __DIR__ . '/../src/storage/Database.php';
|
|
|
require_once __DIR__ . '/../src/storage/ServiceRepository.php';
|
|
|
require_once __DIR__ . '/../src/storage/SystemSettingsRepository.php';
|
|
|
//
|
|
|
error_reporting(E_ALL);
|
|
|
ini_set('display_errors', 1);
|
|
|
|
|
|
session_start();
|
|
|
|
|
|
// 身份验证
|
|
|
if (!isset($_SESSION['user_id'])) {
|
|
|
header('Location: index.php');
|
|
|
exit;
|
|
|
}
|
|
|
|
|
|
$serviceRepo = new ServiceRepository();
|
|
|
$settingsRepo = new SystemSettingsRepository();
|
|
|
$message = '';
|
|
|
$error = '';
|
|
|
// ===================== 修改部分开始 =====================
|
|
|
// 添加服务控制函数
|
|
|
function startService($serviceName, $port) {
|
|
|
$scriptPath = __DIR__ . "/../scripts/start_{$serviceName}.php";
|
|
|
$logFile = __DIR__ . "/../logs/{$serviceName}.log";
|
|
|
|
|
|
// 检查服务是否已经在运行
|
|
|
if (isServiceRunning($serviceName)) {
|
|
|
return ['success' => false, 'message' => '服务已在运行'];
|
|
|
}
|
|
|
|
|
|
// 启动服务(后台运行)
|
|
|
$cmd = "php {$scriptPath} > {$logFile} 2>&1 & echo $!";
|
|
|
$pid = trim(shell_exec($cmd));
|
|
|
|
|
|
sleep(2); // 等待服务启动
|
|
|
|
|
|
if (isServiceRunning($serviceName)) {
|
|
|
return ['success' => true, 'pid' => $pid];
|
|
|
} else {
|
|
|
return ['success' => false, 'message' => '启动失败'];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function stopService($serviceName, $pid) {
|
|
|
if ($pid) {
|
|
|
// 使用 kill 命令终止进程
|
|
|
@exec("kill {$pid} 2>/dev/null");
|
|
|
sleep(1);
|
|
|
|
|
|
// 如果进程还在,强制终止
|
|
|
if (isServiceRunning($serviceName)) {
|
|
|
@exec("kill -9 {$pid} 2>/dev/null");
|
|
|
sleep(1);
|
|
|
}
|
|
|
} else {
|
|
|
// 如果没有PID,查找并终止所有相关进程
|
|
|
@exec("pkill -f 'start_{$serviceName}.php' 2>/dev/null");
|
|
|
@exec("pkill -f 'SmtpServer.php' 2>/dev/null");
|
|
|
@exec("pkill -f 'Pop3Server.php' 2>/dev/null");
|
|
|
}
|
|
|
|
|
|
return !isServiceRunning($serviceName);
|
|
|
}
|
|
|
|
|
|
function isServiceRunning($serviceName) {
|
|
|
// 检查端口是否被监听
|
|
|
$port = ($serviceName === 'smtp') ? 25 : 110;
|
|
|
$cmd = "netstat -tlnp 2>/dev/null | grep :{$port} | grep LISTEN";
|
|
|
$result = shell_exec($cmd);
|
|
|
return !empty($result);
|
|
|
}
|
|
|
|
|
|
function getServicePid($serviceName) {
|
|
|
$port = ($serviceName === 'smtp') ? 25 : 110;
|
|
|
$cmd = "lsof -ti:{$port} 2>/dev/null | head -1";
|
|
|
return trim(shell_exec($cmd));
|
|
|
}
|
|
|
// ===================== 修改部分结束 =====================
|
|
|
// 处理服务起停
|
|
|
if (isset($_GET['action'])) {
|
|
|
$serviceName = $_GET['service'] ?? '';
|
|
|
$action = $_GET['action'] ?? '';
|
|
|
|
|
|
if ($serviceName === 'smtp' || $serviceName === 'pop3') {
|
|
|
// ===================== 修改部分开始 =====================
|
|
|
// 实际启动服务
|
|
|
$port = ($serviceName === 'smtp') ?
|
|
|
$settingsRepo->get('smtp_port', 25) :
|
|
|
$settingsRepo->get('pop3_port', 110);
|
|
|
|
|
|
$result = startService($serviceName, $port);
|
|
|
|
|
|
if ($result['success']) {
|
|
|
$pid = $result['pid'];
|
|
|
$serviceRepo->updateStatus($serviceName, true, $pid);
|
|
|
$message = strtoupper($serviceName) . "服务已启动 (PID: {$pid})";
|
|
|
} else {
|
|
|
$error = strtoupper($serviceName) . "服务启动失败: " . $result['message'];
|
|
|
}
|
|
|
// ===================== 修改部分结束 =====================
|
|
|
}
|
|
|
elseif ($action === 'stop') {
|
|
|
// ===================== 修改部分开始 =====================
|
|
|
// 实际停止服务
|
|
|
$status = $serviceRepo->getStatus($serviceName);
|
|
|
$pid = $status['pid'] ?? getServicePid($serviceName);
|
|
|
|
|
|
if (stopService($serviceName, $pid)) {
|
|
|
$serviceRepo->updateStatus($serviceName, false, null);
|
|
|
$message = strtoupper($serviceName) . "服务已停止";
|
|
|
} else {
|
|
|
$error = strtoupper($serviceName) . "服务停止失败";
|
|
|
}
|
|
|
// ===================== 修改部分结束 =====================
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 获取服务状态
|
|
|
$smtpStatus = $serviceRepo->getStatus('smtp');
|
|
|
$pop3Status = $serviceRepo->getStatus('pop3');
|
|
|
// 实际检查服务是否运行
|
|
|
$smtpRunning = isServiceRunning('smtp');
|
|
|
$pop3Running = isServiceRunning('pop3');
|
|
|
|
|
|
// 如果数据库状态与实际状态不一致,更新数据库
|
|
|
if ($smtpStatus['is_running'] != $smtpRunning) {
|
|
|
$pid = $smtpRunning ? getServicePid('smtp') : null;
|
|
|
$serviceRepo->updateStatus('smtp', $smtpRunning, $pid);
|
|
|
}
|
|
|
|
|
|
if ($pop3Status['is_running'] != $pop3Running) {
|
|
|
$pid = $pop3Running ? getServicePid('pop3') : null;
|
|
|
$serviceRepo->updateStatus('pop3', $pop3Running, $pid);
|
|
|
}
|
|
|
|
|
|
// 重新获取更新后的状态
|
|
|
$smtpStatus = $serviceRepo->getStatus('smtp');
|
|
|
$pop3Status = $serviceRepo->getStatus('pop3');
|
|
|
$smtpRunning = $smtpStatus['is_running'];
|
|
|
$pop3Running = $pop3Status['is_running'];
|
|
|
// ===================== 修改部分结束 =====================
|
|
|
|
|
|
// 获取端口设置
|
|
|
$smtpPort = $settingsRepo->get('smtp_port', 25);
|
|
|
$pop3Port = $settingsRepo->get('pop3_port', 110);
|
|
|
?>
|
|
|
<!DOCTYPE html>
|
|
|
<html>
|
|
|
<head>
|
|
|
<title>服务管理 - 邮件服务器</title>
|
|
|
<meta charset="UTF-8">
|
|
|
<style>
|
|
|
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }
|
|
|
.header { background: #007bff; color: white; padding: 15px; margin: -20px -20px 20px -20px; }
|
|
|
.menu { background: white; padding: 10px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
|
|
.menu a { margin-right: 15px; text-decoration: none; color: #007bff; }
|
|
|
.container { background: white; padding: 20px; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
|
|
.message { background: #d4edda; color: #155724; padding: 12px; border-radius: 5px; margin-bottom: 20px; }
|
|
|
.error { background: #f8d7da; color: #721c24; padding: 12px; border-radius: 5px; margin-bottom: 20px; }
|
|
|
.service-box { border: 1px solid #ddd; padding: 20px; margin-bottom: 20px; border-radius: 5px; }
|
|
|
.service-box h3 { margin-top: 0; }
|
|
|
.status { display: inline-block; padding: 6px 12px; border-radius: 4px; font-weight: 500; margin-right: 10px; }
|
|
|
.status-running { background: #28a745; color: white; }
|
|
|
.status-stopped { background: #dc3545; color: white; }
|
|
|
.btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; text-decoration: none; display: inline-block; }
|
|
|
.btn-success { background: #28a745; color: white; }
|
|
|
.btn-danger { background: #dc3545; color: white; }
|
|
|
.info { color: #666; font-size: 14px; margin-top: 10px; }
|
|
|
.note { background: #fff3cd; border: 1px solid #ffc107; padding: 15px; border-radius: 5px; margin-top: 20px; }
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<div class="header">
|
|
|
<h1>邮件服务器管理后台</h1>
|
|
|
<div>欢迎, <?php echo htmlspecialchars($_SESSION['username']); ?>
|
|
|
(<a href="logout.php" style="color: white;">退出</a>)
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="menu">
|
|
|
<a href="index.php">仪表盘</a>
|
|
|
<a href="users.php">用户管理</a>
|
|
|
<a href="broadcast.php">群发邮件</a>
|
|
|
<a href="filters.php">过滤规则</a>
|
|
|
<a href="logs.php">系统日志</a>
|
|
|
<a href="services.php">服务管理</a>
|
|
|
<a href="settings.php">系统设置</a>
|
|
|
<a href="help.php">帮助</a>
|
|
|
</div>
|
|
|
|
|
|
<div class="container">
|
|
|
<h2>服务管理</h2>
|
|
|
|
|
|
<?php if ($message): ?>
|
|
|
<div class="message"><?php echo $message; ?></div>
|
|
|
<?php endif; ?>
|
|
|
|
|
|
<?php if ($error): ?>
|
|
|
<div class="error"><?php echo $error; ?></div>
|
|
|
<?php endif; ?>
|
|
|
|
|
|
<!-- SMTP服务 -->
|
|
|
<div class="service-box">
|
|
|
<h3>SMTP服务(邮件发送)</h3>
|
|
|
<p>
|
|
|
<span class="status status-<?php echo $smtpRunning ? 'running' : 'stopped'; ?>">
|
|
|
<?php echo $smtpRunning ? '运行中' : '已停止'; ?>
|
|
|
</span>
|
|
|
<?php if ($smtpRunning): ?>
|
|
|
<a href="?service=smtp&action=stop" class="btn btn-danger" onclick="return confirm('确定要停止SMTP服务吗?');">停止服务</a>
|
|
|
<?php else: ?>
|
|
|
<a href="?service=smtp&action=start" class="btn btn-success" onclick="return confirm('确定要启动SMTP服务吗?');">启动服务</a>
|
|
|
<?php endif; ?>
|
|
|
</p>
|
|
|
<div class="info">
|
|
|
<strong>端口:</strong><?php echo $smtpPort; ?><br>
|
|
|
<strong>进程ID:</strong><?php echo $smtpStatus['pid'] ?? '-'; ?><br>
|
|
|
<strong>最后启动:</strong><?php echo $smtpStatus['last_started_at'] ?? '-'; ?><br>
|
|
|
<strong>最后停止:</strong><?php echo $smtpStatus['last_stopped_at'] ?? '-'; ?>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- POP3服务 -->
|
|
|
<div class="service-box">
|
|
|
<h3>POP3服务(邮件接收)</h3>
|
|
|
<p>
|
|
|
<span class="status status-<?php echo $pop3Running ? 'running' : 'stopped'; ?>">
|
|
|
<?php echo $pop3Running ? '运行中' : '已停止'; ?>
|
|
|
</span>
|
|
|
<?php if ($pop3Running): ?>
|
|
|
<a href="?service=pop3&action=stop" class="btn btn-danger" onclick="return confirm('确定要停止POP3服务吗?');">停止服务</a>
|
|
|
<?php else: ?>
|
|
|
<a href="?service=pop3&action=start" class="btn btn-success" onclick="return confirm('确定要启动POP3服务吗?');">启动服务</a>
|
|
|
<?php endif; ?>
|
|
|
</p>
|
|
|
<div class="info">
|
|
|
<strong>端口:</strong><?php echo $pop3Port; ?><br>
|
|
|
<strong>进程ID:</strong><?php echo $pop3Status['pid'] ?? '-'; ?><br>
|
|
|
<strong>最后启动:</strong><?php echo $pop3Status['last_started_at'] ?? '-'; ?><br>
|
|
|
<strong>最后停止:</strong><?php echo $pop3Status['last_stopped_at'] ?? '-'; ?>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="note">
|
|
|
<strong>注意:</strong>此页面仅用于管理服务状态。实际启动服务需要使用命令行:
|
|
|
<ul>
|
|
|
<li>SMTP服务:<code>sudo php scripts/start_smtp.php</code></li>
|
|
|
<li>POP3服务:<code>sudo php scripts/start_pop3.php</code></li>
|
|
|
<li>服务状态实时检测,无需手动刷新</li>
|
|
|
<li>启动/停止可能需要几秒钟时间</li>
|
|
|
<li>如果服务启动失败,请检查端口是否被占用</li>
|
|
|
</ul>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- ===================== 新增部分:自动刷新状态 ===================== -->
|
|
|
<script>
|
|
|
// 每5秒自动检查服务状态
|
|
|
setInterval(function() {
|
|
|
fetch(window.location.href)
|
|
|
.then(response => response.text())
|
|
|
.then(html => {
|
|
|
// 从返回的HTML中提取运行状态
|
|
|
const tempDiv = document.createElement('div');
|
|
|
tempDiv.innerHTML = html;
|
|
|
|
|
|
// 检查SMTP状态是否变化
|
|
|
const smtpStatusText = tempDiv.querySelector('.service-box:nth-child(1) .status')?.textContent;
|
|
|
const currentSmtpStatus = document.querySelector('.service-box:nth-child(1) .status')?.textContent;
|
|
|
|
|
|
// 检查POP3状态是否变化
|
|
|
const pop3StatusText = tempDiv.querySelector('.service-box:nth-child(2) .status')?.textContent;
|
|
|
const currentPop3Status = document.querySelector('.service-box:nth-child(2) .status')?.textContent;
|
|
|
|
|
|
// 如果有变化,刷新页面
|
|
|
if (smtpStatusText !== currentSmtpStatus || pop3StatusText !== currentPop3Status) {
|
|
|
console.log('服务状态变化,刷新页面...');
|
|
|
location.reload();
|
|
|
}
|
|
|
})
|
|
|
.catch(error => console.error('状态检查失败:', error));
|
|
|
}, 5000);
|
|
|
</script>
|
|
|
<!-- ===================== 新增部分结束 ===================== -->
|
|
|
</body>
|
|
|
</html>
|
|
|
|