get('smtp_port', 25); $pop3Port = $settingsRepo->get('pop3_port', 110); function startService($serviceName, $port) { $scriptPath = __DIR__ . "/../scripts/start_{$serviceName}.php"; $logFile = __DIR__ . "/../logs/{$serviceName}.log"; error_log("尝试启动服务: $serviceName , 端口: $port"); if (!file_exists($scriptPath)) { return ['success' => false, 'message' => '启动脚本不存在']; } if (isServiceRunning($serviceName, $port)) { return ['success' => false, 'message' => '服务已在运行']; } @file_put_contents($logFile, ''); //===== 修复:更稳健的命令执行 ===== $raw = shell_exec(sprintf( 'cd %s && (%s > %s 2>/dev/null /dev/null 2>&1 false, 'message' => '未能获取有效进程号']; } /* ===== 修复:添加进程状态检查 ===== */ sleep(1); // 先等待1秒 // 检查进程是否还在运行 $processExists = file_exists("/proc/$pid"); error_log("进程是否存在: " . ($processExists ? "是" : "否")); if (!$processExists) { // 查看脚本为什么退出了 if (file_exists($logFile)) { $logContent = file_get_contents($logFile); error_log("脚本输出日志:\n" . $logContent); } return ['success' => false, 'message' => '进程已退出']; } /* ===== 修复:更长的等待时间 ===== */ $maxChecks = 6; for ($i = 0; $i < $maxChecks; $i++) { sleep(1); // 每次检查等待1秒 if (isServiceRunning($serviceName, $port)) { // 再次确认PID仍然有效 if (file_exists("/proc/$pid")) { return ['success' => true, 'pid' => $pid]; } else { // 进程已退出 return ['success' => false, 'message' => '进程已退出']; } } error_log("第 " . ($i+1) . " 次检查:端口未监听"); } // 启动失败 → 清理孤儿 if (file_exists("/proc/$pid")) { @exec("kill -9 {$pid} 2>/dev/null"); } // 输出失败原因 if (file_exists($logFile)) { // 只读取最后10行,避免读取大文件 $logContent = shell_exec("tail -10 " . escapeshellarg($logFile)); error_log("最终日志内容(最后100行):\n" . $logContent); } return ['success' => false, 'message' => '服务端口未监听,启动失败']; } function stopService($serviceName, $pid, $port) { // ===== 改:优先用 DB 里的 PID,没有再现场嗅探 ===== if (empty($pid) || !is_numeric($pid)) { $pid = getServicePid($serviceName, $port); } if ($pid) { @exec("kill {$pid} 2>/dev/null"); sleep(1); if (isServiceRunning($serviceName, $port)) { @exec("kill -9 {$pid} 2>/dev/null"); sleep(1); } } return !isServiceRunning($serviceName, $port); } function isServiceRunning($serviceName, $port) { // 方法1: 使用单引号确保变量正确展开 $cmd1 = "netstat -tlnp 2>/dev/null | grep ':" . $port . "' | grep LISTEN"; $result1 = shell_exec($cmd1); // 方法2: 使用ss命令(更可靠) $cmd2 = "ss -tlnp 2>/dev/null | grep ':" . $port . "'"; $result2 = shell_exec($cmd2); // 方法3: 使用lsof(你已验证有效) $cmd3 = "lsof -i :" . $port . " 2>/dev/null"; $result3 = shell_exec($cmd3); // 方法4: 直接socket连接测试(最可靠) $fp = @fsockopen('127.0.0.1', $port, $errno, $errstr, 1); if ($fp) { fclose($fp); return true; } // 任意一个方法有结果都算服务在运行 return !empty(trim($result1 ?? '')) || !empty(trim($result2 ?? '')) || !empty(trim($result3 ?? '')); } function getServicePid($serviceName, $port) { return trim(shell_exec("lsof -ti: {$port} 2>/dev/null | head -1")); } // ===================== 修改部分结束 ===================== // 处理服务起停 if (isset($_GET['action'])) { $serviceName = $_GET['service'] ?? ''; $action = $_GET['action'] ?? ''; if ($serviceName === 'smtp' || $serviceName === 'pop3') { $port = $serviceName === 'smtp' ? $smtpPort : $pop3Port; if ($action === 'start') { $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, $port); if (stopService($serviceName, $pid, $port)) { $serviceRepo->updateStatus($serviceName, false, null); $message = strtoupper($serviceName) . "服务已停止"; } else { $error = strtoupper($serviceName) . "服务停止失败"; } // ===================== 修改部分结束 ===================== } } } // 获取服务状态(修改判断逻辑) // ===================== 修改部分开始 ===================== $smtpStatus = $serviceRepo->getStatus('smtp'); $pop3Status = $serviceRepo->getStatus('pop3'); // 实际检查服务是否运行(使用配置的端口) $smtpRunning = isServiceRunning('smtp', $smtpPort); $pop3Running = isServiceRunning('pop3', $pop3Port); // 如果数据库状态与实际状态不一致,更新数据库 if ($smtpStatus['is_running'] != $smtpRunning) { $pid = $smtpRunning ? getServicePid('smtp', $smtpPort) : null; $serviceRepo->updateStatus('smtp', $smtpRunning, $pid); } if ($pop3Status['is_running'] != $pop3Running) { $pid = $pop3Running ? getServicePid('pop3', $pop3Port) : null; $serviceRepo->updateStatus('pop3', $pop3Running, $pid); } // 重新获取更新后的状态 $smtpStatus = $serviceRepo->getStatus('smtp'); $pop3Status = $serviceRepo->getStatus('pop3'); $smtpRunning = $smtpStatus['is_running']; $pop3Running = $pop3Status['is_running']; // ===================== 修改部分结束 ===================== ?> 服务管理 - 邮件服务器

邮件服务器管理后台

欢迎, (退出)

服务管理

SMTP服务(邮件发送)

停止服务 启动服务

端口:
进程ID:
最后启动:
最后停止:

POP3服务(邮件接收)

停止服务 启动服务

端口:
进程ID:
最后启动:
最后停止:
注意: