parent
fe37b27513
commit
9b44622099
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
require_once __DIR__ . '/../src/storage/Database.php';
|
||||
require_once __DIR__ . '/../src/storage/UserRepository.php';
|
||||
require_once __DIR__ . '/../src/storage/EmailRepository.php';
|
||||
require_once __DIR__ . '/../src/admin/BroadcastService.php';
|
||||
require_once __DIR__ . '/../src/utils/Security.php';
|
||||
|
||||
session_start();
|
||||
|
||||
// 身份验证
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 检查管理员权限
|
||||
if (!$_SESSION['is_admin']) {
|
||||
die('权限不足:只有管理员可以访问此页面');
|
||||
}
|
||||
|
||||
$broadcastService = new BroadcastService();
|
||||
$userRepo = new UserRepository();
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
// 处理群发邮件
|
||||
if (isset($_POST['send_broadcast'])) {
|
||||
$subject = trim($_POST['subject'] ?? '');
|
||||
$body = trim($_POST['body'] ?? '');
|
||||
$broadcastType = $_POST['broadcast_type'] ?? 'all';
|
||||
$recipients = trim($_POST['recipients'] ?? '');
|
||||
|
||||
if (empty($subject)) {
|
||||
$error = "主题不能为空";
|
||||
} elseif (empty($body)) {
|
||||
$error = "邮件内容不能为空";
|
||||
} else {
|
||||
$senderEmail = $_SESSION['username'];
|
||||
|
||||
try {
|
||||
if ($broadcastType === 'all') {
|
||||
// 群发给所有用户
|
||||
$result = $broadcastService->broadcastToAll($senderEmail, $subject, $body);
|
||||
} else {
|
||||
// 群发给指定用户
|
||||
$recipientList = array_filter(array_map('trim', explode(',', $recipients)));
|
||||
if (empty($recipientList)) {
|
||||
$error = "请指定收件人";
|
||||
} else {
|
||||
$result = $broadcastService->broadcastToUsers($senderEmail, $recipientList, $subject, $body);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($result)) {
|
||||
if ($result['success'] > 0) {
|
||||
$message = "群发成功!成功发送 {$result['success']} 封邮件";
|
||||
if ($result['failed'] > 0) {
|
||||
$message .= ",失败 {$result['failed']} 封";
|
||||
}
|
||||
if (!empty($result['errors'])) {
|
||||
$error = "部分失败:" . implode('<br>', array_slice($result['errors'], 0, 5));
|
||||
if (count($result['errors']) > 5) {
|
||||
$error .= "<br>... 还有 " . (count($result['errors']) - 5) . " 个错误";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$error = "群发失败:" . implode('<br>', $result['errors']);
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$error = "群发失败: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有用户列表(用于选择收件人)
|
||||
$allUsers = $userRepo->getAll();
|
||||
?>
|
||||
<!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); max-width: 800px; }
|
||||
.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; }
|
||||
.form-group { margin-bottom: 20px; }
|
||||
.form-group label { display: block; margin-bottom: 8px; font-weight: 500; }
|
||||
.form-group input, .form-group textarea, .form-group select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; }
|
||||
.form-group textarea { min-height: 200px; font-family: monospace; }
|
||||
.form-group small { color: #666; font-size: 12px; }
|
||||
.btn { padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; }
|
||||
.btn-primary { background: #007bff; color: white; }
|
||||
.btn-primary:hover { background: #0056b3; }
|
||||
.radio-group { display: flex; gap: 20px; margin-bottom: 15px; }
|
||||
.radio-group label { display: flex; align-items: center; cursor: pointer; }
|
||||
.radio-group input[type="radio"] { width: auto; margin-right: 5px; }
|
||||
.user-list { max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 10px; border-radius: 4px; background: #f8f9fa; }
|
||||
.user-list-item { padding: 5px; }
|
||||
</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="emails.php">邮件管理</a>
|
||||
<a href="broadcast.php">群发邮件</a>
|
||||
<a href="filters.php">过滤规则</a>
|
||||
<a href="logs.php">系统日志</a>
|
||||
<a href="settings.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; ?>
|
||||
|
||||
<form method="POST">
|
||||
<div class="form-group">
|
||||
<label>发送方式</label>
|
||||
<div class="radio-group">
|
||||
<label>
|
||||
<input type="radio" name="broadcast_type" value="all" checked onchange="toggleRecipients()">
|
||||
发送给所有用户
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="broadcast_type" value="selected" onchange="toggleRecipients()">
|
||||
发送给指定用户
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="recipients-group" style="display: none;">
|
||||
<label>收件人(多个邮箱用逗号分隔)</label>
|
||||
<input type="text" name="recipients" placeholder="user1@test.com, user2@test.com">
|
||||
<small>请输入邮箱地址,多个邮箱用逗号分隔</small>
|
||||
<div class="user-list">
|
||||
<strong>可用用户列表:</strong>
|
||||
<?php foreach ($allUsers as $user): ?>
|
||||
<?php if ($user['is_active'] && $user['username'] !== $_SESSION['username']): ?>
|
||||
<div class="user-list-item"><?php echo htmlspecialchars($user['username']); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>邮件主题 *</label>
|
||||
<input type="text" name="subject" required placeholder="请输入邮件主题" value="<?php echo htmlspecialchars($_POST['subject'] ?? ''); ?>">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>邮件内容 *</label>
|
||||
<textarea name="body" required placeholder="请输入邮件内容"><?php echo htmlspecialchars($_POST['body'] ?? ''); ?></textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" name="send_broadcast" class="btn btn-primary">发送群发邮件</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleRecipients() {
|
||||
const broadcastType = document.querySelector('input[name="broadcast_type"]:checked').value;
|
||||
const recipientsGroup = document.getElementById('recipients-group');
|
||||
if (broadcastType === 'selected') {
|
||||
recipientsGroup.style.display = 'block';
|
||||
} else {
|
||||
recipientsGroup.style.display = 'none';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -0,0 +1,243 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
require_once __DIR__ . '/../src/storage/Database.php';
|
||||
require_once __DIR__ . '/../src/storage/FilterRepository.php';
|
||||
require_once __DIR__ . '/../src/utils/Validator.php';
|
||||
require_once __DIR__ . '/../src/utils/Security.php';
|
||||
|
||||
session_start();
|
||||
|
||||
// 身份验证
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$filterRepo = new FilterRepository();
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
// 处理创建过滤规则
|
||||
if (isset($_POST['create_filter'])) {
|
||||
$ruleType = $_POST['rule_type'] ?? '';
|
||||
$ruleValue = trim($_POST['rule_value'] ?? '');
|
||||
$action = $_POST['action'] ?? 'block';
|
||||
$description = trim($_POST['description'] ?? '');
|
||||
|
||||
if (empty($ruleValue)) {
|
||||
$error = "规则值不能为空";
|
||||
} else {
|
||||
if ($ruleType === 'email') {
|
||||
if (!Validator::validateEmail($ruleValue)) {
|
||||
$error = "邮箱格式无效";
|
||||
}
|
||||
} elseif ($ruleType === 'ip') {
|
||||
if (!Validator::validateIP($ruleValue)) {
|
||||
$error = "IP地址格式无效";
|
||||
}
|
||||
} else {
|
||||
$error = "规则类型无效";
|
||||
}
|
||||
|
||||
if (empty($error)) {
|
||||
try {
|
||||
if ($filterRepo->create($ruleType, $ruleValue, $action, $description)) {
|
||||
$message = "过滤规则创建成功";
|
||||
} else {
|
||||
$error = "创建失败,可能已存在相同规则";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$error = "创建失败: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理删除规则
|
||||
if (isset($_GET['delete'])) {
|
||||
$id = (int)$_GET['delete'];
|
||||
if ($filterRepo->delete($id)) {
|
||||
$message = "规则删除成功";
|
||||
} else {
|
||||
$error = "删除失败";
|
||||
}
|
||||
}
|
||||
|
||||
// 处理切换规则状态
|
||||
if (isset($_GET['toggle'])) {
|
||||
$id = (int)$_GET['toggle'];
|
||||
$rule = $filterRepo->getAll();
|
||||
$currentRule = null;
|
||||
foreach ($rule as $r) {
|
||||
if ($r['id'] == $id) {
|
||||
$currentRule = $r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($currentRule) {
|
||||
$newStatus = !$currentRule['is_active'];
|
||||
if ($filterRepo->updateStatus($id, $newStatus)) {
|
||||
$message = "规则状态已更新";
|
||||
} else {
|
||||
$error = "更新失败";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有规则
|
||||
$rules = $filterRepo->getAll();
|
||||
?>
|
||||
<!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; }
|
||||
.form-group { margin-bottom: 15px; }
|
||||
.form-group label { display: block; margin-bottom: 5px; font-weight: 500; }
|
||||
.form-group input, .form-group select, .form-group textarea { width: 100%; max-width: 500px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
|
||||
.form-inline { display: flex; gap: 10px; align-items: flex-end; }
|
||||
.form-inline .form-group { flex: 1; margin-bottom: 0; }
|
||||
.btn { padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; text-decoration: none; display: inline-block; }
|
||||
.btn-primary { background: #007bff; color: white; }
|
||||
.btn-danger { background: #dc3545; color: white; }
|
||||
.btn-success { background: #28a745; color: white; }
|
||||
.btn-warning { background: #ffc107; color: #000; }
|
||||
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
||||
th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
|
||||
th { background: #f8f9fa; }
|
||||
.badge { padding: 4px 8px; border-radius: 3px; font-size: 12px; font-weight: 500; }
|
||||
.badge-email { background: #17a2b8; color: white; }
|
||||
.badge-ip { background: #6c757d; color: white; }
|
||||
.badge-block { background: #dc3545; color: white; }
|
||||
.badge-allow { background: #28a745; color: white; }
|
||||
.badge-active { background: #28a745; color: white; }
|
||||
.badge-inactive { background: #6c757d; color: white; }
|
||||
</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>
|
||||
<?php if ($_SESSION['is_admin'] ?? false): ?>
|
||||
<a href="users.php">用户管理</a>
|
||||
<?php endif; ?>
|
||||
<a href="emails.php">邮件管理</a>
|
||||
<a href="filters.php">过滤规则</a>
|
||||
<a href="logs.php">系统日志</a>
|
||||
<?php if ($_SESSION['is_admin'] ?? false): ?>
|
||||
<a href="settings.php">系统设置</a>
|
||||
<?php endif; ?>
|
||||
</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; ?>
|
||||
|
||||
<!-- 创建过滤规则 -->
|
||||
<h3>创建过滤规则</h3>
|
||||
<form method="POST" class="form-inline">
|
||||
<div class="form-group">
|
||||
<label>规则类型</label>
|
||||
<select name="rule_type" required>
|
||||
<option value="email">邮箱过滤</option>
|
||||
<option value="ip">IP地址过滤</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>规则值</label>
|
||||
<input type="text" name="rule_value" placeholder="邮箱或IP地址" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>动作</label>
|
||||
<select name="action" required>
|
||||
<option value="block">阻止</option>
|
||||
<option value="allow">允许</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>描述</label>
|
||||
<input type="text" name="description" placeholder="规则描述(可选)">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" name="create_filter" class="btn btn-primary">创建规则</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 规则列表 -->
|
||||
<h3>过滤规则列表 (<?php echo count($rules); ?>)</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>类型</th>
|
||||
<th>规则值</th>
|
||||
<th>动作</th>
|
||||
<th>描述</th>
|
||||
<th>状态</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($rules)): ?>
|
||||
<tr>
|
||||
<td colspan="8" style="text-align: center; padding: 40px;">暂无过滤规则</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($rules as $rule): ?>
|
||||
<tr>
|
||||
<td><?php echo $rule['id']; ?></td>
|
||||
<td>
|
||||
<span class="badge badge-<?php echo $rule['rule_type']; ?>">
|
||||
<?php echo $rule['rule_type'] === 'email' ? '邮箱' : 'IP'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($rule['rule_value']); ?></td>
|
||||
<td>
|
||||
<span class="badge badge-<?php echo $rule['action']; ?>">
|
||||
<?php echo $rule['action'] === 'block' ? '阻止' : '允许'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($rule['description'] ?? '-'); ?></td>
|
||||
<td>
|
||||
<span class="badge badge-<?php echo $rule['is_active'] ? 'active' : 'inactive'; ?>">
|
||||
<?php echo $rule['is_active'] ? '激活' : '禁用'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo $rule['created_at']; ?></td>
|
||||
<td>
|
||||
<a href="?toggle=<?php echo $rule['id']; ?>" class="btn btn-warning">
|
||||
<?php echo $rule['is_active'] ? '禁用' : '启用'; ?>
|
||||
</a>
|
||||
<a href="?delete=<?php echo $rule['id']; ?>" class="btn btn-danger" onclick="return confirm('确定要删除此规则吗?');">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../storage/Database.php';
|
||||
require_once __DIR__ . '/../storage/UserRepository.php';
|
||||
require_once __DIR__ . '/../storage/EmailRepository.php';
|
||||
|
||||
/**
|
||||
* 群发邮件服务
|
||||
*/
|
||||
class BroadcastService {
|
||||
private $db;
|
||||
private $userRepo;
|
||||
private $emailRepo;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance();
|
||||
$this->userRepo = new UserRepository();
|
||||
$this->emailRepo = new EmailRepository();
|
||||
}
|
||||
|
||||
/**
|
||||
* 群发邮件给所有用户
|
||||
* @param string $senderEmail 发件人邮箱
|
||||
* @param string $subject 主题
|
||||
* @param string $body 内容
|
||||
* @return array ['success' => int, 'failed' => int, 'errors' => array]
|
||||
*/
|
||||
public function broadcastToAll($senderEmail, $subject, $body) {
|
||||
$users = $this->userRepo->getAll();
|
||||
$sender = $this->userRepo->findByUsername($senderEmail);
|
||||
|
||||
if (!$sender) {
|
||||
return ['success' => 0, 'failed' => 0, 'errors' => ['发件人不存在']];
|
||||
}
|
||||
|
||||
$success = 0;
|
||||
$failed = 0;
|
||||
$errors = [];
|
||||
|
||||
foreach ($users as $user) {
|
||||
// 跳过发件人自己
|
||||
if ($user['username'] === $senderEmail) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 跳过禁用的用户
|
||||
if (!$user['is_active']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->sendEmail($sender['id'], $user['id'], $subject, $body);
|
||||
$success++;
|
||||
} catch (Exception $e) {
|
||||
$failed++;
|
||||
$errors[] = "发送给 {$user['username']} 失败: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => $success,
|
||||
'failed' => $failed,
|
||||
'errors' => $errors
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 群发邮件给指定用户列表
|
||||
* @param string $senderEmail 发件人邮箱
|
||||
* @param array $recipientEmails 收件人邮箱列表
|
||||
* @param string $subject 主题
|
||||
* @param string $body 内容
|
||||
* @return array ['success' => int, 'failed' => int, 'errors' => array]
|
||||
*/
|
||||
public function broadcastToUsers($senderEmail, $recipientEmails, $subject, $body) {
|
||||
$sender = $this->userRepo->findByUsername($senderEmail);
|
||||
|
||||
if (!$sender) {
|
||||
return ['success' => 0, 'failed' => 0, 'errors' => ['发件人不存在']];
|
||||
}
|
||||
|
||||
$success = 0;
|
||||
$failed = 0;
|
||||
$errors = [];
|
||||
|
||||
foreach ($recipientEmails as $email) {
|
||||
$recipient = $this->userRepo->findByUsername(trim($email));
|
||||
|
||||
if (!$recipient) {
|
||||
$failed++;
|
||||
$errors[] = "用户 {$email} 不存在";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$recipient['is_active']) {
|
||||
$failed++;
|
||||
$errors[] = "用户 {$email} 已被禁用";
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->sendEmail($sender['id'], $recipient['id'], $subject, $body);
|
||||
$success++;
|
||||
} catch (Exception $e) {
|
||||
$failed++;
|
||||
$errors[] = "发送给 {$email} 失败: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => $success,
|
||||
'failed' => $failed,
|
||||
'errors' => $errors
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
* @param int $senderId 发件人ID
|
||||
* @param int $recipientId 收件人ID
|
||||
* @param string $subject 主题
|
||||
* @param string $body 内容
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
private function sendEmail($senderId, $recipientId, $subject, $body) {
|
||||
$sender = $this->userRepo->findById($senderId);
|
||||
$recipient = $this->userRepo->findById($recipientId);
|
||||
|
||||
if (!$sender || !$recipient) {
|
||||
throw new Exception("发件人或收件人不存在");
|
||||
}
|
||||
|
||||
$sizeBytes = strlen($subject) + strlen($body);
|
||||
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO emails (sender_id, recipient_id, sender, recipient, subject, body, size_bytes, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, NOW())
|
||||
");
|
||||
|
||||
return $stmt->execute([
|
||||
$senderId,
|
||||
$recipientId,
|
||||
$sender['username'],
|
||||
$recipient['username'],
|
||||
$subject,
|
||||
$body,
|
||||
$sizeBytes
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/Database.php';
|
||||
|
||||
/**
|
||||
* 过滤规则数据访问层
|
||||
*/
|
||||
class FilterRepository {
|
||||
private $db;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建过滤规则
|
||||
* @param string $type 规则类型 ('email' 或 'ip')
|
||||
* @param string $value 规则值
|
||||
* @param string $action 动作 ('block' 或 'allow')
|
||||
* @param string $description 描述
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public function create($type, $value, $action = 'block', $description = '') {
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO filter_rules (rule_type, rule_value, action, description, is_active)
|
||||
VALUES (?, ?, ?, ?, 1)
|
||||
");
|
||||
return $stmt->execute([$type, $value, $action, $description]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有过滤规则
|
||||
* @return array 规则列表
|
||||
*/
|
||||
public function getAll() {
|
||||
$stmt = $this->db->query("
|
||||
SELECT * FROM filter_rules
|
||||
ORDER BY rule_type, created_at DESC
|
||||
");
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取激活的过滤规则
|
||||
* @return array 规则列表
|
||||
*/
|
||||
public function getActive() {
|
||||
$stmt = $this->db->query("
|
||||
SELECT * FROM filter_rules
|
||||
WHERE is_active = 1
|
||||
ORDER BY rule_type, created_at DESC
|
||||
");
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查邮箱是否被过滤
|
||||
* @param string $email 邮箱地址
|
||||
* @return bool 是否被阻止
|
||||
*/
|
||||
public function isEmailBlocked($email) {
|
||||
$stmt = $this->db->prepare("
|
||||
SELECT action FROM filter_rules
|
||||
WHERE rule_type = 'email'
|
||||
AND is_active = 1
|
||||
AND (rule_value = ? OR rule_value LIKE ?)
|
||||
ORDER BY action DESC
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([$email, $email]);
|
||||
$result = $stmt->fetch();
|
||||
return $result && $result['action'] === 'block';
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查IP是否被过滤
|
||||
* @param string $ip IP地址
|
||||
* @return bool 是否被阻止
|
||||
*/
|
||||
public function isIPBlocked($ip) {
|
||||
$stmt = $this->db->prepare("
|
||||
SELECT action FROM filter_rules
|
||||
WHERE rule_type = 'ip'
|
||||
AND is_active = 1
|
||||
AND rule_value = ?
|
||||
ORDER BY action DESC
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([$ip]);
|
||||
$result = $stmt->fetch();
|
||||
return $result && $result['action'] === 'block';
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除规则
|
||||
* @param int $id 规则ID
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public function delete($id) {
|
||||
$stmt = $this->db->prepare("DELETE FROM filter_rules WHERE id = ?");
|
||||
return $stmt->execute([$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新规则状态
|
||||
* @param int $id 规则ID
|
||||
* @param bool $isActive 是否激活
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public function updateStatus($id, $isActive) {
|
||||
$stmt = $this->db->prepare("UPDATE filter_rules SET is_active = ? WHERE id = ?");
|
||||
return $stmt->execute([$isActive ? 1 : 0, $id]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/Database.php';
|
||||
|
||||
/**
|
||||
* 邮箱管理数据访问层
|
||||
*
|
||||
* @package storage
|
||||
*/
|
||||
class MailboxRepository {
|
||||
private $db;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户邮箱大小限制
|
||||
* @param int $userId 用户ID
|
||||
* @return int 大小限制(字节)
|
||||
*/
|
||||
public function getSizeLimit($userId) {
|
||||
$stmt = $this->db->prepare("
|
||||
SELECT size_limit_bytes FROM user_mailbox_limits WHERE user_id = ?
|
||||
");
|
||||
$stmt->execute([$userId]);
|
||||
$result = $stmt->fetch();
|
||||
|
||||
if ($result) {
|
||||
return (int)$result['size_limit_bytes'];
|
||||
}
|
||||
|
||||
// 返回默认值
|
||||
return 104857600; // 100MB
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户邮箱大小限制
|
||||
* @param int $userId 用户ID
|
||||
* @param int $sizeBytes 大小限制(字节)
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public function setSizeLimit($userId, $sizeBytes) {
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO user_mailbox_limits (user_id, size_limit_bytes)
|
||||
VALUES (?, ?)
|
||||
ON DUPLICATE KEY UPDATE size_limit_bytes = VALUES(size_limit_bytes)
|
||||
");
|
||||
return $stmt->execute([$userId, $sizeBytes]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户当前邮箱使用大小
|
||||
* @param int $userId 用户ID
|
||||
* @return int 已使用大小(字节)
|
||||
*/
|
||||
public function getUsedSize($userId) {
|
||||
$stmt = $this->db->prepare("
|
||||
SELECT COALESCE(SUM(size_bytes), 0) as total_size
|
||||
FROM emails
|
||||
WHERE recipient_id = ? AND is_deleted = 0
|
||||
");
|
||||
$stmt->execute([$userId]);
|
||||
$result = $stmt->fetch();
|
||||
return (int)($result['total_size'] ?? 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户邮箱使用情况
|
||||
* @param int $userId 用户ID
|
||||
* @return array ['limit' => int, 'used' => int, 'percentage' => float]
|
||||
*/
|
||||
public function getUsage($userId) {
|
||||
$limit = $this->getSizeLimit($userId);
|
||||
$used = $this->getUsedSize($userId);
|
||||
$percentage = $limit > 0 ? ($used / $limit) * 100 : 0;
|
||||
|
||||
return [
|
||||
'limit' => $limit,
|
||||
'used' => $used,
|
||||
'percentage' => round($percentage, 2)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/Database.php';
|
||||
|
||||
/**
|
||||
* 服务状态数据访问层
|
||||
*/
|
||||
class ServiceRepository {
|
||||
private $db;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务状态
|
||||
* @param string $serviceName 服务名称 ('smtp' 或 'pop3')
|
||||
* @return array|null 服务状态或null
|
||||
*/
|
||||
public function getStatus($serviceName) {
|
||||
$stmt = $this->db->prepare("SELECT * FROM service_status WHERE service_name = ?");
|
||||
$stmt->execute([$serviceName]);
|
||||
return $stmt->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新服务状态
|
||||
* @param string $serviceName 服务名称
|
||||
* @param bool $isRunning 是否运行
|
||||
* @param int|null $pid 进程ID
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public function updateStatus($serviceName, $isRunning, $pid = null) {
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO service_status (service_name, is_running, pid, last_started_at, last_stopped_at)
|
||||
VALUES (?, ?, ?, NOW(), NULL)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
is_running = VALUES(is_running),
|
||||
pid = VALUES(pid),
|
||||
last_started_at = IF(VALUES(is_running) = 1, NOW(), last_started_at),
|
||||
last_stopped_at = IF(VALUES(is_running) = 0, NOW(), last_stopped_at)
|
||||
");
|
||||
return $stmt->execute([$serviceName, $isRunning ? 1 : 0, $pid]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有服务状态
|
||||
* @return array 服务状态列表
|
||||
*/
|
||||
public function getAllStatus() {
|
||||
$stmt = $this->db->query("SELECT * FROM service_status ORDER BY service_name");
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查服务是否运行
|
||||
* @param string $serviceName 服务名称
|
||||
* @return bool 是否运行
|
||||
*/
|
||||
public function isRunning($serviceName) {
|
||||
$status = $this->getStatus($serviceName);
|
||||
if (!$status) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查进程是否真的在运行
|
||||
if ($status['pid'] && $status['is_running']) {
|
||||
// 检查进程是否存在
|
||||
$result = shell_exec("ps -p {$status['pid']} -o pid= 2>/dev/null");
|
||||
if (empty(trim($result))) {
|
||||
// 进程不存在,更新状态
|
||||
$this->updateStatus($serviceName, false, null);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return (bool)$status['is_running'];
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/Database.php';
|
||||
|
||||
/**
|
||||
* 系统设置数据访问层
|
||||
*/
|
||||
class SystemSettingsRepository {
|
||||
private $db;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设置值
|
||||
* @param string $key 设置键
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed 设置值
|
||||
*/
|
||||
public function get($key, $default = null) {
|
||||
$stmt = $this->db->prepare("SELECT setting_value FROM system_settings WHERE setting_key = ?");
|
||||
$stmt->execute([$key]);
|
||||
$result = $stmt->fetch();
|
||||
return $result ? $result['setting_value'] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置值
|
||||
* @param string $key 设置键
|
||||
* @param mixed $value 设置值
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public function set($key, $value) {
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO system_settings (setting_key, setting_value)
|
||||
VALUES (?, ?)
|
||||
ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)
|
||||
");
|
||||
return $stmt->execute([$key, $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有设置
|
||||
* @return array 所有设置
|
||||
*/
|
||||
public function getAll() {
|
||||
$stmt = $this->db->query("SELECT setting_key, setting_value FROM system_settings");
|
||||
$results = $stmt->fetchAll();
|
||||
$settings = [];
|
||||
foreach ($results as $row) {
|
||||
$settings[$row['setting_key']] = $row['setting_value'];
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in new issue